From 13517e723af13cabdadcba4cc0172923b91dd20b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> 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 8b4e9ad4b4..ec7e2577cd 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 d38dfaeb2e..1ed3779367 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 <marc@zpages.de> 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 87d8267532..b390169c6b 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 <rickywd@gmail.com> 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 0b398a046c..89cff3fa13 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<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& 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<MWWorld::Ptr> 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<MWWorld::Ptr>::const_iterator it = allies1.begin(); it != allies1.end(); ++it) @@ -328,10 +329,10 @@ namespace MWMechanics aggressive = true; } - std::set<MWWorld::Ptr> playerFollowersAndEscorters; - getActorsSidingWith(MWMechanics::getPlayer(), playerFollowersAndEscorters); + std::set<MWWorld::Ptr> 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<MWWorld::Ptr> allies2; - getActorsSidingWith(actor2, allies2); + + getActorsSidingWith(actor2, allies2, cachedAllies); + // Check that an ally of actor2 is also in combat with actor1 for (std::set<MWWorld::Ptr>::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<const MWWorld::Ptr, const std::set<MWWorld::Ptr> > 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<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies) { + std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor); + + // If we have already found actor's allies, use the cache + std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >::const_iterator search = cachedAllies.find(actor); + if (search != cachedAllies.end()) + out = search->second; + else + { + for (std::list<MWWorld::Ptr>::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<MWWorld::Ptr>::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<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list<int> list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 20aef4c17c..362c2f126d 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<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& 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<MWWorld::Ptr>& out); /// Recursive version of getActorsSidingWith void getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& 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<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor); From 56dfa615e1e11539842350e4794f4247f7308135 Mon Sep 17 00:00:00 2001 From: Allofich <rickywd@gmail.com> 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 89cff3fa13..80564de9fe 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<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies) { - std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor); - // If we have already found actor's allies, use the cache std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >::const_iterator search = cachedAllies.find(actor); if (search != cachedAllies.end()) - out = search->second; + out.insert(search->second.begin(), search->second.end()); else { + std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor); for (std::list<MWWorld::Ptr>::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 <miroslavr256@gmail.com> 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 df3f30bea5..d251e824cc 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<ESM::ENAMstruct>::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 <hasufell@posteo.de> 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 ef35b31ef6..010917572a 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -4,6 +4,7 @@ #include <osg/TriangleFunctor> #include <osg/Transform> #include <osg/Drawable> +#include <osg/Version> #include <BulletCollision/CollisionShapes/btTriangleMesh.h> @@ -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 <scrawl@baseoftrash.de> 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 | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 234a17cc37..9979bd5d66 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(); - - 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)) + if (xAxis != 0 || yAxis != 0) { - mPlayer->yaw(rot[2]); - mPlayer->pitch(rot[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); + + // 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 <scrawl@baseoftrash.de> 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 a22075abdf..7fbf2965a2 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 <psi29a@gmail.com> 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 ec7e2577cd..7a2ac34c35 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 6ee8d69879..72c2aaa12d 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 273b2f7d5e..b18b40c502 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 f51cda9098..3781733cb8 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 b58bf2b374..0000000000 --- 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 b648bc49ce..0000000000 --- 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 38ca0c31c6..0000000000 --- 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 54d00ccc01..0000000000 --- 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 5367995de8..0000000000 --- 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 8fd7ffc1e1..0000000000 --- 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 3365d25825..0000000000 --- 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 1f3522f2ca..0000000000 --- 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 0e37268320..0000000000 --- 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 b24d8dfdbe..0000000000 --- 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 3427b712af..0000000000 --- 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 6eebab4d99..0000000000 --- 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 d284f65864..0000000000 --- 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 8db8f40e25..0000000000 --- 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 d4fcb0e6bd..0000000000 --- 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 2618c6ff00..0000000000 --- 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 21026b3e24..0000000000 --- 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 <andrei.kortunov@yandex.ru> 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 7fde66ebe5..a6ae5ca65f 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 <miroslavr256@gmail.com> 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 d4cbf25fed..f0a3d2e381 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<osg::Group> 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<ActorAnimation*>(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<ActorAnimation*>(anim.get())); } void Objects::insertNPC(const MWWorld::Ptr &ptr) @@ -102,10 +103,11 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) osg::ref_ptr<NpcAnimation> anim (new NpcAnimation(ptr, osg::ref_ptr<osg::Group>(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 8da01cc4bb..c831652395 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 <andrei.kortunov@yandex.ru> 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 1aa311fd2b..89b94ce12a 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 3e61b74635..1bfeff074b 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<ESM::ENAMstruct>::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<ESM::GameSetting>().find("fCombatDistance")->getFloat(); - static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().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<MWMechanics::ActiveSpells::ActiveEffect>::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<ESM::MagicEffect>().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) + float suggestCombatRange(int rangeTypes) { - if (item.getTypeName() != typeid(ESM::Potion).name()) - return 0.f; + static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat(); + static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->getFloat(); - const ESM::Potion* potion = item.get<ESM::Potion>()->mBase; - return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); - } + // This distance is a possible distance of melee attack + static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); - 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<ESM::Weapon>()->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) + if (rangeTypes & RangeTypes::Touch) { - // 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; + return fCombatDistance; } - 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<ESM::Enchantment>().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<ESM::NPC>()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().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<ESM::Enchantment>().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<ESM::NPC>()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().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<float>& 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<sizeof(armorSlots)/sizeof(int); ++i) - { - MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]); - - if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor)) - { - enemyHasArmor = true; - break; - } - } - - if (!enemyHasArmor) - return 0.f; - - break; - } - - case ESM::MagicEffect::DisintegrateWeapon: - { - 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); - MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - // Ignore enemy without weapons - if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon)) - return 0.f; - - break; - } - - case ESM::MagicEffect::DamageAttribute: - case ESM::MagicEffect::DrainAttribute: - if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0) - return 0.f; - { - if (effect.mAttribute >= 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<ESM::MagicEffect>().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<ESM::ENAMstruct>::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<ESM::Spell>().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<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); - - static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); - static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); - - float mult = fAIMagicSpellMult; - - for (std::vector<ESM::ENAMstruct>::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<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); - - 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<ESM::Weapon>()->mBase; - - if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) - { - if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) - { - bonusDamage = ammo.get<ESM::Weapon>()->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 393bd9f5dc..dc6f359d63 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<Action> 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 0000000000..a73e4fd89f --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -0,0 +1,545 @@ +#include "spellpriority.hpp" + +#include <components/esm/loadench.hpp> +#include <components/esm/loadmgef.hpp> + +#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<MWMechanics::ActiveSpells::ActiveEffect>::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<ESM::MagicEffect>().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<ESM::ENAMstruct>::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<ESM::Potion>()->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<ESM::NPC>()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().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<ESM::Enchantment>().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<ESM::NPC>()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().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<float>& 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<sizeof(armorSlots)/sizeof(int); ++i) + { + MWWorld::ContainerStoreIterator item = inv.getSlot(armorSlots[i]); + + if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor)) + { + enemyHasArmor = true; + break; + } + } + + if (!enemyHasArmor) + return 0.f; + + break; + } + + case ESM::MagicEffect::DisintegrateWeapon: + { + 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); + MWWorld::ContainerStoreIterator item = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + // Ignore enemy without weapons + if (item == inv.end() || (item.getType() != MWWorld::ContainerStore::Type_Weapon)) + return 0.f; + + break; + } + + case ESM::MagicEffect::DamageAttribute: + case ESM::MagicEffect::DrainAttribute: + if (!enemy.isEmpty() && enemy.getClass().getCreatureStats(enemy).getAttribute(effect.mAttribute).getModified() <= 0) + return 0.f; + { + if (effect.mAttribute >= 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<ESM::MagicEffect>().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<ESM::ENAMstruct>::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<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); + + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); + + float mult = fAIMagicSpellMult; + + for (std::vector<ESM::ENAMstruct>::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 0000000000..4e5ff5c713 --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_SPELL_PRIORITY_H +#define OPENMW_SPELL_PRIORITY_H + +#include <components/esm/loadspel.hpp> + +#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 0000000000..07cf6ff5ff --- /dev/null +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -0,0 +1,146 @@ +#include "weaponpriority.hpp" + +#include <components/esm/loadench.hpp> +#include <components/esm/loadmgef.hpp> + +#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<ESM::Weapon>()->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<ESM::Enchantment>().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<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); + + 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<ESM::Weapon>()->mBase; + + if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) + { + if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) + { + bonusDamage = ammo.get<ESM::Weapon>()->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 0000000000..90a767c4ac --- /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 <corrmage@gmail.com> 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 1ff6f89c3b..53bfa18b5f 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 <elsid.mail@gmail.com> 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 baf4efc03c..b44b187adf 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 6125ed36d0..8aaa6cf738 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 <vertex.five@gmail.com> 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 ac172b84bf..56411ca884 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,17 +49,42 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> 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<SDL_Event> 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 <wjherrmann@gmail.com> 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 8aaa6cf738..95c741eab1 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 <andrei.kortunov@yandex.ru> 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 c6b8a4bd7c..8b0f895d1f 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 5f4433a476..e05848ef8b 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 <andrei.kortunov@yandex.ru> 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 e05848ef8b..f82d2f68db 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<MWWorld::Ptr> 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 <andrei.kortunov@yandex.ru> 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 62ac9bd408..751f8d1645 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<int>(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast<float>(disposition)))); From 56a30d7aeccefe15a6172089d47f648bc75995bb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 5634eb0806..a1d74fab64 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 105f95085b..e96cc8b706 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -187,12 +187,12 @@ namespace } adjustButton(TopicsBTN); - int width = getWidget<MyGUI::Widget>(TopicsBTN)->getSize().width + getWidget<MyGUI::Widget>(QuestsBTN)->getSize().width; int topicsWidth = getWidget<MyGUI::Widget>(TopicsBTN)->getSize().width; - int pageWidth = getWidget<MyGUI::Widget>(RightBookPage)->getSize().width; + int cancelLeft = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left; + int cancelRight = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left + getWidget<MyGUI::Widget>(CancelBTN)->getSize().width; - getWidget<MyGUI::Widget>(TopicsBTN)->setPosition((pageWidth - width)/2, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); - getWidget<MyGUI::Widget>(QuestsBTN)->setPosition((pageWidth - width)/2 + topicsWidth, getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().top); + getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); + getWidget<MyGUI::Widget>(QuestsBTN)->setPosition(cancelRight, getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().top); mQuestMode = false; mAllQuests = false; diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index c53f395789..1131b1bbcd 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -49,33 +49,33 @@ <!-- text pages --> - <Widget type="BookPage" skin="MW_BookPage" position="30 22 240 300" name="LeftBookPage"/> - <Widget type="BookPage" skin="MW_BookPage" position="300 22 240 300" name="RightBookPage"/> + <Widget type="BookPage" skin="MW_BookPage" position="30 22 240 320" name="LeftBookPage"/> + <Widget type="BookPage" skin="MW_BookPage" position="295 22 240 320" name="RightBookPage"/> <!-- options overlay --> </Widget> </Widget> <!-- "options" --> - <Widget type="ImageBox" skin="ImageBox" position="300 0 224 350" name="OptionsOverlay"> + <Widget type="ImageBox" skin="ImageBox" position="293 0 242 350" name="OptionsOverlay"> <Property key="ImageTexture" value="textures\tx_menubook_bookmark.dds"/> <Property key="ImageCoord" value="0 0 164 256"/> <Widget type="BookPage" skin="MW_BookPage" position="20 15 92 250" name="LeftTopicIndex"/> <Widget type="BookPage" skin="MW_BookPage" position="112 15 92 250" name="RightTopicIndex"/> - <Widget type="ImageButton" skin="ImageBox" position="62 15 100 20" Align="Top|Left" name="ShowActiveBTN"> + <Widget type="ImageButton" skin="ImageBox" position="71 15 100 20" Align="Top|Left" name="ShowActiveBTN"> <!-- Image set at runtime since it may not be available in all versions of the game --> </Widget> - <Widget type="ImageButton" skin="ImageBox" position="76 15 72 20" Align="Top|Left" name="ShowAllBTN"> + <Widget type="ImageButton" skin="ImageBox" position="85 15 72 20" Align="Top|Left" name="ShowAllBTN"> <!-- Image set at runtime since it may not be available in all versions of the game --> </Widget> - <Widget type="MWList" skin="MW_QuestList" position="8 35 208 225" name="TopicsList" align="Right VStretch"> + <Widget type="MWList" skin="MW_QuestList" position="8 40 226 212" name="TopicsList" align="Right VStretch"> </Widget> - <Widget type="MWList" skin="MW_QuestList" position="8 35 208 225" name="QuestsList" align="Right VStretch"> + <Widget type="MWList" skin="MW_QuestList" position="8 40 226 212" name="QuestsList" align="Right VStretch"> </Widget> <Widget type="ImageButton" skin="ImageBox" position="20 265 56 32" Align="Top|Left" name="TopicsBTN"> @@ -88,7 +88,7 @@ <!-- Image set at runtime since it may not be available in all versions of the game --> </Widget> - <Widget type="ImageButton" skin="ImageBox" position="85 290 56 32" Align="Top|Left" name="CancelBTN"> + <Widget type="ImageButton" skin="ImageBox" position="92 290 56 32" Align="Top|Left" name="CancelBTN"> <Property key="ImageHighlighted" value="textures\tx_menubook_cancel_over.dds"/> <Property key="ImageNormal" value="textures\tx_menubook_cancel_idle.dds"/> <Property key="ImagePushed" value="textures\tx_menubook_cancel_pressed.dds"/> From c920d083e421f947a33c04203dbb49556ef88aaf Mon Sep 17 00:00:00 2001 From: Siimacore <antoine.queiros@gmail.com> 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 94e186db80..31da90d2f7 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 96b5c0b979..8d0d61b8f7 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 <andrei.kortunov@yandex.ru> 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 7b2a1560d3..a823ae0fd6 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 <jakewestrip@live.com> 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 211e0c5f91..8ac133d76a 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<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); 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 95c741eab1..2a10cbc2ba 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 <andrei.kortunov@yandex.ru> 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 1bfeff074b..d444989668 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<ESM::Enchantment>().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 dc6f359d63..466ae2dc43 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 a73e4fd89f..a56f430c64 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<MWMechanics::ActiveSpells::ActiveEffect>::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<ESM::Enchantment>().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<float>(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 <andrei.kortunov@yandex.ru> 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 62ac9bd408..2f217ab12f 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<MWWorld::Ptr> 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 <miroslavr256@gmail.com> 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 a7e522acdc..9e44f237e0 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -20,6 +20,9 @@ #include <cstdlib> #endif +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#include <unistd.h> +#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 <me@lenny.ninja> 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 53c0643f68..97030643f1 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<std::string,std::string>& fallbackMap, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map<std::string, std::string>& 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 bf628b1025..1c5348e656 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 <spycrab@users.noreply.github.com> 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 4263001492..c921e17d07 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 29419a4c29..bf144bfedd 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 f8d44292ed..a9506385d4 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 56411ca884..ac172b84bf 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,42 +49,17 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> 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<SDL_Event> 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 2a10cbc2ba..c48647f4e4 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 <andrei.kortunov@yandex.ru> 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 ce03af7a1e..65f8c80d8e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -4,6 +4,7 @@ #include <components/esm/loadcrea.hpp> #include <components/esm/creaturestate.hpp> +#include <components/settings/settings.hpp> #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" @@ -448,10 +449,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr<MWWorld::Action>(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<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing + return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("")); + return std::shared_ptr<MWWorld::Action>(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 f8ff3da19a..ed1f12b31c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include <components/esm/loadmgef.hpp> #include <components/esm/loadnpc.hpp> #include <components/esm/npcstate.hpp> +#include <components/settings/settings.hpp> #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -863,16 +864,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); - if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) - return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}")); - if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) - || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) - return std::shared_ptr<MWWorld::Action>(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<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) + return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("")); + return std::shared_ptr<MWWorld::Action>(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 62fe5a70e5..e1d5d75f6e 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 40c1ed0990..a0460326b8 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 <andrei.kortunov@yandex.ru> 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 a6ae5ca65f..ecd4ba48a2 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 <me@lenny.ninja> 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 97030643f1..88ee42b01c 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 1c5348e656..5d911d4bec 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 <me@lenny.ninja> 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 88ee42b01c..c6f663059d 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 <andrei.kortunov@yandex.ru> 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 f8ddeba3ee..ab43df0f18 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<std::string>& 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 6592de56e3..ed673c5d6a 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 0000000000..6b79b94178 --- /dev/null +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<MyGUI type="Layout"> + <Widget type="Window" skin="MW_DialogNoTransp" layer="MessageBox" position="0 0 500 400" align="Center" name="_Main"> + <Widget type="EditBox" skin="MW_TextEditClient" position="10 10 490 20" align="Left Top Stretch" name="message"> + <Property key="FontName" value="Default"/> + <Property key="TextAlign" value="Center"/> + <Property key="Static" value="true"/> + <Property key="WordWrap" value="true"/> + <Property key="MultiLine" value="1"/> + <Property key="VisibleVScroll" value="1"/> + </Widget> + <Widget type="Widget" skin="" position="0 0 500 400" align="Stretch" name="buttons"> + </Widget> + </Widget> +</MyGUI> From 4cc8afd25da2aca12995c4801a3d034381903972 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 1e770a60b2..798eb1d6a9 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 <andrei.kortunov@yandex.ru> 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 d9a673ec2f..c66f9d0adc 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layout"> - <Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 220 192" align="Center" name="_Main"> + <Widget type="Window" skin="MW_DialogNoTransp" layer="Windows" position="0 0 220 192" align="Center" name="_Main"> <Widget type="TextBox" skin="NormalText" position="0 4 220 24"> <Property key="Caption" value="#{sPersuasionMenuTitle}"/> From 56f5a5dee385eb2d1c3c97439d81447ba0885a07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 798eb1d6a9..81a3d864c2 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 33199d6aeb..e53493bb1d 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -36,6 +36,18 @@ <!-- The interior of the box --> + <Child type="Widget" skin="DialogBG_NoTransp_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> + + <!-- Borders --> + + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + + </Resource> + + <Resource type="ResourceSkin" name="HUD_Box_Owned" size="40 40"> + + <!-- The interior of the box --> + <Child type="Widget" skin="DialogBG_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> <!-- Borders --> diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 00e6f91487..a272ae84a0 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -158,13 +158,20 @@ </Resource> <!-- Defines a owned background --> - <Resource type="ResourceSkin" name="DialogBG_Owned" size="8 8" texture="white"> + <Resource type="ResourceSkin" name="DialogBG_NoTransp_Owned" size="8 8" texture="white"> <Property key="Colour" value="#{setting=GUI,color background owned}"/> <BasisSkin type="MainSkin" offset="0 0 8 8"> <State name="normal" offset="0 0 8 8"/> </BasisSkin> </Resource> + <Resource type="ResourceSkin" name="DialogBG_Owned" size="8 8" texture="transparent"> + <Property key="Colour" value="#{setting=GUI,color background owned}"/> + <BasisSkin type="MainSkin" offset="0 0 8 8"> + <State name="normal" offset="0 0 8 8"/> + </BasisSkin> + </Resource> + <!-- These define the dialog borders --> <Resource type="ResourceSkin" name="DB_B" size="512 4" texture="textures\menu_thick_border_bottom.dds"> <BasisSkin type="TileRect" offset="0 0 512 4" align="Stretch"> From f41a4bb93794de0e76665486ec13a06a589785f7 Mon Sep 17 00:00:00 2001 From: Thunderforge <wjherrmann@gmail.com> 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 161e515153..d998849663 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -2,7 +2,6 @@ #include <QDebug> #include <QPushButton> -#include <QAbstractButton> #include <QMessageBox> #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 87154732ae..f6a6015b8f 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("<html><head/><body><p>The OpenMW Wizard successfully installed Morrowind on your computer.</p> \ <p>Click Finish to close the Wizard.</p></body></html>")); diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index 2f0af88c94..7a4dcbf10c 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -7,7 +7,6 @@ #include <QMessageBox> #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 0d5132f5bf..4c10bf38c6 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 7ef8761dd6..b99f151aae 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -3,7 +3,6 @@ #include <QDebug> #include <QTime> -#include <QDateTime> #include <QCloseEvent> #include <QMessageBox> #include <QTextCodec> @@ -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 5f3917bd51..e00344af93 100644 --- a/apps/wizard/methodselectionpage.cpp +++ b/apps/wizard/methodselectionpage.cpp @@ -1,5 +1,4 @@ #include "methodselectionpage.hpp" -#include <QDebug> #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 531d093afb..4d4d66badc 100644 --- a/files/ui/wizard/methodselectionpage.ui +++ b/files/ui/wizard/methodselectionpage.ui @@ -17,16 +17,16 @@ <string>Select Installation Method</string> </property> <property name="subTitle"> - <string>Select how OpenMW should get the required Morrowind installation files.</string> + <string><html><head/><body><p>Select how you would like to install <i>The Elder Scrolls III: Morrowind</i>.</p></body></html></string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QRadioButton" name="newLocationRadioButton"> + <widget class="QRadioButton" name="retailDiscRadioButton"> <property name="styleSheet"> <string notr="true">font-weight:bold;</string> </property> <property name="text"> - <string>Install Morrowind to a new location</string> + <string>Retail CD/DVD</string> </property> <property name="checked"> <bool>true</bool> @@ -34,7 +34,7 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="newLocationLayout"> + <layout class="QHBoxLayout" name="retailDiscLayout"> <item> <spacer name="horizontalSpacer"> <property name="orientation"> @@ -72,14 +72,14 @@ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> </property> <property name="buddy"> - <cstring>newLocationRadioButton</cstring> + <cstring>retailDiscRadioButton</cstring> </property> </widget> </item> <item> - <widget class="QLabel" name="newLocationLabel"> + <widget class="QLabel" name="retailDiscLabel"> <property name="text"> - <string>Install Morrowind from a retail disk to a new location for OpenMW to use.</string> + <string>Install from a retail disc to a new location.</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -94,7 +94,7 @@ <string notr="true">font-weight:bold</string> </property> <property name="text"> - <string>Select an existing Morrowind installation</string> + <string>Existing Installation</string> </property> </widget> </item> @@ -138,7 +138,7 @@ <item> <widget class="QLabel" name="existingLocationLabel"> <property name="text"> - <string>Select an existing Morrowind installation for OpenMW to use.</string> + <string>Select an existing installation.</string> </property> <property name="wordWrap"> <bool>true</bool> From 464c64a306bb79ca76fc0bdc3de0324e6982c37a Mon Sep 17 00:00:00 2001 From: Thunderforge <wjherrmann@gmail.com> 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 ac172b84bf..f622f21661 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -1,7 +1,6 @@ #include "sdlinputwrapper.hpp" #include <iostream> -#include <stdexcept> #include <osgViewer/Viewer> @@ -423,7 +422,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> 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<osgViewer::Viewer> 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 <wjherrmann@gmail.com> 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 f622f21661..a76de00d1c 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -499,7 +499,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> 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 <andrei.kortunov@yandex.ru> 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 09e5ed9c7c..bb707fa0d2 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -12,7 +12,7 @@ <!-- Avatar --> <Widget type="Widget" skin="MW_Box" position="8 38 212 185" name="Avatar" align="Left Top Stretch"> - <Widget type="ImageBox" skin="ImageBox" position="0 0 212 161" align="Stretch" name="AvatarImage"> + <Widget type="ImageBox" skin="ImageBox" position="3 3 206 158" align="Stretch" name="AvatarImage"> <UserString key="ToolTipType" value="AvatarItemSelection"/> </Widget> <Widget type="TextBox" skin="ProgressText" position="0 161 212 24" align="HStretch Bottom" name="ArmorRating"> From c542ae6875c8e913f8824cdc4fca303d0e893b45 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 8685475a4e..ba58a9c690 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 <andrei.kortunov@yandex.ru> 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 76bb4f53fa..9aaa98f19d 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 <andrei.kortunov@yandex.ru> 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 ed1f12b31c..ca6c85aba6 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<MWWorld::Action>(new MWWorld::FailedAction("")); + if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing + + // Can't talk to werewolfs + if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf()) + return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr)); } From 249c1ae95a6c70acd2f2b13af9a5bb863e6044f1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 82eebf1278..3a801ffc3a 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 <andrei.kortunov@yandex.ru> 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 bd0d2ea4ad..9cb0041071 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 f82d2f68db..ca0bb48e8f 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 8460a14739..b174e87cd6 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 ed06f58c5a..a5598252fc 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 <andrei.kortunov@yandex.ru> 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 8460a14739..e5f1d73dc2 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<MWWorld::Ptr> 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<MWWorld::Ptr> 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 <andrei.kortunov@yandex.ru> 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 643b69532b..c7d2ef7de6 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 <andrei.kortunov@yandex.ru> 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 52c05fdfac..90d29f686d 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<ESM::Spell>().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 0f1f803b73..a19c8a51dd 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 ecd4ba48a2..f7ee15bf44 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 a73e4fd89f..0b86b9494d 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<ESM::Spell>().search(it->first); + if (!spell || spell->mData.mType != ESM::Spell::ST_Spell) + continue; + } + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; for (std::vector<MWMechanics::ActiveSpells::ActiveEffect>::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt) From 67d59bead51ce4948c0e0256ee014bdab3bc8b5f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 7379f3613d..95dc8cc4dc 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 e1f5a165e7..ac61041c34 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 c7d2ef7de6..5dc1f3454f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,6 +3,7 @@ #include <iomanip> #include <MyGUI_Button.h> +#include <MyGUI_EditBox.h> #include <MyGUI_ScrollView.h> #include <components/widgets/list.hpp> @@ -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 cb7c6c0d01..6391f85971 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 84d4ca959b..4d1a490aad 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 354253fa4f..cd2d2cd1d1 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 958b52dc08..9ddfac612b 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 <andrei.kortunov@yandex.ru> 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 9cb0041071..2daaf9711c 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 00f8899de2..9a23526f7e 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 362c2f126d..cd949696b9 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 661df35b0f..25d04d1763 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 a3cdf097d0..66039bf5d7 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 f4b4cec91a..d182e40d74 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 a5598252fc..af0377a33f 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 626fafb5a4..21b3b5587e 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 <andrei.kortunov@yandex.ru> 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 | 46 +++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index fe94246c43..fd5f9c7fe0 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -22,8 +22,15 @@ struct AiFollowStorage : AiTemporaryBase { float mTimer; bool mMoving; + float mTargetAngleRadians; + bool mTurnActorToTarget; - AiFollowStorage() : mTimer(0.f), mMoving(false) {} + 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<AiFollowStorage>(); + 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 <Capostrophic@users.noreply.github.com> 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 e6e3b4c4e1..1244686413 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<ESM::GameSetting>().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 <andrei.kortunov@yandex.ru> 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 431ad09b3a..e701336fe8 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 362c2f126d..8228284a72 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 e4a825efc7..fad7bc96d9 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<CreatureStats::SummonKey, int>& creatureMap = creatureStats.getSummonedCreatureMap(); - for (std::map<CreatureStats::SummonKey, int>::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<std::pair<int, std::string> >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) { @@ -101,21 +85,18 @@ namespace MWMechanics } } + // Update summon effects for (std::map<CreatureStats::SummonKey, int>::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<int>& graveyard = creatureStats.getSummonedCreatureGraveyard(); @@ -137,6 +118,26 @@ namespace MWMechanics else ++it; } + + if (!cleanup) + return; + + for (std::map<CreatureStats::SummonKey, int>::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 b2a3c60eac..9329dcb830 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 <andrei.kortunov@yandex.ru> 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 2daaf9711c..f5013a8f3d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -7,6 +7,8 @@ #include <set> #include <stdint.h> +#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 4910ab932a..8df262f240 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 21afa7b8e5..3f333f4cbe 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 3801cd261c..07e6cc9db0 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 a2d1295223..57e4753828 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 81a3d864c2..9b89c3957c 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 d182e40d74..68115301f6 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 af0377a33f..bba2c55d62 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 42d57ffabf..097ec0faa8 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 <kyleacooley@gmail.com> 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 ef984c0ca4..a7809f3e30 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<std::string>& 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 030a0174e7..ad02014072 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<boost::filesystem::path> 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<std::string>& blacklistedScripts); ~Document(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 098d7bad5a..11378cab49 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 ed8e327d7b..771afe8e59 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<std::string> 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<std::string>& 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 c87e283a80..5c0b2e2824 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 ee9e4329c1..8c25faaa5f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -11,6 +11,7 @@ #include <components/esm/cellref.hpp> #include <components/resource/scenemanager.hpp> +#include <components/vfs/manager.hpp> #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<std::string> CSMWorld::Data::getIds (bool listDeleted) const return ids; } +void CSMWorld::Data::assetsChanged() +{ + VFS::Manager* vfs = mResourcesManager.getVFS(); + vfs->rebuildIndex(); + + ResourceTable* meshTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Meshes)); + ResourceTable* iconTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Icons)); + ResourceTable* musicTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Musics)); + ResourceTable* soundResTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_SoundsRes)); + ResourceTable* texTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Textures)); + ResourceTable* vidTable = static_cast<ResourceTable*>(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 f96003e443..8bc1c42712 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,7 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection<ESM::Filter> mFilters; Collection<MetaData> mMetaData; - const ResourcesManager& mResourcesManager; + ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector<QAbstractItemModel *> mModels; std::map<UniversalId::Type, QAbstractItemModel *> 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 5fe9194d7c..5bf0267bb5 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<std::string, VFS::File*>& index = vfs->getIndex(); diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index d6998da9f0..5e9872ea84 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 016799be35..6b271c2768 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<UniversalId::Type, Resources>::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<UniversalId::Type, Resources>::const_iterator iter = mResources.find (type); diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 1ce06f2d3d..9696668563 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<UniversalId::Type, Resources> 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 5227ec3e63..f55f87873f 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 88dcc24b0c..7d538df530 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 ff49a90fdd..92ed07daf4 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 b36c7117b0..9bdf12c233 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<std::string, File*>& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index ad5150a441..9240909ad5 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<std::string, File *> &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 6c8e1b82bb..16c2d65eac 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<std::string, File*>& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 457947d40d..037fef325f 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<Archive*>::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 6592a65a88..2ad7cf6433 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 <andrei.kortunov@yandex.ru> 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 95dc8cc4dc..7379f3613d 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 ac61041c34..e1f5a165e7 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 5dc1f3454f..c7d2ef7de6 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,7 +3,6 @@ #include <iomanip> #include <MyGUI_Button.h> -#include <MyGUI_EditBox.h> #include <MyGUI_ScrollView.h> #include <components/widgets/list.hpp> @@ -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 6391f85971..cb7c6c0d01 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 4d1a490aad..84d4ca959b 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 cd2d2cd1d1..354253fa4f 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 9ddfac612b..958b52dc08 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 <andrei.kortunov@yandex.ru> 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 97aedab815..e4f6eafdee 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 <krizdjali+github@gmail.com> 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 0000000000..25cc3fffcb --- /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 <krizdjali+github@gmail.com> 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 ca2c6502e5..9fbb82dbac 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 <admin@h313.info> 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 c6f663059d..1cba2e13ae 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 5d911d4bec..46a03818b5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,6 +49,7 @@ namespace MWSound // Caches available music tracks by <playlist name, (sound files) > std::map<std::string, std::vector<std::string> > mMusicFiles; + std::vector<int> 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 <kyleacooley@gmail.com> 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 8c25faaa5f..633b1ae206 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 d19d9cf804..4e48d97459 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 61599cd5e2..58200993b9 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 8d05a1b4e9..a9686e5db9 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,6 +2,8 @@ #include <algorithm> +#include <osgDB/Registry> + #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" @@ -68,6 +70,14 @@ namespace Resource (*it)->updateCache(referenceTime); } + void ResourceSystem::clearCache() + { + for (std::vector<ResourceManager*>::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 dc608b8757..ef9ac96476 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 <kyleacooley@gmail.com> 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 633b1ae206..61db4ff77f 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 8bc1c42712..8fe5eeff9c 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 48156359f1..4b06432d66 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<std::string, Object *>::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 ca82dd580d..f53f619732 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 eb90e9db38..5220570972 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 e28e2562cb..e14697e627 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 b5497558ad..b1077139c2 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<CSMWorld::CellCoordinates, Cell *>::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 0663d34248..8c41df51e2 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 2f35103171..972fb556dc 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 73f7dc810f..630ccf293d 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 b82aa45b21..3201f73033 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<CSMWorld::UniversalId>& 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 5283b3a97e..5274639903 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 a9686e5db9..b1061adcda 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -74,8 +74,6 @@ namespace Resource { for (std::vector<ResourceManager*>::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 <andrei.kortunov@yandex.ru> 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 35dd57ca3d..d875fae22f 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -34,6 +34,7 @@ <Widget type="AutoSizedEditBox" skin="HeaderText" position="0 0 166 18" name="FavoriteAttributesT" align="Left Top"> <Property key="Caption" value="#{sChooseClassMenu2}"/> <Property key="TextAlign" value="Left Top"/> + <Property key="Static" value="true"/> <UserString key="ToolTipType" value="Layout"/> <UserString key="ToolTipLayout" value="TextToolTip"/> <UserString key="Caption_Text" value="#{sCreateClassMenuHelp2}"/> diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index 9ca6c6a319..e2920c7423 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -33,6 +33,7 @@ <Widget type="AutoSizedEditBox" skin="HeaderText" position="0 0 166 18" name="FavoriteAttributesT" align="Left Top"> <Property key="Caption" value="#{sChooseClassMenu2}"/> <Property key="TextAlign" value="Left Top"/> + <Property key="Static" value="true"/> <UserString key="ToolTipType" value="Layout"/> <UserString key="ToolTipLayout" value="TextToolTip"/> <UserString key="Caption_Text" value="#{sCreateClassMenuHelp2}"/> From 6ef5d1408f7dbec911b14c8d6f13838ae80e19b9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 3d341eee5a..43b0518fd1 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layout"> - <Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 244 248" align="Center" name="_Main"> + <Widget type="Window" skin="MW_DialogNoTransp" layer="Windows" position="0 0 244 248" align="Center" name="_Main"> <!-- Edit box --> <Widget type="Widget" skin="MW_Box" position="8 8 220 192" align="Stretch" name="Client"/> diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index eb2a2789d0..7039c719e7 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layout"> - <Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 336 242" align="Center" name="_Main"> + <Widget type="Window" skin="MW_DialogNoTransp" layer="Windows" position="0 0 336 242" align="Center" name="_Main"> <Widget type="AutoSizedTextBox" skin="SandText" position="13 13 200 16"> <Property key="Caption" value="#{sEditNote}"/> 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 1cba2e13ae..c6f663059d 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 46a03818b5..5d911d4bec 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,7 +49,6 @@ namespace MWSound // Caches available music tracks by <playlist name, (sound files) > std::map<std::string, std::vector<std::string> > mMusicFiles; - std::vector<int> 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 <kyleacooley@gmail.com> 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 a7809f3e30..d9f86cddec 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<std::string>& 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 61db4ff77f..d7f42d0273 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<std::string> CSMWorld::Data::getIds (bool listDeleted) const void CSMWorld::Data::assetsChanged() { - VFS::Manager* vfs = mResourcesManager.getVFS(); - vfs->rebuildIndex(); + mVFS->rebuildIndex(); ResourceTable* meshTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Meshes)); ResourceTable* iconTable = static_cast<ResourceTable*>(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 8fe5eeff9c..771a706b37 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,6 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection<ESM::Filter> mFilters; Collection<MetaData> mMetaData; + VFS::Manager* mVFS; ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector<QAbstractItemModel *> 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 6b271c2768..c50b866824 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() +{ + // 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; +} + +void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) { 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 }; - - addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); + 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<UniversalId::Type, Resources>::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 9696668563..0e83853006 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<UniversalId::Type, Resources> 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 b1061adcda..d7a6771c4e 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,8 +2,6 @@ #include <algorithm> -#include <osgDB/Registry> - #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" From 7914fd5c9c42ea4c678a925253d495429c049248 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 9bdf12c233..f2082f7504 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<std::string, File*>& out, char (*normalize_function) (char)) = 0; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index a527a6ad92..88e6bf2c72 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<std::string, File *> &out, char (*normalize_function)(char)) @@ -26,6 +27,17 @@ void BsaArchive::listResources(std::map<std::string, File *> &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 a6e2740378..92204f90c0 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<std::string, File*>& out, char (*normalize_function) (char)); private: + void load(); + + std::string mFileName; Bsa::BSAFile mFile; std::vector<BsaArchiveFile> mResources; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 9240909ad5..8fb992e763 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 16c2d65eac..5843bf8719 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<std::string, File*>& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 037fef325f..9b1798e8f8 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -60,7 +60,7 @@ namespace VFS void Manager::rebuildIndex() { for (std::vector<Archive*>::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 <kyleacooley@gmail.com> 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 2269337600..2f04aa7c2d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -122,6 +122,13 @@ namespace Resource { return _sharedStateSetList.size(); } + + void clearCache() + { + OpenThreads::ScopedLock<OpenThreads::Mutex> 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 c6ff02acf6..14032df776 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 <kyleacooley@gmail.com> 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 4b06432d66..ebc383ff2c 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 15ea15cc4e..d7e8669efe 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<CSMWorld::Cell>& cells = mData.getCells(); diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index d2ed9b458d..47e5867071 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<CSMWorld::Cell>& 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 <kyleacooley@gmail.com> 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 ebc383ff2c..5aa5342326 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 4706555397..361dd6c04e 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -231,4 +231,16 @@ namespace Terrain return buffer; } + void BufferCache::clearCache() + { + { + OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mIndexBufferMutex); + mIndexBufferMap.clear(); + } + { + OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex); + mUvBufferMap.clear(); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index e8963354ba..bfdf558bc0 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -22,6 +22,8 @@ namespace Terrain /// @note Thread safe. osg::ref_ptr<osg::Vec2Array> 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 e4a7c2d682..ea71c726fd 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 553e06d970..2f92fa8361 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 b7cc0ae01c..9bbb585a89 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 d0576fbd34..2fb669494c 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 <kyleacooley@gmail.com> 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 2f04aa7c2d..aba1d454e1 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -721,9 +721,8 @@ namespace Resource { ResourceManager::clearCache(); - mSharedStateMutex.lock(); + OpenThreads::ScopedLock<OpenThreads::Mutex> 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 <kyleacooley@gmail.com> 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 | 38 ++++++++++++---------- 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, 40 insertions(+), 29 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d7f42d0273..39c0291fc5 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<ResourceTable*>(getTableModel(UniversalId::Type_Meshes)); - ResourceTable* iconTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Icons)); - ResourceTable* musicTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Musics)); - ResourceTable* soundResTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_SoundsRes)); - ResourceTable* texTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Textures)); - ResourceTable* vidTable = static_cast<ResourceTable*>(getTableModel(UniversalId::Type_Videos)); + const UniversalId assetTableIds[] = { + UniversalId::Type_Meshes, + UniversalId::Type_Icons, + UniversalId::Type_Musics, + UniversalId::Type_SoundsRes, + UniversalId::Type_Textures, + UniversalId::Type_Videos + }; - meshTable->beginReset(); - iconTable->beginReset(); - musicTable->beginReset(); - soundResTable->beginReset(); - texTable->beginReset(); - vidTable->beginReset(); + size_t numAssetTables = sizeof(assetTableIds) / sizeof(UniversalId); + + for (size_t i = 0; i < numAssetTables; ++i) + { + ResourceTable* table = static_cast<ResourceTable*>(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<ResourceTable*>(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 92ed07daf4..dfbeea0311 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 5aa5342326..a10e38397d 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 010917572a..c1a7eb8f38 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 fec7251ac4..8ae2b531f2 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 fcda455cc2..266139f3cf 100644 --- a/components/resource/multiobjectcache.cpp +++ b/components/resource/multiobjectcache.cpp @@ -43,6 +43,12 @@ namespace Resource objectsToRemove.clear(); } + void MultiObjectCache::clear() + { + OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex); + _objectCache.clear(); + } + void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex); diff --git a/components/resource/multiobjectcache.hpp b/components/resource/multiobjectcache.hpp index a314a9e4b0..527247bf96 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 ef9ac96476..efce50b977 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 aba1d454e1..69a54bf17a 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -723,6 +723,7 @@ namespace Resource OpenThreads::ScopedLock<OpenThreads::Mutex> 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 9bbb585a89..b7cc0ae01c 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 2fb669494c..d0576fbd34 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 <kyleacooley@gmail.com> 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 54e323956d..86c87962dd 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -5,9 +5,6 @@ #include <QLocalSocket> #include <QMessageBox> -#include <components/vfs/manager.hpp> -#include <components/vfs/registerarchives.hpp> - #include <components/fallback/validate.hpp> #include <components/nifosg/nifloader.hpp> @@ -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 ff670ba1be..b60f5c6a84 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,8 +1,6 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H -#include <memory> - #include <boost/interprocess/sync/file_lock.hpp> #include <boost/filesystem/fstream.hpp> @@ -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<VFS::Manager> 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 d9f86cddec..7257b2fe3c 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<std::string>& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, vfs, resourcesManager, fallback, resDir), + ToUTF8::FromType encoding, + const std::vector<std::string>& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& 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 ad02014072..d31fd5aca5 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -9,6 +9,7 @@ #include <QObject> #include <QTimer> +#include <components/files/multidircollection.hpp> #include <components/to_utf8/to_utf8.hpp> #include "../world/data.hpp" @@ -59,7 +60,6 @@ namespace CSMDoc private: - VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector<boost::filesystem::path> 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<std::string>& blacklistedScripts); + const Fallback::Map* fallback, ToUTF8::FromType encoding, + const std::vector<std::string>& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& 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 11378cab49..531cfd2672 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<std::string>& 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 771afe8e59..ae6d9481a3 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -11,8 +11,7 @@ #include <components/to_utf8/to_utf8.hpp> #include <components/fallback/fallback.hpp> - -#include "../world/resourcesmanager.hpp" +#include <components/files/multidircollection.hpp> #include "loader.hpp" @@ -39,9 +38,14 @@ namespace CSMDoc QThread mLoaderThread; Loader mLoader; ToUTF8::FromType mEncoding; - CSMWorld::ResourcesManager mResourcesManager; std::vector<std::string> mBlacklistedScripts; - VFS::Manager* mVFS; + + boost::filesystem::path mResDir; + Fallback::Map mFallbackMap; + + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector<std::string> mArchives; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -74,15 +78,11 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector<std::string>& 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<std::string>& 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 39c0291fc5..007190e4a7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ #include <components/resource/scenemanager.hpp> #include <components/vfs/manager.hpp> +#include <components/vfs/registerarchives.hpp> #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<std::string>& 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<std::string> 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 771a706b37..8a3667ea11 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -31,6 +31,7 @@ #include <components/resource/resourcesystem.hpp> +#include <components/files/multidircollection.hpp> #include <components/to_utf8/to_utf8.hpp> #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<ESM::Filter> mFilters; Collection<MetaData> mMetaData; - VFS::Manager* mVFS; - ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector<QAbstractItemModel *> mModels; std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex; @@ -120,6 +120,11 @@ namespace CSMWorld std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache; int mReaderIndex; + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector<std::string> mArchives; + std::unique_ptr<VFS::Manager> mVFS; + ResourcesManager mResourcesManager; std::shared_ptr<Resource::ResourceSystem> mResourceSystem; std::vector<std::shared_ptr<ESM::ESMReader> > 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<std::string>& 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 f2082f7504..b36c7117b0 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<std::string, File*>& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index 88e6bf2c72..9b686049fe 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<std::string, File *> &out, char (*normalize_function)(char)) { for (std::vector<BsaArchiveFile>::iterator it = mResources.begin(); it != mResources.end(); ++it) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 92204f90c0..217594abd2 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<std::string, File*>& out, char (*normalize_function) (char)); private: diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 8fb992e763..ad5150a441 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<std::string, File *> &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 5843bf8719..6c8e1b82bb 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<std::string, File*>& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 9b1798e8f8..4f3994bace 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<Archive*>::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<Archive*>::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 2ad7cf6433..c5f0a8fec3 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 <andrei.kortunov@yandex.ru> 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 9c57a2a7f5..3a730fbeb3 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<ESM::MagicEffect>().find(effect.mEffectID); // Underwater casting not possible From d3d04171f9f1c80cfce59ed99a3e66da8fa57770 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 a10e38397d..153de773cf 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 9b686049fe..a527a6ad92 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<std::string, File *> &out, char (*normalize_function)(char)) @@ -21,17 +26,6 @@ void BsaArchive::listResources(std::map<std::string, File *> &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 217594abd2..a6e2740378 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -27,9 +27,6 @@ namespace VFS virtual void listResources(std::map<std::string, File*>& out, char (*normalize_function) (char)); private: - void load(); - - std::string mFileName; Bsa::BSAFile mFile; std::vector<BsaArchiveFile> mResources; From 0177fe6602f5550538be170ce18a09fd8bb90eae Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 20d3448b53..1375940763 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 <kyleacooley@gmail.com> 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 c50b866824..62dfe53a9e 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 <kyleacooley@gmail.com> 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 153de773cf..765c5b3161 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<osg::ref_ptr<CSVRender::TagBase> > 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<std::string, Object *>::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 228b2b5e76..a9cce02007 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<PathgridTag*>(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId) From a8576d78ad4ed809a336ea8a89e40eec0ad3585f Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 f68c69094e..2f1615c876 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<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())). - findColumnIndex ( - getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ? - CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal); + CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&> (*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" <me@hristos.triantafillou.us> 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 791e773533..71ac294688 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 <AnyOldName3@users.noreply.github.com> 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 46bd7d3f96..0f2d807aae 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -4,6 +4,7 @@ #include <iosfwd> #include <iostream> #include <boost/filesystem/path.hpp> +#include <MyGUI_TextIterator.h> #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 <harry@h313.info> 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 c48647f4e4..bb773c4ef0 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 c6f663059d..8117973694 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -3,6 +3,7 @@ #include <iostream> #include <algorithm> #include <map> +#include <numeric> #include <osg/Matrixf> @@ -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<std::string> filelist; + auto &tracklist = mMusicToPlay[mCurrentPlaylist]; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { const std::map<std::string, VFS::File*>& 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 5d911d4bec..691e52932e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -6,6 +6,7 @@ #include <utility> #include <deque> #include <map> +#include <unordered_map> #include <components/settings/settings.hpp> @@ -49,6 +50,7 @@ namespace MWSound // Caches available music tracks by <playlist name, (sound files) > std::map<std::string, std::vector<std::string> > mMusicFiles; + std::unordered_map<std::string, std::vector<int>> 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 3a801ffc3a..11c7f59264 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -221,8 +221,8 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> 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 100c17e11e..1a53495a9c 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -73,8 +73,6 @@ namespace MWGui std::vector<std::string> mSplashScreens; - // TODO: add releaseGLObjects() for mTexture - osg::ref_ptr<osg::Texture2D> mTexture; std::unique_ptr<MyGUI::ITexture> mGuiTexture; diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 4e48d97459..c0e99674ec 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 58200993b9..6031ecc01d 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<Resource::ObjectCache> mCache; diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index d7a6771c4e..4d61dce692 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<ResourceManager*>::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 efce50b977..396bdb8fa5 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<SceneManager> mSceneManager; std::unique_ptr<ImageManager> mImageManager; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 69a54bf17a..ab801ab82f 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<OpenThreads::Mutex> lock(mSharedStateMutex); + mSharedStateManager->releaseGLObjects(state); } void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 14032df776..65524f76ed 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 2bfb17b5c0..7cb49c6cb5 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<OpenThreads::Mutex> 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 5196dbe809..bd820a725c 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -32,6 +32,7 @@ namespace Shader osg::ref_ptr<osg::Program> getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader); + void releaseGLObjects(osg::State* state); private: std::string mPath; diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 361dd6c04e..1734686def 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<OpenThreads::Mutex> lock(mIndexBufferMutex); + for (auto indexbuffer : mIndexBufferMap) + indexbuffer.second->releaseGLObjects(state); + } + { + OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mUvBufferMutex); + for (auto uvbuffer : mUvBufferMap) + uvbuffer.second->releaseGLObjects(state); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index bfdf558bc0..37563d2c67 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 ea71c726fd..7575113ef2 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 2f92fa8361..46531f23ec 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 e514cca121..522cf6ac3c 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 Nif::Property*>::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<const Nif::NiVertexColorProperty*>(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 522cf6ac3c..78186c439f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1710,10 +1710,8 @@ namespace NifOsg const Nif::NiVertexColorProperty* vertprop = static_cast<const Nif::NiVertexColorProperty*>(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 <andrei.kortunov@yandex.ru> 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 2daaf9711c..7966cb6daa 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 416a7ad872..d7ccfa3e44 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 efb6248afa..62a9b6d0ff 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -4,6 +4,7 @@ #include <components/settings/settings.hpp> #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<std::vector<int>, 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 8b0f895d1f..4cba7a0aee 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 619540cff3..4e44624097 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<MWWorld::Ptr>(); + 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 afbcff001e..64db9043e0 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 0c3485e6ad..5ce3fd1fe6 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 97aedab815..06854c43fe 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 f74ba21a3e..ceb6f62b74 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 a823ae0fd6..5f3e3152da 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 9a23526f7e..cd15c4074e 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 cd949696b9..b7aae21e8d 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 25d04d1763..e9f42476bb 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 66039bf5d7..bde64cdfb7 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 d182e40d74..c0685e6f08 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 af0377a33f..1cab13cbcb 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 <andrei.kortunov@yandex.ru> 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 07cf6ff5ff..d06e73c932 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<ESM::Enchantment>().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<float>(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 78186c439f..b7d1c15b84 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<SceneUtil::RigGeometry> 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 1385f771e5..8634a4df6c 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 <andrei.kortunov@yandex.ru> 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 84e5794e37..0e1b2cc89d 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<float>& value) { - int current = std::max(0, static_cast<int>(value.getCurrent())); + int current = static_cast<int>(value.getCurrent()); int modified = static_cast<int>(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 1a680b8017..bf18e7355e 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<float>& value) { - int current = std::max(0, static_cast<int>(value.getCurrent())); + int current = static_cast<int>(value.getCurrent()); int modified = static_cast<int>(value.getModified()); mFatigue->setValue(current, modified); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 22140b8b2c..17e51e3383 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<float>& value) { - int current = std::max(0, static_cast<int>(value.getCurrent())); + int current = static_cast<int>(value.getCurrent()); int modified = static_cast<int>(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 695337cde4..744ef236fa 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 34680fa945..77593dece0 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 ``<whatever>`` +GNU/Linux ``~/.config/openmw/`` OS X ``~/Library/Application Support/openmw/`` -Windows ``<whatever>`` +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 02a65ff213..fa069d8d6d 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 9844948ead..bb1097e0cf 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(<property>, <pattern>)` query will check -whether `<propery>` matches `<pattern>`. The pattern is a regular expression, +whether `<property>` matches `<pattern>`. 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 b7d1c15b84..78186c439f 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<SceneUtil::RigGeometry> 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 8634a4df6c..1385f771e5 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 c921e17d07..f5ec86cc31 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 4efa7c2737..5d01525b96 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -2,6 +2,8 @@ #include <cassert> +#include <OpenThreads/Thread> + #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<double>(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 7f7919f813..9163b21f3c 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 ca6a0b0a48..c5836b6530 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 1a53495a9c..2f8831fdc5 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 b0d0d8acd2..33ba58cc7c 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 <andrei.kortunov@yandex.ru> 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 b8f6f5ecb2..15499c1a8a 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -3,6 +3,7 @@ #include <components/esm/loadlock.hpp> #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<int, std::string> 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 efa675c950..1bcf7fb85d 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<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr<MWWorld::Action> 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 ecaa056f9d..030ee3f8bf 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -3,6 +3,7 @@ #include <components/esm/loadprob.hpp> #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<int, std::string> 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 f67d8af863..9ac3ab0c9e 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<int, std::string> canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr<MWWorld::Action> 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 4e44624097..e912193bf3 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -344,16 +344,17 @@ namespace MWGui { MWWorld::Ptr item = *button->getUserData<MWWorld::Ptr>(); 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 <andrei.kortunov@yandex.ru> 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 4cba7a0aee..6a2d3ff83a 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 <andrei.kortunov@yandex.ru> 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 8117973694..15b95b2339 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 d85b722039..2d5fdfb39a 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 8f4597ff36..83f28e0638 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -52,7 +52,7 @@ namespace Shader void applyStateSet(osg::ref_ptr<osg::StateSet> 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<ShaderRequirements> 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 78186c439f..b7d1c15b84 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<SceneUtil::RigGeometry> 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 1385f771e5..8634a4df6c 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 e5e36def8a..79c6dcabfc 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<const Resource::BulletShape> 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 <kyleacooley@gmail.com> 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 5c0b2e2824..0101a432bd 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 154bdab82d..a9a48ef0da 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<typename ESXRecordT> struct TopicColumn : public Column<ESXRecordT> { - TopicColumn (bool journal) + TopicColumn (bool journal) : Column<ESXRecordT> (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<ESXRecordT>& record) const @@ -1755,7 +1758,7 @@ namespace CSMWorld return true; } }; - + template<typename ESXRecordT> struct GenderNpcColumn : public Column<ESXRecordT> { @@ -2198,8 +2201,8 @@ namespace CSMWorld struct EffectTextureColumn : public Column<ESXRecordT> { EffectTextureColumn (Columns::ColumnId columnId) - : Column<ESXRecordT> (columnId, - columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : Column<ESXRecordT> (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<typename ESXRecordT> + struct TextureIndexColumn : public Column<ESXRecordT> + { + TextureIndexColumn() + : Column<ESXRecordT> (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record<ESXRecordT>& record) const + { + return record.get().mIndex; + } + + virtual bool isEditable() const + { + return false; + } + }; + + // TODO remove + template<typename ESXRecordT> + struct PluginIndexColumn : public Column<ESXRecordT> + { + PluginIndexColumn() + : Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record<ESXRecordT>& record) const + { + return -1; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template<> + inline QVariant PluginIndexColumn<Land>::get (const Record<Land>& record) const + { + return record.get().mPlugin; + } + + template<> + inline QVariant PluginIndexColumn<LandTexture>::get (const Record<LandTexture>& record) const + { + return record.get().mPluginIndex; + } + struct BodyPartRaceColumn : public RaceColumn<ESM::BodyPart> { const MeshTypeColumn<ESM::BodyPart> *mMeshType; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index aeee0d2087..cec11211c6 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 b23d863678..1ff871c844 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 007190e4a7..456d2bccc1 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<ESM::MagicEffect>); + mLand.addColumn (new StringIdColumn<Land>); + mLand.addColumn (new RecordStateColumn<Land>); + mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land)); + mLand.addColumn (new PluginIndexColumn<Land>); + + mLandTextures.addColumn (new StringIdColumn<LandTexture>); + mLandTextures.addColumn (new RecordStateColumn<LandTexture>); + mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new PluginIndexColumn<LandTexture>); + mLandTextures.addColumn (new TextureIndexColumn<LandTexture>); + mLandTextures.addColumn (new TextureColumn<LandTexture>); + mPathgrids.addColumn (new StringIdColumn<Pathgrid>); mPathgrids.addColumn (new RecordStateColumn<Pathgrid>); mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (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 77db2be108..38386f6daf 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::Type> 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 e9104fc226..accd1b78da 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 dfbeea0311..10de46e064 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 834407be05..46aa87891a 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 7c27bdf7a8..b570397b7d 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 <kyleacooley@gmail.com> 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 0a146dc06b..4207258db6 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 16f5ce51f4..9d867ff933 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -6,6 +6,7 @@ #include <algorithm> #include <cctype> #include <stdexcept> +#include <string> #include <functional> #include <QVariant> @@ -13,8 +14,8 @@ #include <components/misc/stringops.hpp> #include "columnbase.hpp" - #include "collectionbase.hpp" +#include "landtexture.hpp" namespace CSMWorld { @@ -22,15 +23,14 @@ namespace CSMWorld template<typename ESXRecordT> 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<typename ESXRecordT> - std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record) + void IdAccessor<ESXRecordT>::setId(ESXRecordT& record, const std::string& id) const { - return record.mId; + record.mId = id; } template<typename ESXRecordT> @@ -39,6 +39,23 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor<LandTexture>::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<LandTexture>::getId (const LandTexture& record) const + { + return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex); + } + /// \brief Single-type record collection template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> > class Collection : public CollectionBase @@ -213,7 +230,7 @@ namespace CSMWorld Record<ESXRecordT> 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<ESXRecordT> record2; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a9a48ef0da..316fa4366a 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<LandTexture>::get(const Record<LandTexture>& 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<typename ESXRecordT> struct RecordStateColumn : public Column<ESXRecordT> { @@ -2421,6 +2428,31 @@ namespace CSMWorld } }; + template<typename ESXRecordT> + struct TextureHandleColumn : public Column<ESXRecordT> + { + TextureHandleColumn() + : Column<ESXRecordT> (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) + {} + + QVariant get(const Record<ESXRecordT>& record) const override + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void set(Record<ESXRecordT>& 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<typename ESXRecordT> struct TextureIndexColumn : public Column<ESXRecordT> { @@ -2428,31 +2460,30 @@ namespace CSMWorld : Column<ESXRecordT> (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) {} - QVariant get (const Record<ESXRecordT>& record) const + QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mIndex; } - virtual bool isEditable() const + bool isEditable() const override { return false; } }; - // TODO remove template<typename ESXRecordT> struct PluginIndexColumn : public Column<ESXRecordT> { PluginIndexColumn() - : Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + : Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) {} - QVariant get (const Record<ESXRecordT>& record) const + QVariant get(const Record<ESXRecordT>& 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 cec11211c6..49935d40df 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 1ff871c844..c6e2a2a415 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 456d2bccc1..b0ab73de1c 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<Land>(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn<Land>); - mLandTextures.addColumn (new StringIdColumn<LandTexture>); + mLandTextures.addColumn (new StringIdColumn<LandTexture>(true)); mLandTextures.addColumn (new RecordStateColumn<LandTexture>); mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new TextureHandleColumn<LandTexture>); mLandTextures.addColumn (new PluginIndexColumn<LandTexture>); mLandTextures.addColumn (new TextureIndexColumn<LandTexture>); mLandTextures.addColumn (new TextureColumn<LandTexture>); @@ -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 7975e05eab..078484aabf 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 9faf64d711..ecca269d34 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 266377d0f6..4b82f8d73e 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,5 +1,7 @@ #include "landtexture.hpp" +#include <string> + #include <components/esm/esmreader.hpp> 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 91459eee28..a7376438c1 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 0000000000..f79c084278 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -0,0 +1,106 @@ +#include "landtexturecreator.hpp" + +#include <cstdint> +#include <limits> + +#include <QIntValidator> +#include <QLabel> +#include <QLineEdit> + +#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<uint16_t>::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<CSMWorld::IdTable&>(*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<CSMWorld::IdTable&>(*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 0000000000..46388bf03d --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_WORLD_LANDTEXTURECREATOR_H +#define CSV_WORLD_LANDTEXTURECREATOR_H + +#include <string> + +#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 b570397b7d..a33802823b 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<TableSubView, PathgridCreatorFactory>); + manager.add (CSMWorld::UniversalId::Type_Lands, + new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >); + + manager.add (CSMWorld::UniversalId::Type_LandTextures, + new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator> >); + manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GlobalCreator> >); @@ -183,6 +188,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrid, new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false)); + manager.add (CSMWorld::UniversalId::Type_Land, + new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> >(false)); + + manager.add (CSMWorld::UniversalId::Type_LandTexture, + new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator> >(false)); + manager.add (CSMWorld::UniversalId::Type_DebugProfile, new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false)); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 613b706e30..3e150f9c0c 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 2cb5abf0c8..1604e9281c 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 <kyleacooley@gmail.com> 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 9d867ff933..f69d06d780 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<typename ESXRecordT, typename IdAccessorT> + bool Collection<ESXRecordT, IdAccessorT>::touchRecord(const std::string& id) + { + int index = getIndex(id); + Record<ESXRecordT>& 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<typename ESXRecordT, typename IdAccessorT> Collection<ESXRecordT, IdAccessorT>::Collection() {} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index ef826e31c8..bac790c5d0 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 316fa4366a..92e899a454 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,7 +67,7 @@ namespace CSMWorld inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& 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<typename ESXRecordT> diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5f94223765..c6a56f7b8e 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 b54a1d5acb..4c9be7e8a4 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -5,6 +5,7 @@ #include <string> #include <map> +#include <memory> #include <vector> #include <QVariant> @@ -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<RecordBase> 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 b0ab73de1c..27a914aeb6 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 078484aabf..94eab3fc34 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 ecca269d34..5e5f9da4ab 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 0d77d48efc..8b82f984b9 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 31dae256e4..44a6ce07d0 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 de5a709c6e..48558d1c25 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 30dba42419..580d27a24d 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<CSMWorld::IdTableBase&> (*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<CSMWorld::IdTable*>(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 26f6e78995..d6fa17ef9e 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 <andrei.kortunov@yandex.ru> 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 62a9b6d0ff..9fb4a97678 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<std::vector<int>, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); From a5b01fefec97ca69e07872034853f2bd7f24b9c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 7e1059d06e..84d43156e1 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 5f3e3152da..e4fa8fc2b4 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 fba8d1a4da..ed510e6168 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 052bf4920e..6eb3a29556 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 e9f42476bb..51dc37e185 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 bde64cdfb7..9bcad09949 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 83780e9f82..5f3dd58af3 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 47dc6e6a2a..adad219164 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 <andrei.kortunov@yandex.ru> 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 73927e0ab5..e4d0abf7bb 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 98d29bfc9f..22bafaa71c 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<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(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 | 191 +++++++++++---------------- components/sceneutil/riggeometry.hpp | 22 +-- 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 b7d1c15b84..6b603cc9e2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1236,7 +1236,6 @@ namespace NifOsg SceneUtil::RigGeometry::BoneInfluence influence; const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[i].weights; - //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { std::pair<unsigned short, float> 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> 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 8634a4df6c..1df1be27ff 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 9adfdcddb0..ec01f62d03 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<RigGeometry*>(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<RigGeometry*>(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<osg::Geometry> 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<texCoordList.size(); ++i) - if (texCoordList[i]) - setTexCoordArray(i, texCoordList[i], osg::Array::BIND_PER_VERTEX); - - setVertexAttribArrayList(from.getVertexAttribArrayList()); - - // 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<osg::VertexBufferObject> vbo (new osg::VertexBufferObject); - vbo->setUsage(GL_DYNAMIC_DRAW_ARB); - - osg::ref_ptr<osg::Array> vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); - if (vertexArray) + for (unsigned int i=0; i<2; ++i) { - vertexArray->setVertexBufferObject(vbo); - setVertexArray(vertexArray); - } + 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 - if (osg::Array* normals = from.getNormalArray()) - { - osg::ref_ptr<osg::Array> normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); - if (normalArray) + // 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<osg::VertexBufferObject> vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr<osg::Array> 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<osg::Array> 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<osg::Vec4Array*>(from.getTexCoordArray(7))) - { - mSourceTangents = tangents; - osg::ref_ptr<osg::Array> 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<osg::Vec4Array*>(from.getTexCoordArray(7))) + { + mSourceTangents = tangents; + osg::ref_ptr<osg::Array> 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<osg::Geometry> 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<osg::Vec3Array*>(mSourceGeometry->getVertexArray()); - osg::Vec3Array* normalSrc = static_cast<osg::Vec3Array*>(mSourceGeometry->getNormalArray()); - osg::Vec4Array* tangentSrc = mSourceTangents; + const osg::Vec3Array* positionSrc = static_cast<osg::Vec3Array*>(mSourceGeometry->getVertexArray()); + const osg::Vec3Array* normalSrc = static_cast<osg::Vec3Array*>(mSourceGeometry->getNormalArray()); + const osg::Vec4Array* tangentSrc = mSourceTangents; - osg::Vec3Array* positionDst = static_cast<osg::Vec3Array*>(getVertexArray()); - osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(getNormalArray()); - osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(getTexCoordArray(7)); + osg::Vec3Array* positionDst = static_cast<osg::Vec3Array*>(geom.getVertexArray()); + osg::Vec3Array* normalDst = static_cast<osg::Vec3Array*>(geom.getNormalArray()); + osg::Vec4Array* tangentDst = static_cast<osg::Vec4Array*>(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> 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 39829bcb0a..097e7ea69f 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<osg::Geometry> getSourceGeometry(); - // Called automatically by our CullCallback - void update(osg::NodeVisitor* nv); - - // Called automatically by our UpdateCallback - void updateBounds(osg::NodeVisitor* nv); + virtual void accept(osg::NodeVisitor &nv); private: + void cull(osg::NodeVisitor* nv); + void updateBounds(osg::NodeVisitor* nv); + + osg::ref_ptr<osg::Geometry> mGeometry[2]; + osg::Geometry* getGeometry(unsigned int frame) const; + osg::ref_ptr<osg::Geometry> mSourceGeometry; osg::ref_ptr<osg::Vec4Array> mSourceTangents; Skeleton* mSkeleton; diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 64094275cd..177d700b23 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>, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable osg::Geometry SceneUtil::RigGeometry") + : osgDB::ObjectWrapper(createInstanceFunc<SceneUtil::RigGeometry>, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") { } }; diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 49bc5b70f3..116edfdb4a 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 542471ff13..245e3522c7 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 22bafaa71c..df9b8545a8 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 2d5fdfb39a..2c0b9f0e31 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<int, std::string>::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<osgUtil::TangentSpaceGenerator> 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; + adjustGeometry(geometry, reqs); - if (mAllowedToModifyStateSets && (useShader || generateTangents)) - { - osg::ref_ptr<osg::Geometry> sourceGeometry = &geometry; - SceneUtil::RigGeometry* rig = dynamic_cast<SceneUtil::RigGeometry*>(&geometry); - if (rig) - sourceGeometry = rig->getSourceGeometry(); - - bool requiresSetGeometry = false; - - // make sure that all UV sets are there - for (std::map<int, std::string>::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<osgUtil::TangentSpaceGenerator> 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<SceneUtil::RigGeometry*>(&drawable)) + { + osg::ref_ptr<osg::Geometry> 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 83f28e0638..cb0538d9d3 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 | 21 +-- components/shader/shadervisitor.cpp | 9 +- 10 files changed, 311 insertions(+), 231 deletions(-) create mode 100644 components/sceneutil/morphgeometry.cpp create mode 100644 components/sceneutil/morphgeometry.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ad2c64b6ef..a78eac5721 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 6430dbfce8..88de179039 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 87a0b830e5..262966e957 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -6,11 +6,10 @@ #include <osg/Texture2D> #include <osg/UserDataContainer> -#include <osgAnimation/MorphGeometry> - #include <osgParticle/Emitter> #include <components/nif/data.hpp> +#include <components/sceneutil/morphgeometry.hpp> #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<osgAnimation::MorphGeometry*>(drawable); + SceneUtil::MorphGeometry* morphGeom = static_cast<SceneUtil::MorphGeometry*>(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 5fbb172f9b..0e87af44f1 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 6b603cc9e2..8810f171a2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -13,9 +13,6 @@ #include <components/misc/resourcehelpers.hpp> #include <components/resource/imagemanager.hpp> -// skel -#include <osgAnimation/MorphGeometry> - // particle #include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystemUpdater> @@ -39,6 +36,7 @@ #include <components/nif/effect.hpp> #include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/riggeometry.hpp> +#include <components/sceneutil/morphgeometry.hpp> #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; i<getNumChildren(); ++i) - { - if (i%2 == nv.getTraversalNumber()%2) - getChild(i)->accept(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<osgAnimation::MorphGeometry*>(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<int>& boundTextures, int animflags) { - osg::ref_ptr<osg::Geometry> geometry; + osg::ref_ptr<osg::Drawable> 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<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); + drawable = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController( static_cast<const Nif::NiGeomMorpherController*>(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<osg::Geometry> geom (new osg::Geometry); + drawable = geom; + triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags); } - geometry->setName(triShape->name); + drawable->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> frameswitch = new FrameSwitch; - - osg::ref_ptr<osg::Geometry> 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<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags) + osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags) { - osg::ref_ptr<osgAnimation::MorphGeometry> morphGeom = new osgAnimation::MorphGeometry; - morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // No normals available in the MorphData - morphGeom->setMorphNormals(false); + osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry; - morphGeom->setUpdateCallback(NULL); - morphGeom->setCullCallback(new UpdateMorphGeometry); - morphGeom->setUseVertexBufferObjects(true); - - triShapeToGeometry(triShape, morphGeom, parentNode, composite, boundTextures, animflags); - - morphGeom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW_ARB); + osg::ref_ptr<osg::Geometry> sourceGeometry (new osg::Geometry); + triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags); + morphGeom->setSourceGeometry(sourceGeometry); const std::vector<Nif::NiMorphData::MorphData>& 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<osg::Geometry> 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<osg::BoundingBox> 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; i<vertBounds.size(); ++i) - vertBounds[i].set(osg::Vec3f(0,0,0), osg::Vec3f(0,0,0)); - - for (unsigned int i = 1; i < morphs.size(); ++i) - { - for (unsigned int j=0; j<morphs[i].mVertices.size() && vertBounds.size(); ++j) - { - osg::BoundingBox& bounds = vertBounds[j]; - bounds.expandBy(bounds._max + morphs[i].mVertices[j]); - bounds.expandBy(bounds._min + morphs[i].mVertices[j]); - } - } - - osg::BoundingBox box; - for (unsigned int i=0; i<vertBounds.size(); ++i) - { - vertBounds[i]._max += morphs[0].mVertices[i]; - vertBounds[i]._min += morphs[0].mVertices[i]; - box.expandBy(vertBounds[i]); - } - - // For the initial bounding box (used for object placement) use the default pose, fire off a bounding compute to set this initial box - morphGeom->getBound(); - - // 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 738c7a30d6..08f36cfcf1 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -8,7 +8,7 @@ #include <osgParticle/Emitter> #include <osgParticle/Program> -#include <osgAnimation/MorphGeometry> +#include <components/sceneutil/morphgeometry.hpp> #include <components/sceneutil/riggeometry.hpp> @@ -49,46 +49,12 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast<const osgParticle::ParticleSystem*>(drawable)) return operator()(partsys); - if (dynamic_cast<const osgAnimation::MorphGeometry*>(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<const SceneUtil::RigGeometry*>(drawable)) + if (dynamic_cast<const SceneUtil::RigGeometry*>(drawable) || dynamic_cast<const SceneUtil::MorphGeometry*>(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 0000000000..5d55e75ec0 --- /dev/null +++ b/components/sceneutil/morphgeometry.cpp @@ -0,0 +1,187 @@ +#include "morphgeometry.hpp" + +#include <cassert> + +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<osg::Geometry> 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<osg::VertexBufferObject> vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr<osg::Array> 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<osg::Geometry> 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<mMorphTargets.size(); ++i) + if (mMorphTargets[i].getWeight() > 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<osg::Vec3Array*>(mSourceGeometry->getVertexArray()); + std::vector<osg::BoundingBox> 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; i<vertBounds.size(); ++i) + vertBounds[i].set(osg::Vec3f(0,0,0), osg::Vec3f(0,0,0)); + + for (unsigned int i = 0; i < mMorphTargets.size(); ++i) + { + const osg::Vec3Array& offsets = *mMorphTargets[i].getOffsets(); + for (unsigned int j=0; j<offsets.size() && j<vertBounds.size(); ++j) + { + osg::BoundingBox& bounds = vertBounds[j]; + bounds.expandBy(bounds._max + offsets[j]); + bounds.expandBy(bounds._min + offsets[j]); + } + } + + osg::BoundingBox box; + for (unsigned int i=0; i<vertBounds.size(); ++i) + { + vertBounds[i]._max += sourceVerts[i]; + vertBounds[i]._min += sourceVerts[i]; + box.expandBy(vertBounds[i]); + } + return box; + } +} + +void MorphGeometry::cull(osg::NodeVisitor *nv) +{ + if (mLastFrameNumber == nv->getTraversalNumber() || !mDirty) + { + nv->apply(*getGeometry(mLastFrameNumber)); + return; + } + + mDirty = false; + mLastFrameNumber = nv->getTraversalNumber(); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + + const osg::Vec3Array* positionSrc = static_cast<osg::Vec3Array*>(mSourceGeometry->getVertexArray()); + osg::Vec3Array* positionDst = static_cast<osg::Vec3Array*>(geom.getVertexArray()); + assert(positionSrc->size() == positionDst->size()); + for (unsigned int vertex=0; vertex<positionSrc->size(); ++vertex) + (*positionDst)[vertex] = (*positionSrc)[vertex]; + + for (unsigned int i=0; i<mMorphTargets.size(); ++i) + { + float weight = mMorphTargets[i].getWeight(); + if (weight == 0.f) + continue; + const osg::Vec3Array* offsets = mMorphTargets[i].getOffsets(); + for (unsigned int vertex=0; vertex<positionSrc->size(); ++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 0000000000..1afef18953 --- /dev/null +++ b/components/sceneutil/morphgeometry.hpp @@ -0,0 +1,81 @@ +#ifndef OPENMW_COMPONENTS_MORPHGEOMETRY_H +#define OPENMW_COMPONENTS_MORPHGEOMETRY_H + +#include <osg/Geometry> + +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<osg::Geometry> sourceGeom); + + class MorphTarget + { + protected: + osg::ref_ptr<osg::Vec3Array> 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<MorphTarget> 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<osg::Geometry> getSourceGeometry() const; + + virtual void accept(osg::NodeVisitor &nv); + + virtual osg::BoundingBox computeBoundingBox() const; + + private: + void cull(osg::NodeVisitor* nv); + + MorphTargetList mMorphTargets; + + osg::ref_ptr<osg::Geometry> mSourceGeometry; + + osg::ref_ptr<osg::Geometry> 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 177d700b23..ab03215326 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -6,6 +6,7 @@ #include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/riggeometry.hpp> +#include <components/sceneutil/morphgeometry.hpp> namespace SceneUtil { @@ -37,15 +38,6 @@ public: } }; -class FrameSwitchSerializer : public osgDB::ObjectWrapper -{ -public: - FrameSwitchSerializer() - : osgDB::ObjectWrapper(createInstanceFunc<osg::Group>, "NifOsg::FrameSwitch", "osg::Object osg::Node osg::Group NifOsg::FrameSwitch") - { - } -}; - class RigGeometrySerializer : public osgDB::ObjectWrapper { public: @@ -55,6 +47,15 @@ public: } }; +class MorphGeometrySerializer : public osgDB::ObjectWrapper +{ +public: + MorphGeometrySerializer() + : osgDB::ObjectWrapper(createInstanceFunc<SceneUtil::MorphGeometry>, "SceneUtil::MorphGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::MorphGeometry") + { + } +}; + class LightManagerSerializer : public osgDB::ObjectWrapper { public: @@ -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 2c0b9f0e31..9b3876d6c8 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -13,6 +13,7 @@ #include <components/resource/imagemanager.hpp> #include <components/vfs/manager.hpp> #include <components/sceneutil/riggeometry.hpp> +#include <components/sceneutil/morphgeometry.hpp> #include "shadermanager.hpp" @@ -376,12 +377,18 @@ namespace Shader const ShaderRequirements& reqs = mRequirements.back(); createProgram(reqs); - if (SceneUtil::RigGeometry* rig = dynamic_cast<SceneUtil::RigGeometry*>(&drawable)) + if (auto rig = dynamic_cast<SceneUtil::RigGeometry*>(&drawable)) { osg::ref_ptr<osg::Geometry> sourceGeometry = rig->getSourceGeometry(); if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) rig->setSourceGeometry(sourceGeometry); } + else if (auto morph = dynamic_cast<SceneUtil::MorphGeometry*>(&drawable)) + { + osg::ref_ptr<osg::Geometry> 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 5d55e75ec0..4c53b68a52 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -31,7 +31,7 @@ void MorphGeometry::setSourceGeometry(osg::ref_ptr<osg::Geometry> 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 ec01f62d03..f3eea1bbdf 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -35,7 +35,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr<osg::Geometry> 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<osg::Geometry> sourceGeometry) to.setVertexArray(vertexArray); } - if (osg::Array* normals = from.getNormalArray()) + if (const osg::Array* normals = from.getNormalArray()) { osg::ref_ptr<osg::Array> normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); if (normalArray) @@ -64,7 +64,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr<osg::Geometry> sourceGeometry) } } - if (osg::Vec4Array* tangents = dynamic_cast<osg::Vec4Array*>(from.getTexCoordArray(7))) + if (const osg::Vec4Array* tangents = dynamic_cast<const osg::Vec4Array*>(from.getTexCoordArray(7))) { mSourceTangents = tangents; osg::ref_ptr<osg::Array> tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 097e7ea69f..638f53679f 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<osg::Geometry> mSourceGeometry; - osg::ref_ptr<osg::Vec4Array> mSourceTangents; + osg::ref_ptr<const osg::Vec4Array> mSourceTangents; Skeleton* mSkeleton; osg::ref_ptr<osg::RefMatrix> 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 4c53b68a52..98e5a92bc5 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 f3eea1bbdf..f52bca80c0 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 <wjherrmann@gmail.com> 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 0a146dc06b..fc8930b719 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 <wjherrmann@gmail.com> 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 2344222e53..a1c6c2068a 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 98e5a92bc5..2ffbace3b9 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 1afef18953..122c1456c5 100644 --- a/components/sceneutil/morphgeometry.hpp +++ b/components/sceneutil/morphgeometry.hpp @@ -57,6 +57,8 @@ namespace SceneUtil osg::ref_ptr<osg::Geometry> 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 f52bca80c0..7f148cf5e3 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 638f53679f..64f4bf3122 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,8 @@ namespace SceneUtil osg::ref_ptr<osg::Geometry> 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 <kyleacooley@gmail.com> 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 320bbf6aeb..0020fd3c85 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<CSMWorld::UniversalId>& 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 bf4c4967f7..bde523a09a 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<CSMWorld::UniversalId>& ids) +{ + // Combine multiple touch commands into one "macro" command + std::unique_ptr<QUndoCommand> macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*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 60d487bc1a..d708c10476 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<CSMWorld::UniversalId>& 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 580d27a24d..3cccaaa223 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<CSMWorld::IdTable*>(mModel)) + std::vector<CSMWorld::UniversalId> touchIds; + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) { - 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); + 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 d6fa17ef9e..02f9023e70 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<CSMWorld::UniversalId>& ids); + void closeRequest(); void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 5a25bbc53e..cfde5c694d 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<CSMWorld::UniversalId>& ids) +{ + mCreator->touch(ids); +} + void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds) { extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 781cccc9eb..5402c466e8 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<CSMWorld::UniversalId>&); void extendedDeleteConfigRequest(const std::vector<std::string> &selectedIds); void extendedRevertConfigRequest(const std::vector<std::string> &selectedIds); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 6664a37713..12e29995da 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<CSMWorld::UniversalId>&)), + mBottom, SLOT(touchRequest(const std::vector<CSMWorld::UniversalId>&))); + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector<std::string> &)), mBottom, SLOT(extendedDeleteConfigRequest(const std::vector<std::string> &))); connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector<std::string> &)), From 7cc95a11a47721cd9c3f70d6acf9b0d595f576ba Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> Date: Sun, 3 Sep 2017 20:00:19 -0400 Subject: [PATCH 120/521] Add more land table columns --- apps/opencs/model/world/columnimp.cpp | 242 +++++++++++++++++++++++--- 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, 278 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index dc3d39edb2..65d2fecd2c 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<ESM::BodyPart> *meshType) - : mMeshType(meshType) -{} - -QVariant CSMWorld::BodyPartRaceColumn::get(const Record<ESM::BodyPart> &record) const +namespace CSMWorld { - if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + /* LandMapLodColumn */ + LandMapLodColumn::LandMapLodColumn() + : Column<Land>(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) { - return QString::fromUtf8(record.get().mRace.c_str()); } - return QVariant(QVariant::UserType); -} - -void CSMWorld::BodyPartRaceColumn::set(Record<ESM::BodyPart> &record, const QVariant &data) -{ - ESM::BodyPart record2 = record.get(); - - record2.mRace = data.toString().toUtf8().constData(); - - record.setModified(record2); -} - -bool CSMWorld::BodyPartRaceColumn::isEditable() const -{ - return true; + + QVariant LandMapLodColumn::get(const Record<Land>& record) const + { + // Note: original data is signed + const char* rawData = reinterpret_cast<const char*>(&record.get().mWnam[0]); + return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + } + + void LandMapLodColumn::set(Record<Land>& record, const QVariant& data) + { + Land copy = record.get(); + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast<const signed char*>(array.data()); + + assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + + for (int i = 0; i < array.count(); ++i) + { + copy.mWnam[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandMapLodColumn::isEditable() const + { + return true; + } + + /* LandNormalsColumn */ + LandNormalsColumn::LandNormalsColumn() + : Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandNormalsColumn::get(const Record<Land>& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is signed + const char* rawData = reinterpret_cast<const char*>(&landData->mNormals[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandNormalsColumn::set(Record<Land>& 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<const signed char*>(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<Land>(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandHeightsColumn::get(const Record<Land>& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is float + const char* rawData = reinterpret_cast<const char*>(&landData->mHeights[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + } + + void LandHeightsColumn::set(Record<Land>& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const float* rawData = reinterpret_cast<const float*>(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<Land>(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandColoursColumn::get(const Record<Land>& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is unsigned char + const char* rawData = reinterpret_cast<const char*>(&landData->mColours[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandColoursColumn::set(Record<Land>& 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<const unsigned char*>(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<Land>(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandTexturesColumn::get(const Record<Land>& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is uint16_t + const char* rawData = reinterpret_cast<const char*>(&landData->mTextures[0]); + return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + } + + void LandTexturesColumn::set(Record<Land>& 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<const uint16_t*>(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<ESM::BodyPart> *meshType) + : mMeshType(meshType) + {} + + QVariant BodyPartRaceColumn::get(const Record<ESM::BodyPart> &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<ESM::BodyPart> &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 92e899a454..f58a35bc4a 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<Land> + { + LandMapLodColumn(); + + QVariant get(const Record<Land>& record) const override; + void set(Record<Land>& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandNormalsColumn : public Column<Land> + { + LandNormalsColumn(); + + QVariant get(const Record<Land>& record) const override; + void set(Record<Land>& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandHeightsColumn : public Column<Land> + { + LandHeightsColumn(); + + QVariant get(const Record<Land>& record) const override; + void set(Record<Land>& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandColoursColumn : public Column<Land> + { + LandColoursColumn(); + + QVariant get(const Record<Land>& record) const override; + void set(Record<Land>& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandTexturesColumn : public Column<Land> + { + LandTexturesColumn(); + + QVariant get(const Record<Land>& record) const override; + void set(Record<Land>& record, const QVariant& data) override; + bool isEditable() const override; + }; + struct BodyPartRaceColumn : public RaceColumn<ESM::BodyPart> { const MeshTypeColumn<ESM::BodyPart> *mMeshType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c6e2a2a415..432597105a 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 27a914aeb6..3284d9b056 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<Land>); mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn<Land>); + mLand.addColumn (new LandMapLodColumn); + mLand.addColumn (new LandNormalsColumn); + mLand.addColumn (new LandHeightsColumn); + mLand.addColumn (new LandColoursColumn); + mLand.addColumn (new LandTexturesColumn); mLandTextures.addColumn (new StringIdColumn<LandTexture>(true)); mLandTextures.addColumn (new RecordStateColumn<LandTexture>); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 9f33c37da8..a7b97a4654 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 <kyleacooley@gmail.com> 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 4207258db6..36ff8cf675 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 f69d06d780..fccbebd43d 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<Land>::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<LandTexture>::setId (LandTexture& record, const std::string& id) const { @@ -50,6 +63,12 @@ namespace CSMWorld record.mIndex = index; } + template<> + inline const std::string IdAccessor<Land>::getId (const Land& record) const + { + return Land::createUniqueRecordId(record.mX, record.mY); + } + template<> inline const std::string IdAccessor<LandTexture>::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<typename ESXRecordT, typename IdAccessorT> - void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin, - const std::string& destination, - const UniversalId::Type type) + int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin, + const std::string& destination, UniversalId::Type type) { - Record<ESXRecordT> copy; - copy.mModified = getRecord(origin).get(); - copy.mState = RecordBase::State_ModifiedOnly; - IdAccessorT().setId(copy.get(), destination); + Record<ESXRecordT> 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<typename ESXRecordT, typename IdAccessorT> - bool Collection<ESXRecordT, IdAccessorT>::touchRecord(const std::string& id) + int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id) { int index = getIndex(id); Record<ESXRecordT>& 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<typename ESXRecordT, typename IdAccessorT> + void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + cloneRecordImp(origin, destination, type); + } + + template<> + inline void Collection<Land, IdAccessor<Land> >::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<typename ESXRecordT, typename IdAccessorT> + bool Collection<ESXRecordT, IdAccessorT>::touchRecord(const std::string& id) + { + return touchRecordImp(id) != -1; + } + + template<> + inline bool Collection<Land, IdAccessor<Land> >::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<typename ESXRecordT, typename IdAccessorT> diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 80f86c7467..22fc965993 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 e5f25c1d3d..cc7e914af3 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 0000000000..34599b2c40 --- /dev/null +++ b/apps/opencs/view/world/landcreator.cpp @@ -0,0 +1,79 @@ +#include "landcreator.hpp" + +#include <limits> + +#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<int>::max(); + const int MinInt = std::numeric_limits<int>::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 0000000000..aea202dcd4 --- /dev/null +++ b/apps/opencs/view/world/landcreator.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_WORLD_LANDCREATOR_H +#define CSV_WORLD_LANDCREATOR_H + +#include <QLabel> +#include <QSpinBox> + +#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 a33802823b..3e72f9a9e6 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<TableSubView, PathgridCreatorFactory>); manager.add (CSMWorld::UniversalId::Type_Lands, - new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >); + new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandCreator> >); manager.add (CSMWorld::UniversalId::Type_LandTextures, new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<LandTextureCreator> >); @@ -189,7 +190,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, PathgridCreatorFactory> (false)); manager.add (CSMWorld::UniversalId::Type_Land, - new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> >(false)); + new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandCreator> >(false)); manager.add (CSMWorld::UniversalId::Type_LandTexture, new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<LandTextureCreator> >(false)); From d3014cf39424972a3b86bc61bfe92cf54551d7b2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 c63d41be3e..51c9dd0093 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<const ESMTerrain::LandObject> 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(); + int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)); + if (row == -1) + return nullptr; - for (int i=0; i<numRecords; ++i) - { - const CSMWorld::LandTexture* ltex = &mData.getLandTextures().getRecord(i).get(); - if (ltex->mIndex == index && ltex->mPluginIndex == plugin) - return ltex; - } - - 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 72c3eb98d5..7d48dd0371 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 a7b97a4654..223b7975aa 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 <kyleacooley@gmail.com> 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 22fc965993..2b12b55fef 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,6 +1,7 @@ #include "land.hpp" #include <sstream> +#include <exception> namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4b82f8d73e..63ebbc11fa 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,7 @@ #include "landtexture.hpp" #include <string> +#include <exception> #include <components/esm/esmreader.hpp> 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 2ffbace3b9..1b7e4ca93e 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<osg::Geometry> MorphGeometry::getSourceGeometry() const From 97d0fd756a2dff3ac73bd308a1ad7f88c3e4e13d Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 c6a56f7b8e..c98f527772 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -2,6 +2,7 @@ #include <cmath> #include <sstream> +#include <unordered_set> #include <components/misc/stringops.hpp> @@ -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<uint16_t*>(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<uint16_t*>(newTextureByteArray.data()); + + // Find all indices used + std::unordered_set<int> 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<std::string> oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } + + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(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 4c9be7e8a4..5f4259cb88 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<RecordBase> mOld; + std::vector<std::string> 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 94eab3fc34..5543fc13f2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,11 +1,13 @@ #include "idtable.hpp" +#include <limits> #include <stdexcept> #include <components/esm/cellid.hpp> #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<std::string>& 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<const Record<LandTexture>&>(idCollection()->getRecord(oldRow)).get(); + const LandTexture& newLtex = dynamic_cast<const Record<LandTexture>&>(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<uint16_t>::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 5e5f9da4ab..ccc5ac4043 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<std::string,std::string>; + + /// The newly added records + std::vector<std::string> createdRecords; + /// The 1st string is the original id, the 2nd is the mapped id + std::vector<StringPair> 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<std::string>& ids); }; } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 2b12b55fef..74833d7efb 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,7 +1,7 @@ #include "land.hpp" #include <sstream> -#include <exception> +#include <stdexcept> namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 63ebbc11fa..32bab1e6d1 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,7 +1,7 @@ #include "landtexture.hpp" #include <string> -#include <exception> +#include <stdexcept> #include <components/esm/esmreader.hpp> diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 34599b2c40..08b8b36209 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,8 @@ #include <limits> +#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<CSMWorld::UniversalId>& ids) + { + // Combine multiple touch commands into one "macro" command + std::unique_ptr<QUndoCommand> macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*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 aea202dcd4..ef8cf60d5b 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<CSMWorld::UniversalId>& ids) override; + void focus() override; void reset() override; From 99e90ef808ec95d3c5e22e3e72d99ef10e58b0d9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 0101a432bd..1f84c5a87d 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 fccbebd43d..80117d0c6c 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 f58a35bc4a..8e5908bd37 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<Land>::get(const Record<Land>& record) const + { + const Land& land = record.get(); + return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + } + template<> inline QVariant StringIdColumn<LandTexture>::get(const Record<LandTexture>& 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 49935d40df..63ccb6017a 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 5543fc13f2..127ffde2c7 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,6 @@ #include "idtable.hpp" +#include <cstdint> #include <limits> #include <stdexcept> @@ -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<uint16_t>::max(); - size_t Prime = (1 << 19) - 1; // A mersenne prime - size_t K = 2154; + size_t MaxIndex = std::numeric_limits<uint16_t>::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 74833d7efb..bfa927444e 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 cc7e914af3..e604f13119 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 32bab1e6d1..43deb64a47 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,6 @@ #include "landtexture.hpp" -#include <string> +#include <sstream> #include <stdexcept> #include <components/esm/esmreader.hpp> @@ -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 08b8b36209..a227a6a870 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,9 @@ #include <limits> +#include <QLabel> +#include <QSpinBox> + #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 ef8cf60d5b..9674a2b581 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 <QLabel> -#include <QSpinBox> - #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 f79c084278..fdabfb2818 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -3,9 +3,9 @@ #include <cstdint> #include <limits> -#include <QIntValidator> #include <QLabel> #include <QLineEdit> +#include <QSpinBox> #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 46388bf03d..b11c47758a 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 <andrei.kortunov@yandex.ru> 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 1244686413..48705dc72b 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 <andrei.kortunov@yandex.ru> 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 bdd4c0a2e2..b45da2d1ce 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 <andrei.kortunov@yandex.ru> 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 5956352069..f0fc7fb6e7 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<int> (getSkill (faction.mData.mSkills[i]).getModified())); + skills.push_back (static_cast<int> (getSkill (faction.mData.mSkills[i]).getBase())); } if (skills.empty()) From ab607f302834c1409e1f0d72caa0dc68be83361c Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 | 182 ++++++++++++------ 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, 369 insertions(+), 96 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 80117d0c6c..6e74a17261 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<typename ESXRecordT, typename IdAccessorT> @@ -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 c98f527772..5bfcd68462 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -41,10 +41,116 @@ 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) + , mOldState(0) +{ + setText("Import land textures"); +} + +void CSMWorld::ImportLandTexturesCommand::redo() +{ + int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); + int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); + + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast<uint16_t*>(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<uint16_t*>(newTextureByteArray.data()); + + // Perform touch/copy/etc... + onRedo(); + + // Find all indices used + std::unordered_set<int> 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<std::string> oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } + + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(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 + 1) + newTextureData[i] = newIndex + 1; + } + } + } + + // 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(); +} + +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) @@ -53,75 +159,27 @@ CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTa mOld.reset(mLands.getRecord(mId).clone()); } -void CSMWorld::TouchLandCommand::redo() +const std::string& CSMWorld::TouchLandCommand::getOriginId() const { - 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<uint16_t*>(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<uint16_t*>(newTextureByteArray.data()); - - // Find all indices used - std::unordered_set<int> 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<std::string> oldTextures; - for (int index : texIndices) - { - oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); - } - - // Import the textures, replace old values - LandTextureIdTable::ImportResults results = dynamic_cast<LandTextureIdTable&>(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); - } + return mId; } -void CSMWorld::TouchLandCommand::undo() +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 5f4259cb88..aab0c54108 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<std::string> 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<RecordBase> mOld; - std::vector<std::string> mCreatedTextures; bool mChanged; }; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 765c5b3161..51279cac4b 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<CSMWorld::Land>& 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<CSMWorld::Land>& 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<std::string, Object *>::const_iterator iter (mObjects.begin()); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f53f619732..f6db475d7c 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 b1077139c2..b224ac1c49 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 8c41df51e2..6672c2268f 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 bde523a09a..bd3da230d2 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 d708c10476..3baacfc06e 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 a227a6a870..dd7bfe68de 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<CSMWorld::CreateCommand> command, const std::string& id) + { + if (mCloneMode) + { + CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*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 9674a2b581..e0c5577e42 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<CSMWorld::CreateCommand> 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 7d48dd0371..c816755567 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 223b7975aa..d7b736f997 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 <andrei.kortunov@yandex.ru> 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 f478dad7e6..2e80301d2d 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 <krizdjali+github@gmail.com> 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 27baff8157..19c9558cf8 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 1d5e662d83..b0c67d8fa1 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 93f53d0e8a..a7c25ca2e0 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 8cbe18d513..5d70aa917b 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 4bd6616859..0711375567 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 d7f0200d2a..efe440ae79 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 fc8930b719..65c1d8ed83 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 89b94ce12a..3ef62dfa3b 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 ea4b1209c6..7d6898367f 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 d2b9ab0f6d..2d9a11c512 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 <kyleacooley@gmail.com> 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 51279cac4b..18614a85f5 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<CSMWorld::Land>& 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 f6db475d7c..6418ed249d 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 b224ac1c49..4a745195bf 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 b7cc0ae01c..22c65b62c2 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 d0576fbd34..e1c3828fcd 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 <miroslavr256@gmail.com> 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 d7ccfa3e44..4560ab2700 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 72e1c09f3f..cf4a5b589a 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 <img> 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 33ba58cc7c..4b7b3c3870 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 ceb6f62b74..4f06afb7d9 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 <krizdjali+github@gmail.com> 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 19c9558cf8..167ab9d2c7 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 b0c67d8fa1..90964f2d76 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 a7c25ca2e0..69200583e1 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 5d70aa917b..70a6708a8d 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 0711375567..f1717a4c36 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 efe440ae79..10119d7d79 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 65c1d8ed83..281921c81e 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 3ef62dfa3b..134953f3de 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 7d6898367f..9b09bc41f7 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 2d9a11c512..5f7338e520 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 c5669fa70c..9a1722dab6 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 <krizdjali+github@gmail.com> 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 167ab9d2c7..ec0615ff9c 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 90964f2d76..122ca2f3af 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 69200583e1..82182b7fae 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 70a6708a8d..70281910f1 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 f1717a4c36..e83656708b 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 10119d7d79..3cbee2b7e8 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 <krizdjali+github@gmail.com> 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 70281910f1..aac076404f 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 <kyleacooley@gmail.com> 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 65d2fecd2c..e6b406864b 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 3284d9b056..0ffe5fa21d 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 ea6eefb882..7849aab926 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,6 +4,7 @@ #include <components/esm/esmreader.hpp> #include "collection.hpp" +#include "land.hpp" namespace CSMWorld { @@ -39,6 +40,22 @@ namespace CSMWorld record.load (reader, isDeleted); } + template<> + inline void IdCollection<Land, IdAccessor<Land> >::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<typename ESXRecordT, typename IdAccessorT> int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index c816755567..6f118c1ab9 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 <krizd@PETESLAPTOP> 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 9a1722dab6..460751445d 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 <kyleacooley@gmail.com> 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 6e74a17261..80117d0c6c 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<typename ESXRecordT, typename IdAccessorT> @@ -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 18614a85f5..1c1d496bb2 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 6418ed249d..101aebd585 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 bd3da230d2..5e2118e9b2 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<CSMWorld::UniversalId>& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr<QUndoCommand> macro(new QUndoCommand()); - macro->setText("Touch records"); + mUndoStack.beginMacro("Touch Records"); CSMWorld::IdTable& table = dynamic_cast<CSMWorld::IdTable&>(*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 dd7bfe68de..2ebfe18698 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<CSMWorld::UniversalId>& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr<QUndoCommand> macro(new QUndoCommand()); - macro->setText("Touch records"); + getUndoStack().beginMacro("Touch records"); CSMWorld::IdTable& lands = dynamic_cast<CSMWorld::IdTable&>(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); CSMWorld::IdTable& ltexs = dynamic_cast<CSMWorld::IdTable&>(*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 6f118c1ab9..f597defd7b 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 <krizdjali+github@gmail.com> 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 460751445d..11f230ac6d 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 <kyleacooley@gmail.com> 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 e6b406864b..1ee7f8a039 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<Land>& record) const { - // Note: original data is signed - const char* rawData = reinterpret_cast<const char*>(&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<const char*>(&land.mWnam[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandMapLodColumn::set(Record<Land>& record, const QVariant& data) { - Land copy = record.get(); QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast<const signed char*>(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<Land>& 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<const char*>(&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<const char*>(&land.getLandData()->mNormals[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandNormalsColumn::set(Record<Land>& 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<const signed char*>(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<Land>& 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<const char*>(&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<const char*>(&land.getLandData()->mHeights[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandHeightsColumn::set(Record<Land>& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast<const float*>(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<Land>& 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<const char*>(&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<const char*>(&land.getLandData()->mColours[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandColoursColumn::set(Record<Land>& 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<const unsigned char*>(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<Land>& 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<const char*>(&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<const char*>(&land.getLandData()->mTextures[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandTexturesColumn::set(Record<Land>& 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<const uint16_t*>(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 127ffde2c7..b41eea8f87 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 1c1d496bb2..552a54ac27 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<CellNodeContainer*>(node->getUserData()); + container->getCell()->updateLand(); + } + }; +} + bool CSVRender::Cell::removeObject (const std::string& id) { std::map<std::string, Object *>::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<CSMWorld::CellCoordinates, bool> 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 101aebd585..4446086881 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 f597defd7b..1d2cf75751 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 d7b736f997..7be954b3eb 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 <Capostrophic@users.noreply.github.com> 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 2ad362b335..735c0b66d3 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<osg::Node> 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<osg::Node> attached = SceneUtil::attach(node, mObjectRoot, bonename, found->second.get()); From de14e436803ac3ddb8ad9836d7ce5d90e9a13b68 Mon Sep 17 00:00:00 2001 From: AnyOldName3 <krizdjali+github@gmail.com> 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 11f230ac6d..6686ea1312 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 <kyleacooley@gmail.com> 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 1d2cf75751..083f27cef7 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 <andrei.kortunov@yandex.ru> 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 ed510e6168..d15e1a1a59 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<ESM::GameSetting>().find("fAlarmRadius")->getFloat(); + if (sqrDist > fAlarmRadius * fAlarmRadius) + return; + bool followerOrEscorter = false; for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats2.getAiSequence().begin(); it != creatureStats2.getAiSequence().end(); ++it) { From afbdc27a34995e0bcef7386c4229cdedc3777f0c Mon Sep 17 00:00:00 2001 From: AnyOldName3 <krizdjali+github@gmail.com> 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 a78eac5721..0050104cf3 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 6686ea1312..6573265bd7 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 <Capostrophic@users.noreply.github.com> 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 6ae778fffe..c4b46958d7 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 <andrei.kortunov@yandex.ru> 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 6b1953917e..70910ec2f0 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<int>(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<int>(currentValue))); From 7760e4514c767e266bd72697567f4b9868653ed8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 362ad3b1c9..da8e932795 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 <marc@zpages.de> 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 bb773c4ef0..d9782ccf39 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 bb1097e0cf..b1b147992d 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 a726781733..e62c27fc18 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=<name of your bsa>.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 b1b147992d..fedd424622 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 <psi29a@gmail.com> 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 c5836b6530..946751f681 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,16 +65,26 @@ namespace MWGui const std::map<std::string, VFS::File*>& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); + std::list<std::string> supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ - std::map<std::string, VFS::File*>::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 <psi29a@gmail.com> 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 946751f681..41d7efb414 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,7 +65,9 @@ namespace MWGui const std::map<std::string, VFS::File*>& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); - std::list<std::string> supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ + + /* priority given to the left */ + std::list<std::string> 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 <psi29a@gmail.com> 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 41d7efb414..15d9d555f8 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<std::string> supported_extensions = {".tga", ".dds", ".png", ".bmp", ".jpeg", ".jpg"}; + std::list<std::string> 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 <miroslavr256@gmail.com> 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 82182b7fae..fc5fae72ed 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 68ee93c89e..5c65332beb 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -6,6 +6,7 @@ #include <components/esm/creaturestate.hpp> #include <components/esm/containerstate.hpp> +#include <components/esm/projectilestate.hpp> #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<std::pair<int, std::string>, 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 e4985f9930..a640d67565 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<ESM::GlobalScript> 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 d38069d891..4c8222c561 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -303,6 +303,7 @@ namespace ESSImport converters[ESM::REC_QUES] = std::shared_ptr<Converter>(new ConvertQUES()); converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT()); + converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(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<unsigned int, std::shared_ptr<Converter> >::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 0ad73c2672..eb6ca93365 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -48,6 +48,9 @@ namespace ESSImport std::map<std::pair<int, std::string>, NPCC> mNpcChanges; std::map<std::pair<int, std::string>, CNTC> mContainerChanges; + std::map<std::pair<int, std::string>, int> mActorIdMap; + int mNextActorId; + std::map<std::string, ESM::Creature> mCreatures; std::map<std::string, ESM::NPC> 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 0000000000..b2dcf4e7da --- /dev/null +++ b/apps/essimporter/importproj.cpp @@ -0,0 +1,18 @@ +#include "importproj.h" + +#include <components/esm/esmreader.hpp> + +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 0000000000..b8abab5fa2 --- /dev/null +++ b/apps/essimporter/importproj.h @@ -0,0 +1,47 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H +#define OPENMW_ESSIMPORT_IMPORTPROJ_H + +#include <vector> +#include <components/esm/esmcommon.hpp> +#include <components/esm/util.hpp> + +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<PNAM> mProjectiles; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif From a66d310a1d1d266da479b3e4fe7a3d35b94ce325 Mon Sep 17 00:00:00 2001 From: MiroslavR <miroslavr256@gmail.com> 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 eb6ca93365..4896f5594d 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 <chris.kcat@gmail.com> 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 | 31 ++-- apps/openmw/mwsound/sound.hpp | 46 +++-- apps/openmw/mwsound/sound_output.hpp | 27 +-- 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, 260 insertions(+), 175 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9aa4bafdf6..9986564cd0 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<MWSound::Sound> SoundPtr; - typedef std::shared_ptr<MWSound::Stream> 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 2d7f3a9696..9c9b442c73 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<MWSoundDecoderBridge> 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 042795a8c0..0e000f8d8a 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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(sound->mHandle); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index ea3f393fff..cb943d87e5 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<ALuint> IDDq; IDDq mFreeSources; - typedef std::vector<MWBase::SoundPtr> SoundVec; + typedef std::vector<Sound*> SoundVec; SoundVec mActiveSounds; - typedef std::vector<MWBase::SoundStreamPtr> StreamVec; + typedef std::vector<Stream*> 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 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, 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 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 8c663fb1e0..9a3fc4e751 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 e34d888ee8..907a601b5d 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 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, 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 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 15b95b2339..f8b753a183 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<Sound>()) + , mStreams(new std::deque<Stream>()) + , 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<ESM::GameSetting>().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: "<<e.what()<< std::endl; + if(track) + mUnusedStreams.push_back(track); + track = nullptr; } return track; } - void SoundManager::stopTrack(MWBase::SoundStreamPtr stream) + void SoundManager::stopTrack(Stream *stream) { mOutput->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: "<<e.what()<< std::endl; - sound.reset(); + if(sound) + mUnusedSounds.push_back(sound); + sound = nullptr; } return sound; } - MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, 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 { // 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: "<<e.what()<< std::endl; - sound.reset(); + if(sound) + mUnusedSounds.push_back(sound); + sound = nullptr; } return sound; } - MWBase::SoundPtr SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound3D(const osg::Vec3f& initialPos, 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 { // 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: "<<e.what()<< std::endl; - sound.reset(); + if(sound) + mUnusedSounds.push_back(sound); + sound = nullptr; } return sound; } - void SoundManager::stopSound(MWBase::SoundPtr sound) + void SoundManager::stopSound(Sound *sound) { - if (sound.get()) + if(sound) mOutput->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 691e52932e..836c3f228a 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<Sound_Buffer*> SoundList; SoundList mUnusedBuffers; - typedef std::pair<MWBase::SoundPtr,Sound_Buffer*> SoundBufferRefPair; + std::unique_ptr<std::deque<Sound>> mSounds; + std::vector<Sound*> mUnusedSounds; + + std::unique_ptr<std::deque<Stream>> mStreams; + std::vector<Stream*> mUnusedStreams; + + typedef std::pair<MWBase::Sound*,Sound_Buffer*> SoundBufferRefPair; typedef std::vector<SoundBufferRefPair> SoundBufferRefPairList; typedef std::map<MWWorld::ConstPtr,SoundBufferRefPairList> SoundMap; SoundMap mActiveSounds; - typedef std::map<MWWorld::ConstPtr,MWBase::SoundStreamPtr> SaySoundMap; + typedef std::map<MWWorld::ConstPtr,Stream*> SaySoundMap; SaySoundMap mActiveSaySounds; - typedef std::vector<MWBase::SoundStreamPtr> TrackList; + typedef std::vector<Stream*> 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 5afdce7004..64d601563b 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 bfa4980e95..c7025a3a09 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -103,7 +103,7 @@ namespace MWWorld bool mStack; - std::vector<MWBase::SoundPtr> mSounds; + std::vector<MWBase::Sound*> mSounds; std::vector<std::string> mSoundIds; }; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index eaf88d45a9..c4b46961c3 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 0442007570..84a6c51055 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -288,7 +288,7 @@ namespace MWWorld std::map<std::string, RegionWeather> 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 <chris.kcat@gmail.com> 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 134953f3de..00ae2fa4ab 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 0000000000..4b9a155379 --- /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 <stddef.h> +/* Define int64_t and uint64_t types */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include <inttypes.h> +#elif defined(_WIN32) && defined(__GNUC__) +#include <stdint.h> +#elif defined(_WIN32) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include <inttypes.h> +#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 0000000000..8539fd5178 --- /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 0000000000..57766983f6 --- /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 0e000f8d8a..f2e8bad5c9 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 cb943d87e5..c35c1b2a2b 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 <chris.kcat@gmail.com> 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 9986564cd0..4439fe8f3f 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 f8b753a183..0dd3ef7540 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 <chris.kcat@gmail.com> 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 9a3fc4e751..1389835dba 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 <chris.kcat@gmail.com> 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 0dd3ef7540..67c7f77e47 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 <chris.kcat@gmail.com> 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 f2e8bad5c9..993000edbc 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<typename T> -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<typename T> +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<std::string> 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<ALCint> 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<ALCint> attrs; attrs.push_back(ALC_HRTF_SOFT); From c790fedd3f7e6610c61003d926cd6842a7cf09e4 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 993000edbc..1dd78f5cec 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" <<std::endl; + alFilterf(mWaterFilter, AL_LOWPASS_GAIN, 0.9f); + alFilterf(mWaterFilter, AL_LOWPASS_GAINHF, 0.01f); + } + else + { + alDeleteFilters(1, &mWaterFilter); + mWaterFilter = 0; + } + alGetError(); + } + + alGenAuxiliaryEffectSlots(1, &mEffectSlot); + alGenEffects(1, &mWaterEffect); + if(alGetError() == AL_NO_ERROR) + { + alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() == AL_NO_ERROR) + std::cout<< "EAX Reverb supported" <<std::endl; + else + { + alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if(alGetError() == AL_NO_ERROR) + std::cout<< "Standard Reverb supported" <<std::endl; + } + LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER); + } } mInitialized = true; @@ -643,6 +732,16 @@ void OpenAL_Output::deinit() alDeleteSources(1, &mFreeSources[i]); mFreeSources.clear(); + if(mEffectSlot) + alDeleteAuxiliaryEffectSlots(1, &mEffectSlot); + mEffectSlot = 0; + if(mWaterEffect) + alDeleteEffects(1, &mWaterEffect); + mWaterEffect = 0; + if(mWaterFilter) + alDeleteFilters(1, &mWaterFilter); + mWaterFilter = 0; + alcMakeContextCurrent(0); if(mContext) alcDestroyContext(mContext); @@ -1209,6 +1308,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) , mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index c35c1b2a2b..d92f99a843 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -23,6 +23,10 @@ namespace MWSound ALCdevice *mDevice; ALCcontext *mContext; + struct { + int EXT_EFX : 1; + } ALC; + typedef std::deque<ALuint> 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<StreamThread> mStreamThread; From 0b720cd90c66b4f978819295abeffefe9a2c5b2b Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 1dd78f5cec..596646a74a 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 <chris.kcat@gmail.com> 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 67c7f77e47..9a5963308d 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 <chris.kcat@gmail.com> 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 a0460326b8..aec667a9c4 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 <chris.kcat@gmail.com> 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 836c3f228a..e5889e36d2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -50,7 +50,7 @@ namespace MWSound std::unique_ptr<Sound_Output> mOutput; // Caches available music tracks by <playlist name, (sound files) > - std::map<std::string, std::vector<std::string> > mMusicFiles; + std::unordered_map<std::string, std::vector<std::string>> mMusicFiles; std::unordered_map<std::string, std::vector<int>> 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<std::string,Sound_Buffer*> NameBufferMap; + typedef std::unordered_map<std::string,Sound_Buffer*> NameBufferMap; NameBufferMap mBufferNameMap; // NOTE: unused buffers are stored in front-newest order. From edfba68eb583948db714d2144be261a8800f65f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 596646a74a..1b6b435f27 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" <<std::endl; alFilterf(mWaterFilter, AL_LOWPASS_GAIN, 0.9f); - alFilterf(mWaterFilter, AL_LOWPASS_GAINHF, 0.01f); + alFilterf(mWaterFilter, AL_LOWPASS_GAINHF, 0.125f); } else { @@ -709,18 +709,34 @@ void OpenAL_Output::init(const std::string &devname) } alGenAuxiliaryEffectSlots(1, &mEffectSlot); - alGenEffects(1, &mWaterEffect); + alGetError(); + + alGenEffects(1, &mDefaultEffect); if(alGetError() == AL_NO_ERROR) { - alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); if(alGetError() == AL_NO_ERROR) std::cout<< "EAX Reverb supported" <<std::endl; else { - alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); if(alGetError() == AL_NO_ERROR) std::cout<< "Standard Reverb supported" <<std::endl; } + EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_GENERIC; + props.flGain = 0.0f; + LoadEffect(mDefaultEffect, props); + } + + alGenEffects(1, &mWaterEffect); + if(alGetError() == AL_NO_ERROR) + { + alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() != AL_NO_ERROR) + { + alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + alGetError(); + } LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER); } @@ -745,6 +761,9 @@ void OpenAL_Output::deinit() if(mEffectSlot) alDeleteAuxiliaryEffectSlots(1, &mEffectSlot); mEffectSlot = 0; + if(mDefaultEffect) + alDeleteEffects(1, &mDefaultEffect); + mDefaultEffect = 0; if(mWaterEffect) alDeleteEffects(1, &mWaterEffect); mWaterEffect = 0; @@ -954,10 +973,26 @@ void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat g alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); - 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); @@ -977,10 +1012,26 @@ void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat m if((pos - mListenerPos).length2() > 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<OpenAL_SoundStream*>(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 d92f99a843..fb832abc6d 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 <chris.kcat@gmail.com> 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 9a5963308d..36617f3b2e 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 <chris.kcat@gmail.com> 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 1b6b435f27..146776442a 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 fb832abc6d..777b9207f8 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<ALuint> IDDq; IDDq mFreeSources; From abe80f58683b604f98e49f7386bb451dc4e4400b Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 36617f3b2e..25af9add8b 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 <chris.kcat@gmail.com> 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 | 399 ++++++++++++------------ apps/openmw/mwsound/openal_output.hpp | 10 +- apps/openmw/mwsound/sound_output.hpp | 10 +- apps/openmw/mwsound/soundmanagerimp.cpp | 331 +++++++++----------- 4 files changed, 373 insertions(+), 377 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 146776442a..a6258babee 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 "<<alcGetString(device, err)<<" ("<<err<<") @ "<< + func<<":"<<line <<std::endl; + return err; +} +#define getALCError(d) checkALCError((d), __FUNCTION__, __LINE__) + +ALenum checkALError(const char *func, int line) +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + std::cerr<< ">>>>>>>>> AL error "<<alGetString(err)<<" ("<<err<<") @ "<< + func<<":"<<line <<std::endl; + return err; +} +#define getALError() checkALError(__FUNCTION__, __LINE__) + // Helper to get an OpenAL extension function template<typename T, typename R> 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 ("<<getChannelConfigName(chans)<<", "<< + getSampleTypeName(type)<<")" <<std::endl; return AL_NONE; } @@ -307,9 +304,11 @@ private: friend class OpenAL_Output; public: - OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData=false); + OpenAL_SoundStream(ALuint src, DecoderPtr decoder); ~OpenAL_SoundStream(); + bool init(bool getLoudnessData=false); + bool isPlaying(); double getStreamDelay() const; double getStreamOffset() const; @@ -394,57 +393,60 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder, bool getLoudnessData) - : mSource(src), mCurrentBufIdx(0), mFrameSize(0), mSilence(0), mDecoder(decoder), mIsFinished(false) +OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) + : mSource(src), mBuffers{0}, mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0) + , mBufferSize(0), mFrameSize(0), mSilence(0), mDecoder(std::move(decoder)) + , mLoudnessAnalyzer(nullptr) { - alGenBuffers(sNumBuffers, mBuffers); - throwALerror(); - try - { - int srate; - ChannelConfig chans; - SampleType type; - - mDecoder->getInfo(&srate, &chans, &type); - mFormat = getALFormat(chans, type); - mSampleRate = srate; - - switch(type) - { - case SampleType_UInt8: mSilence = 0x80; break; - case SampleType_Int16: mSilence = 0x00; break; - case SampleType_Float32: mSilence = 0x00; break; - } - - mFrameSize = framesToBytes(1, chans, type); - mBufferSize = static_cast<ALuint>(sBufferLength*srate); - mBufferSize *= mFrameSize; - - if (getLoudnessData) - mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); - } - catch(std::exception&) - { - alDeleteBuffers(sNumBuffers, mBuffers); - alGetError(); - throw; - } - mIsFinished = false; } + OpenAL_SoundStream::~OpenAL_SoundStream() { - alDeleteBuffers(sNumBuffers, mBuffers); + if(mBuffers[0] && alIsBuffer(mBuffers[0])) + alDeleteBuffers(sNumBuffers, mBuffers); alGetError(); mDecoder->close(); } +bool OpenAL_SoundStream::init(bool getLoudnessData) +{ + alGenBuffers(sNumBuffers, mBuffers); + ALenum err = getALError(); + if(err != AL_NO_ERROR) + return false; + + ChannelConfig chans; + SampleType type; + + mDecoder->getInfo(&mSampleRate, &chans, &type); + mFormat = getALFormat(chans, type); + if(!mFormat) return false; + + switch(type) + { + case SampleType_UInt8: mSilence = 0x80; break; + case SampleType_Int16: mSilence = 0x00; break; + case SampleType_Float32: mSilence = 0x00; break; + } + + mFrameSize = framesToBytes(1, chans, type); + mBufferSize = static_cast<ALuint>(sBufferLength*mSampleRate); + mBufferSize *= mFrameSize; + + if (getLoudnessData) + mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); + + mIsFinished = false; + return true; +} + 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<std::string> 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" <<std::endl; else - fail("Failed to open \""+devname+"\""); + std::cerr<< "Failed to open \""<<devname<<"\"" <<std::endl; + return false; } else { @@ -615,42 +618,49 @@ void OpenAL_Output::init(const std::string &devname) mContext = alcCreateContext(mDevice, NULL); if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE) { + std::cerr<< "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice)) <<std::endl; if(mContext) alcDestroyContext(mContext); - mContext = 0; - fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); + mContext = nullptr; + alcCloseDevice(mDevice); + mDevice = nullptr; + return false; } ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); - alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); - throwALerror(); - - ALCint maxmono=0, maxstereo=0; + ALCuint maxtotal; + ALCint maxmono = 0, maxstereo = 0; alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &maxmono); alcGetIntegerv(mDevice, ALC_STEREO_SOURCES, 1, &maxstereo); - throwALCerror(mDevice); - - try + if(getALCError(mDevice) != ALC_NO_ERROR) + maxtotal = 256; + else { - ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256); + maxtotal = std::min<ALCuint>(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: "<<e.what()<<", trying to continue"<< std::endl; + ALuint src = 0; + alGenSources(1, &src); + if(getALError() != AL_NO_ERROR) + break; + mFreeSources.push_back(src); } if(mFreeSources.empty()) - fail("Could not allocate any sources"); + { + std::cerr<< "Could not allocate any sound sources" <<std::endl; + alcMakeContextCurrent(nullptr); + alcDestroyContext(mContext); + mContext = nullptr; + alcCloseDevice(mDevice); + mDevice = nullptr; + return false; + } + std::cout<< "Allocated "<<mFreeSources.size()<<" sound sources" <<std::endl; if(ALC.EXT_EFX) { @@ -689,7 +699,11 @@ void OpenAL_Output::init(const std::string &devname) LOAD_FUNC(alGetAuxiliaryEffectSlotf); LOAD_FUNC(alGetAuxiliaryEffectSlotfv); #undef LOAD_FUNC - throwALerror(); + if(getALError() != AL_NO_ERROR) + { + ALC.EXT_EFX = false; + goto skip_efx; + } alGenFilters(1, &mWaterFilter); if(alGetError() == AL_NO_ERROR) @@ -743,12 +757,15 @@ void OpenAL_Output::init(const std::string &devname) alListenerf(AL_METERS_PER_UNIT, 1.0f / UnitsPerMeter); } +skip_efx: + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); // 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; + return true; } void OpenAL_Output::deinit() @@ -786,11 +803,9 @@ void OpenAL_Output::deinit() std::vector<std::string> OpenAL_Output::enumerateHrtf() { - if(!mDevice) - fail("Device not initialized"); - std::vector<std::string> 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!" <<std::endl; + return false; + } source = mFreeSources.front(); + + 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; + + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); - - try { - initCommon2D(source, sound->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(); - - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } - 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!" <<std::endl; + return false; + } source = mFreeSources.front(); + + 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); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); - - try { - initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), - 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(); - - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } - 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!" <<std::endl; + return false; + } + ALuint source = mFreeSources.front(); if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<<decoder->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!" <<std::endl; + return false; + } + ALuint source = mFreeSources.front(); if(sound->getIsLooping()) std::cout <<"Warning: cannot loop stream \""<<decoder->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 777b9207f8..05f9c5090b 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<std::string> 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<std::string> 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 907a601b5d..01dc8b5b90 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<std::string> 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<std::string> 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 25af9add8b..51ce67096a 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<std::string> names = mOutput->enumerate(); - std::cout <<"Enumerated output devices:"<< std::endl; - for(size_t i = 0;i < names.size();i++) - std::cout <<" "<<names[i]<< std::endl; + std::vector<std::string> names = mOutput->enumerate(); + std::cout <<"Enumerated output devices:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout <<" "<<name<<"\n"; } + ); + std::cout.flush(); - std::string devname = Settings::Manager::getString("device", "Sound"); - try { - mOutput->init(devname); - } - catch(std::exception &e) { - if(devname.empty()) - throw; - std::cerr <<"Failed to open device \""<<devname<<"\": " << e.what() << std::endl; - mOutput->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[i]<< std::endl; - } - - if(hrtfstate == 0) - mOutput->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 \""<<devname<<"\", trying default" <<std::endl; + inited = mOutput->init(); } - catch(std::exception &e) { - std::cout <<"Sound init failed: "<<e.what()<< std::endl; + if(!inited) + { + std::cerr<< "Failed to initialize default audio device, sound disabled" <<std::endl; + return; } + + names = mOutput->enumerateHrtf(); + if(!names.empty()) + { + std::cout<< "Enumerated HRTF names:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout<< " "<<name<<"\n"; } + ); + std::cout.flush(); + } + + if(hrtfstate == 0) + mOutput->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<ESM::Sound>().find(soundId); + const ESM::Sound *sound = world->getStore().get<ESM::Sound>().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 "<<filename<< std::endl; mLastPlayedMusic = filename; - try { - stopMusic(); - DecoderPtr decoder = getDecoder(); - decoder->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: "<<e.what()<< std::endl; - } + MWBase::World *world = MWBase::Environment::get().getWorld(); + const osg::Vec3f pos = world->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: "<<e.what()<< std::endl; - } + mVFS->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: "<<e.what()<< std::endl; - if(track) - mUnusedStreams.push_back(track); - track = nullptr; + mUnusedStreams.push_back(track); + return nullptr; } + + mActiveTracks.insert( + std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track), track + ); return track; } @@ -573,30 +568,25 @@ namespace MWSound { if(!mOutput->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)); - } - catch(std::exception&) + 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)) { - //std::cout <<"Sound Error: "<<e.what()<< std::endl; - if(sound) - mUnusedSounds.push_back(sound); - sound = nullptr; + 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[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); return sound; } @@ -606,48 +596,44 @@ 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)); + if(!sfx) return nullptr; + + const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); + if((mode&Play_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 + stopSound3D(ptr, soundId); + + bool played; + Sound *sound = getSoundRef(); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { - // 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; - - // 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->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)); + 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: "<<e.what()<< std::endl; - if(sound) - mUnusedSounds.push_back(sound); - sound = nullptr; + sound->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)); - } - catch(std::exception &) + // 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)) { - //std::cout <<"Sound Error: "<<e.what()<< std::endl; - if(sound) - mUnusedSounds.push_back(sound); - sound = nullptr; + 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[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); return sound; } From 3757571d4697e4253193fd7019a3b189e5eec3b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 a6258babee..b3ba4a07fc 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -592,7 +592,7 @@ std::vector<std::string> 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 \""<<name<<"\"" << std::endl; } - mContext = alcCreateContext(mDevice, NULL); + ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); + ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"); + + std::vector<ALCint> 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 \""<<hrtfname<<"\", using default" <<std::endl; + else + { + attrs.push_back(ALC_HRTF_ID_SOFT); + attrs.push_back(index); + } + } + } + attrs.push_back(0); + + mContext = alcCreateContext(mDevice, attrs.data()); if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE) { std::cerr<< "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice)) <<std::endl; @@ -627,8 +667,22 @@ bool OpenAL_Output::init(const std::string &devname) return false; } - ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); - AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); + if(!ALC.SOFT_HRTF) + std::cout<< "HRTF status unavailable" <<std::endl; + else + { + ALCint hrtf_state; + alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); + if(!hrtf_state) + std::cout<< "HRTF disabled" <<std::endl; + else + { + const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT); + std::cout<< "Enabled HRTF "<<hrtf <<std::endl; + } + } + + AL.SOFT_source_spatialize = alIsExtensionPresent("AL_SOFT_source_spatialize"); ALCuint maxtotal; ALCint maxmono = 0, maxstereo = 0; @@ -805,7 +859,7 @@ std::vector<std::string> OpenAL_Output::enumerateHrtf() { std::vector<std::string> ret; - if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + if(!mDevice || !ALC.SOFT_HRTF) return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; @@ -823,9 +877,9 @@ std::vector<std::string> 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" <<std::endl; return; @@ -838,8 +892,12 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector<ALCint> 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" <<std::endl; + std::cout<< "HRTF disabled" <<std::endl; else { const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT); @@ -877,31 +935,6 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) } } -void OpenAL_Output::disableHrtf() -{ - if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) - { - std::cerr<< "HRTF extension not present" <<std::endl; - return; - } - - LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; - getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); - - std::vector<ALCint> 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" <<std::endl; - else - std::cout<< "Disabled HRTF" <<std::endl; -} - Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 05f9c5090b..8a7b7b3b88 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -24,10 +24,11 @@ namespace MWSound ALCcontext *mContext; struct { - int EXT_EFX : 1; + bool EXT_EFX : 1; + bool SOFT_HRTF : 1; } ALC; struct { - int SOFT_source_spatialize : 1; + bool SOFT_source_spatialize : 1; } AL; typedef std::deque<ALuint> IDDq; @@ -59,12 +60,11 @@ namespace MWSound public: virtual std::vector<std::string> 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<std::string> 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 01dc8b5b90..ad18e0d40a 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<std::string> 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<std::string> 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 51ce67096a..7310e457f5 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 \""<<devname<<"\", trying default" <<std::endl; - inited = mOutput->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 <chris.kcat@gmail.com> 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 7310e457f5..2e8ff85c8f 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<ESM::Region::SoundRef>::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 <chris.kcat@gmail.com> 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 b3ba4a07fc..00562de1af 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1,9 +1,10 @@ #include <algorithm> #include <stdexcept> #include <iostream> +#include <cstring> #include <vector> #include <memory> -#include <cstring> +#include <array> #include <stdint.h> @@ -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<FormatEntry,4> 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<FormatEntryExt,6> 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<FormatEntryExt,2> 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<FormatEntryExt,3> 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 <chris.kcat@gmail.com> 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 4439fe8f3f..f1c35df19d 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<Sound_Decoder> 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<int>(a); } + inline int operator&(Type a, Type b) { return static_cast<int>(a) & static_cast<int>(b); } + inline int operator&(int a, Type b) { return a & static_cast<int>(b); } + inline int operator|(Type a, Type b) { return static_cast<int>(a) | static_cast<int>(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 + protected: + using PlayMode = MWSound::PlayMode; + using Type = MWSound::Type; + public: - SoundManager() {} - virtual ~SoundManager() {} virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& 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<int>(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<int>(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 dc4eb844ac..b6a46cff84 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 07e6cc9db0..903ec49581 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 172c16c831..f9056b75df 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 4b7b3c3870..1526949a3b 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 d15e1a1a59..baa2470da2 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 51dc37e185..2f645279a8 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 e4d0abf7bb..8211c2f5f9 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 bedc02138b..4d199c299f 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 9c9b442c73..f54ab5c068 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 00562de1af..1a9baed771 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<ALuint> 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<OpenAL_SoundStream*>((*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<OpenAL_SoundStream*>(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<ALuint> 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<OpenAL_SoundStream*>((*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<OpenAL_SoundStream*>(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 1389835dba..7324b6747d 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<int>(b); } + inline int operator&(PlayMode a, PlayMode b) { return static_cast<int>(a) & static_cast<int>(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<MWSound::Type>(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 2e8ff85c8f..0b6d8ff34a 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<int>(a) | static_cast<int>(b); } + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map<std::string, std::string>& 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 e5889e36d2..d2dce3928e 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 468207e810..32a3c8f96d 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 64d601563b..5b15583bfb 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 c4b46961c3..2f0a2f8cf5 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 <chris.kcat@gmail.com> 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 1a9baed771..64aa1aff70 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<ALuint,6> 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<char> 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 <kyleacooley@gmail.com> 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 22c65b62c2..335bb496bd 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 <andrei.kortunov@yandex.ru> 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 d233fba6f8..19bf7f55ef 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<ESM::Skill::Length; ++i) + { + mSaveSkills[i].setBase(0); + mSaveSkills[i].setModifier(0); + } + + for (int i=0; i<ESM::Attribute::Length; ++i) + { + mSaveAttributes[i].setBase(0); + mSaveAttributes[i].setModifier(0); + } + + mMarkedPosition.pos[0] = 0; + mMarkedPosition.pos[1] = 0; + mMarkedPosition.pos[2] = 0; + mMarkedPosition.rot[0] = 0; + mMarkedPosition.rot[1] = 0; + mMarkedPosition.rot[2] = 0; } void Player::write (ESM::ESMWriter& writer, Loading::Listener& progress) const From d2b5f7dea5e9e7a9e1c34fd0c05aedb3aa5221ce Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> 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 e7cac15d06..d492dc542a 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 2f645279a8..bfe8812e6d 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 <chris.kcat@gmail.com> 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 64aa1aff70..85a7d13ba0 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -595,23 +595,23 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname deinit(); mDevice = alcOpenDevice(devname.c_str()); + if(!mDevice && !devname.empty()) + { + std::cerr<< "Failed to open \""<<devname<<"\", trying default" <<std::endl; + mDevice = alcOpenDevice(nullptr); + } if(!mDevice) { - if(devname.empty()) - std::cerr<< "Failed to open default audio device" <<std::endl; - else - std::cerr<< "Failed to open \""<<devname<<"\"" <<std::endl; + std::cerr<< "Failed to open default audio device" <<std::endl; return false; } - else - { - const ALCchar *name = NULL; - if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT")) - name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER); - if(alcGetError(mDevice) != AL_NO_ERROR || !name) - name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER); - std::cout << "Opened \""<<name<<"\"" << std::endl; - } + + const ALCchar *name = nullptr; + if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT")) + name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(mDevice) != AL_NO_ERROR || !name) + name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER); + std::cout<< "Opened \""<<name<<"\"" <<std::endl; ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"); @@ -643,7 +643,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname } if(index < 0) - std::cerr<< "Failed to find HRTF name \""<<hrtfname<<"\", using default" <<std::endl; + std::cerr<< "Failed to find HRTF \""<<hrtfname<<"\", using default" <<std::endl; else { attrs.push_back(ALC_HRTF_ID_SOFT); @@ -698,7 +698,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname { ALuint src = 0; alGenSources(1, &src); - if(getALError() != AL_NO_ERROR) + if(alGetError() != AL_NO_ERROR) break; mFreeSources.push_back(src); } @@ -824,8 +824,10 @@ void OpenAL_Output::deinit() { mStreamThread->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 0b6d8ff34a..03bff89b40 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..." <<std::endl; + mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); @@ -91,9 +89,6 @@ namespace MWSound 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; - std::vector<std::string> 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()) + if(!mOutput->init(devname, hrtfname, hrtfmode)) { - std::cerr<< "Failed to initialize device \""<<devname<<"\", trying default" <<std::endl; - inited = mOutput->init(std::string(), hrtfname, hrtfmode); - } - if(!inited) - { - std::cerr<< "Failed to initialize default audio device, sound disabled" <<std::endl; + std::cerr<< "Failed to initialize audio output, sound disabled" <<std::endl; return; } From 9dbb713b7c1b0f32bcf09a0ada96dde7786adbaf Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 85a7d13ba0..a6d3e4b12f 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..." <<std::endl; + mDevice = alcOpenDevice(devname.c_str()); if(!mDevice && !devname.empty()) { @@ -613,6 +615,12 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER); std::cout<< "Opened \""<<name<<"\"" <<std::endl; + ALCint major=0, minor=0; + alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor); + std::cout<< " ALC Version: "<<major<<"."<<minor<<"\n"<< + " ALC Extensions: "<<alcGetString(mDevice, ALC_EXTENSIONS) <<std::endl; + ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF"); @@ -665,6 +673,11 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname return false; } + std::cout<< " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<< + " Renderer: "<<alGetString(AL_RENDERER)<<"\n"<< + " Version: "<<alGetString(AL_VERSION)<<"\n"<< + " Extensions: "<<alGetString(AL_EXTENSIONS)<<std::endl; + if(!ALC.SOFT_HRTF) std::cout<< "HRTF status unavailable" <<std::endl; else diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 03bff89b40..2a65be737f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -56,8 +56,6 @@ namespace MWSound , mUnderwaterSound(nullptr) , mNearWaterSound(nullptr) { - std::cout<< "Initializing sound..." <<std::endl; - mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); @@ -82,13 +80,23 @@ namespace MWSound mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax); if(!useSound) + { + std::cout<< "Sound disabled." <<std::endl; return; + } 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::string devname = Settings::Manager::getString("device", "Sound"); + if(!mOutput->init(devname, hrtfname, hrtfmode)) + { + std::cerr<< "Failed to initialize audio output, sound disabled" <<std::endl; + return; + } + std::vector<std::string> 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" <<std::endl; - return; - } - names = mOutput->enumerateHrtf(); if(!names.empty()) { From 1e729e8da96b9ec08046c899aa25eccaf94beecf Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> Date: Sat, 16 Sep 2017 01:56:58 -0700 Subject: [PATCH 186/521] Avoid more explicit loops --- apps/openmw/mwsound/soundmanagerimp.cpp | 166 ++++++++++-------------- 1 file changed, 69 insertions(+), 97 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2a65be737f..f50b3f2fbe 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -99,20 +99,16 @@ namespace MWSound std::vector<std::string> names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout <<" "<<name<<"\n"; } - ); + for(const std::string &name : names) + std::cout <<" "<<name<<"\n"; std::cout.flush(); names = mOutput->enumerateHrtf(); if(!names.empty()) { std::cout<< "Enumerated HRTF names:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout<< " "<<name<<"\n"; } - ); + for(const std::string &name : names) + std::cout <<" "<<name<<"\n"; std::cout.flush(); } } @@ -120,12 +116,11 @@ namespace MWSound SoundManager::~SoundManager() { clear(); - SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->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) - { - 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 = nullptr; mNearWaterSound = nullptr; - stopMusic(); + + for(SaySoundMap::value_type &snd : mActiveSaySounds) + { + mOutput->finishStream(snd.second); + mUnusedStreams.push_back(snd.second); + } + mActiveSaySounds.clear(); + + for(Stream *sound : mActiveTracks) + { + mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); + } + mActiveTracks.clear(); } } From 4b448c74d24023c9f43c952335829c3c287061f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 a6d3e4b12f..77a14a398b 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<char> 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<OpenAL_SoundStream*>(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<OpenAL_SoundStream*>(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<ALuint> sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> 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(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); + OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); + sources.push_back(stream->mSource); } - ); - 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<OpenAL_SoundStream*>(stream->mHandle); - sources.push_back(strm->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<ALuint> sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> 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(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); + OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); + sources.push_back(stream->mSource); } - ); - 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<OpenAL_SoundStream*>(stream->mHandle); - sources.push_back(strm->mSource); - } - } - ); + } if(!sources.empty()) { alSourcePlayv(sources.size(), sources.data()); From 5c53ee42a10d8037420f442b65b2ac9e7045ad82 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 f50b3f2fbe..949b724f14 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<ESM::Sound>()) + 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 <chris.kcat@gmail.com> 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 | 30 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 ++--- apps/openmw/mwsound/sound_output.hpp | 5 ++--- apps/openmw/mwsound/soundmanagerimp.cpp | 9 ++++---- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 77a14a398b..3fb1c1c13b 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<Sound_Handle,size_t> 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); } } + ALint size = 0; + alGetBufferi(buffer, AL_SIZE, &size); 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); - getALError(); - - return (ALuint)size; + return size; } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 8a7b7b3b88..afc8697331 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -66,9 +66,8 @@ namespace MWSound virtual std::vector<std::string> 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<Sound_Handle,size_t> 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 ad18e0d40a..871562dc07 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -36,9 +36,8 @@ namespace MWSound virtual std::vector<std::string> 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<Sound_Handle,size_t> 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 949b724f14..ac87a2f06b 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 fedd424622..923b1af369 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 923b1af369..38915c95b4 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 <PlutonicOverkill@users.noreply.github.com> 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 7f901c470d..960ca74bcc 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 <andrei.kortunov@yandex.ru> 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 69fb2c4626..ecc011fc10 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,6 +3,7 @@ #include <MyGUI_ListBox.h> #include <MyGUI_ImageBox.h> #include <MyGUI_Gui.h> +#include <MyGUI_ScrollView.h> #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 0a84bb4e98..c8ec9da098 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<MyGUI::Widget*> mSpellItems; diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index 2375e52770..d93249c033 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -11,7 +11,9 @@ </Widget> <!-- Spell list --> - <Widget type="Widget" skin="" position="8 160 519 178" align="Left Top" name="SpellArea"/> + <Widget type="ScrollView" skin="MW_ScrollView" position="8 160 507 170" align="Left Top" name="SpellArea"> + <Property key="CanvasAlign" value="Left"/> + </Widget>> <!-- Dialog buttons --> <Widget type="HBox" position="0 338 511 24"> From 4bb349a5259d534c34ef2017d2f941c5be838045 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 bfd8dd562d..3a35c83eaf 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 <krizdjali+github@gmail.com> 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 baa2470da2..673304d309 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 <andrei.kortunov@yandex.ru> 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 6a2d3ff83a..6eb0c554e4 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 <krizdjali+github@gmail.com> 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 673304d309..0cb7619db9 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 bfe8812e6d..75ecf00a81 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 790ae20990..ee368ad242 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; i<numSteps; ++i) { position = MovementSolver::move(position, physicActor->getPtr(), 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 4d4a36f6c4..5c22de12ec 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 75ecf00a81..cd14ec5a4f 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 <kyleacooley@gmail.com> 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 1ee7f8a039..6a19df0d5b 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,7 +1,80 @@ #include "columnimp.hpp" +#include <stdexcept> + namespace CSMWorld { + /* LandTextureNicknameColumn */ + LandTextureNicknameColumn::LandTextureNicknameColumn() + : Column<LandTexture>(Columns::ColumnId_TextureNickname, ColumnBase::Display_String) + { + } + + QVariant LandTextureNicknameColumn::get(const Record<LandTexture>& record) const + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void LandTextureNicknameColumn::set(Record<LandTexture>& 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<LandTexture>(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + { + } + + QVariant LandTextureIndexColumn::get(const Record<LandTexture>& record) const + { + return record.get().mIndex; + } + + bool LandTextureIndexColumn::isEditable() const + { + return false; + } + + /* LandPluginIndexColumn */ + LandPluginIndexColumn::LandPluginIndexColumn() + : Column<Land>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandPluginIndexColumn::get(const Record<Land>& record) const + { + return record.get().mPlugin; + } + + bool LandPluginIndexColumn::isEditable() const + { + return false; + } + + /* LandTexturePluginIndexColumn */ + LandTexturePluginIndexColumn::LandTexturePluginIndexColumn() + : Column<LandTexture>(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandTexturePluginIndexColumn::get(const Record<LandTexture>& record) const + { + return record.get().mPluginIndex; + } + + bool LandTexturePluginIndexColumn::isEditable() const + { + return false; + } + /* LandMapLodColumn */ LandMapLodColumn::LandMapLodColumn() : Column<Land>(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) @@ -30,7 +103,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast<const signed char*>(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<const signed char*>(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<const float*>(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<const unsigned char*>(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<const uint16_t*>(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 8e5908bd37..025b064c6b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,14 +67,14 @@ namespace CSMWorld inline QVariant StringIdColumn<Land>::get(const Record<Land>& 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<LandTexture>::get(const Record<LandTexture>& 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<typename ESXRecordT> @@ -2435,78 +2435,38 @@ namespace CSMWorld } }; - template<typename ESXRecordT> - struct TextureHandleColumn : public Column<ESXRecordT> + struct LandTextureNicknameColumn : public Column<LandTexture> { - TextureHandleColumn() - : Column<ESXRecordT> (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) - {} + LandTextureNicknameColumn(); - QVariant get(const Record<ESXRecordT>& record) const override - { - return QString::fromUtf8(record.get().mId.c_str()); - } - - void set(Record<ESXRecordT>& 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<LandTexture>& record) const override; + void set(Record<LandTexture>& record, const QVariant& data) override; + bool isEditable() const override; }; - template<typename ESXRecordT> - struct TextureIndexColumn : public Column<ESXRecordT> + struct LandTextureIndexColumn : public Column<LandTexture> { - TextureIndexColumn() - : Column<ESXRecordT> (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) - {} + LandTextureIndexColumn(); - QVariant get(const Record<ESXRecordT>& record) const override - { - return record.get().mIndex; - } - - bool isEditable() const override - { - return false; - } + QVariant get(const Record<LandTexture>& record) const override; + bool isEditable() const override; }; - template<typename ESXRecordT> - struct PluginIndexColumn : public Column<ESXRecordT> + struct LandPluginIndexColumn : public Column<Land> { - PluginIndexColumn() - : Column<ESXRecordT> (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) - {} + LandPluginIndexColumn(); - QVariant get(const Record<ESXRecordT>& record) const override - { - return -1; - } - - bool isEditable() const override - { - return false; - } + QVariant get(const Record<Land>& record) const override; + bool isEditable() const override; }; - template<> - inline QVariant PluginIndexColumn<Land>::get (const Record<Land>& record) const + struct LandTexturePluginIndexColumn : public Column<LandTexture> { - return record.get().mPlugin; - } + LandTexturePluginIndexColumn(); - template<> - inline QVariant PluginIndexColumn<LandTexture>::get (const Record<LandTexture>& record) const - { - return record.get().mPluginIndex; - } + QVariant get(const Record<LandTexture>& record) const override; + bool isEditable() const override; + }; struct LandMapLodColumn : public Column<Land> { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 63ccb6017a..ec010ba364 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 432597105a..15018795c7 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 5bfcd68462..b654eb00d6 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 0ffe5fa21d..2216d5ca6c 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<Land>); mLand.addColumn (new RecordStateColumn<Land>); mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land)); - mLand.addColumn (new PluginIndexColumn<Land>); + 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<LandTexture>(true)); mLandTextures.addColumn (new RecordStateColumn<LandTexture>); mLandTextures.addColumn (new FixedRecordTypeColumn<LandTexture>(UniversalId::Type_LandTexture)); - mLandTextures.addColumn (new TextureHandleColumn<LandTexture>); - mLandTextures.addColumn (new PluginIndexColumn<LandTexture>); - mLandTextures.addColumn (new TextureIndexColumn<LandTexture>); + mLandTextures.addColumn (new LandTextureNicknameColumn); + mLandTextures.addColumn (new LandTexturePluginIndexColumn); + mLandTextures.addColumn (new LandTextureIndexColumn); mLandTextures.addColumn (new TextureColumn<LandTexture>); mPathgrids.addColumn (new StringIdColumn<Pathgrid>); diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index fdabfb2818..43d911e50d 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<CSMWorld::IdTable&>(*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<CSMWorld::IdTable&>(*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 083f27cef7..f3f72e88ad 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 <chris.kcat@gmail.com> 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 f1c35df19d..2b3cf1f0df 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 ac87a2f06b..a798d350c2 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<std::string> 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 d2dce3928e..e31a0e5752 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 <chris.kcat@gmail.com> Date: Mon, 18 Sep 2017 01:21:18 -0700 Subject: [PATCH 203/521] Don't spam about missing animations --- apps/openmw/mwmechanics/character.cpp | 85 +++++++++++++-------------- apps/openmw/mwrender/animation.cpp | 2 - 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cd14ec5a4f..06916f9892 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2025,59 +2025,54 @@ void CharacterController::unpersistAnimationState() bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - { - std::cerr<< "Animation "<<groupname<<" not found for " << mPtr.getCellRef().getRefId() << std::endl; return false; - } - else + + // 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)) { - // 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; - } - } - - count = std::max(count, 1); - - 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); - - 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) + if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) { mAnimQueue.resize(1); - mAnimQueue.push_back(entry); + return true; } } + + count = std::max(count, 1); + + 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); + + 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); + } return true; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df9b8545a8..a8e0caed5b 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 "<<groupname<<" for "<<mPtr.getCellRef().getRefId() <<std::endl; resetActiveGroups(); } From 917a3b5dff11a834bdae4a26778086958324c322 Mon Sep 17 00:00:00 2001 From: Chris Robinson <chris.kcat@gmail.com> 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 a8e0caed5b..90b69de8e5 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 <chris.kcat@gmail.com> 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 65524f76ed..b223353c29 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 46531f23ec..d8c4fd084d 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -32,9 +32,9 @@ namespace Terrain osg::ref_ptr<osg::Node> 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 <andrei.kortunov@yandex.ru> 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 84d43156e1..d9068b285b 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 baa2470da2..3669549446 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<MWWorld::Ptr> actors; + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); + getObjectsInRange(position, aiProcessingDistance, actors); + for(std::vector<MWWorld::Ptr>::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 6eb3a29556..e433434a54 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 5f3dd58af3..5d9ef726a3 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 adad219164..1bf3a8d227 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 76130be24c..c98e0fc5ad 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 <andrei.kortunov@yandex.ru> 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 ab43df0f18..bfe173b47a 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<MyGUI::Button*>::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 <andrei.kortunov@yandex.ru> 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 baa2470da2..eb2a97cbbb 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 <andrei.kortunov@yandex.ru> 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 | 94 +++++++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 68d95fb885..098029ce7d 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()) - { - std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); - std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + float result = 0; - return leftName.compare(rightName) < 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()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(leftName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + leftChargePercent = 101; + else + leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast<int>(left.mBase.getCellRef().getEnchantmentCharge() / static_cast<float>(ench->mData.mCharge) * 100); + } + else + std::cerr << "Warning: Can't find enchantment '" << leftName << "' on item " << left.mBase.getCellRef().getRefId() << std::endl; } - else - return compareType(left.mBase.getTypeName(), right.mBase.getTypeName()); + + if (!rightName.empty()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(rightName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + rightChargePercent = 101; + else + rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast<int>(right.mBase.getCellRef().getEnchantmentCharge() / static_cast<float>(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; + } + + // 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?= <tastyfish@sznam.cz> 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 0ed389bdf7..2329e7afa3 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 <andrei.kortunov@yandex.ru> 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 098029ce7d..45aa261df3 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<int>(left.mBase.getCellRef().getEnchantmentCharge() / static_cast<float>(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<int>(right.mBase.getCellRef().getEnchantmentCharge() / static_cast<float>(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 <miroslavr256@gmail.com> 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 fc5fae72ed..0e742ff548 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 5c65332beb..2473daf955 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -1,12 +1,12 @@ #include "converter.hpp" #include <stdexcept> +#include <algorithm> #include <osgDB/WriteFile> #include <components/esm/creaturestate.hpp> #include <components/esm/containerstate.hpp> -#include <components/esm/projectilestate.hpp> #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); + auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(), + [&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; }); + + 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);*/ - - std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl; - continue; + 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 a640d67565..621b85709e 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -22,6 +22,7 @@ #include <components/esm/globalscript.hpp> #include <components/esm/queststate.hpp> #include <components/esm/stolenitems.hpp> +#include <components/esm/projectilestate.hpp> #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 4c8222c561..73b15baaed 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<unsigned int, std::shared_ptr<Converter> > converters; converters[ESM::REC_GLOB] = std::shared_ptr<Converter>(new ConvertGlobal()); @@ -304,12 +305,12 @@ namespace ESSImport converters[recJOUR ] = std::shared_ptr<Converter>(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr<Converter>(new ConvertSCPT()); converters[ESM::REC_PROJ] = std::shared_ptr<Converter>(new ConvertPROJ()); + converters[recSPLM] = std::shared_ptr<Converter>(new ConvertSPLM()); // TODO: // - REGN (weather in certain regions?) // - VFXM // - SPLM (active spell effects) - // - PROJ (magic projectiles in air) std::set<unsigned int> unknownRecords; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 4896f5594d..86501b3cb4 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<std::string, ESM::Creature> mCreatures; std::map<std::string, ESM::NPC> mNpcs; + std::vector<SPLM::ActiveSpell> mActiveSpells; + Context() : mDay(0) , mMonth(0) diff --git a/apps/essimporter/importsplm.cpp b/apps/essimporter/importsplm.cpp new file mode 100644 index 0000000000..9fdba4ddb5 --- /dev/null +++ b/apps/essimporter/importsplm.cpp @@ -0,0 +1,43 @@ +#include "importsplm.h" + +#include <components/esm/esmreader.hpp> + +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 0000000000..8fd5c2bb52 --- /dev/null +++ b/apps/essimporter/importsplm.h @@ -0,0 +1,81 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H +#define OPENMW_ESSIMPORT_IMPORTSPLM_H + +#include <vector> +#include <components/esm/esmcommon.hpp> +#include <components/esm/util.hpp> + +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<ActiveEffect> mActiveEffects; + }; + + std::vector<ActiveSpell> mActiveSpells; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5e76d82eba..0385359396 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 f7ee15bf44..a808b82853 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 9991c583d5..2e368afcf9 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 5b15583bfb..6e716cb54e 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,6 +1,7 @@ #include "projectilemanager.hpp" #include <iomanip> +#include <iostream> #include <osg/PositionAttitudeTransform> @@ -41,13 +42,29 @@ namespace { - ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& sounds, float& speed, std::string& texture, const ESM::EffectList& effects) + ESM::EffectList getMagicBoltData(std::vector<std::string>& projectileIDs, std::vector<std::string>& 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<ESM::Spell>().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<ESM::Enchantment>().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<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin()); - iter!=effects.mList.end(); ++iter) + for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects->mList.begin()); + iter!=effects->mList.end(); ++iter) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find ( iter->mEffectID); @@ -82,14 +99,14 @@ namespace if (projectileEffects.mList.size() == 1) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().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<std::string>::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 c7025a3a09..1ef72a0481 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<MWBase::Sound*> mSounds; std::vector<std::string> mSoundIds; }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a9506385d4..40bc13c949 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<std::string>& World::getContentFiles() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a15dcaf3dd..774753b6ce 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 70ae4c5ee6..8ade9d5b2e 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 3471fbfc79..67ec89bb6d 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 43b0518fd1..906ca23529 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ <Widget type="Window" skin="MW_DialogNoTransp" layer="Windows" position="0 0 244 248" align="Center" name="_Main"> <!-- Edit box --> - <Widget type="Widget" skin="MW_Box" position="8 8 220 192" align="Stretch" name="Client"/> + <Widget type="Widget" skin="MW_Box" position="8 8 220 192" align="Stretch"/> <Widget type="EditBox" skin="MW_TextBoxEdit" position="10 10 218 190" name="TextEdit" align="Left Top Stretch"> <Property key="MultiLine" value="true"/> diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b020..1ed3995728 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ <Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 588 433" name="_Main"> <Property key="MinSize" value="380 230"/> - <Widget type="Widget" skin="MW_Box" position="8 8 381 381" align="Stretch" name="Client"/> + <Widget type="Widget" skin="MW_Box" position="8 8 381 381" align="Stretch"/> <Widget type="Widget" position="15 15 364 370" align="Left Top Stretch"> <Widget type="BookPage" skin="MW_BookPage" position="0 0 364 370" name="History" align="Left Top Stretch"> diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1d..a1c4f608b4 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ <!-- The interior of the box --> - <Child type="Widget" skin="BlackBG" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="BlackBG" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> <Resource type="ResourceSkin" name="HUD_Box_Transparent" size="40 40"> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> <Resource type="ResourceSkin" name="HUD_Box_NoTransp" size="40 40"> <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> @@ -36,11 +36,11 @@ <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG_NoTransp_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG_NoTransp_Owned" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> @@ -48,11 +48,11 @@ <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG_Owned" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> 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 0ce8ce951b..eeddc22dd4 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 8fe25a5dc0..366b0c4c6e 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ </Widget> <!-- Drowning bar --> - <Widget type="Widget" skin="MW_Dialog" position="0 36 230 58" align="Center Top" name="DrowningFrame"> + <Widget type="Window" skin="MW_Dialog" position="0 36 230 58" align="Center Top" name="DrowningFrame"> <Property key="Visible" value="false"/> - <Widget type="TextBox" skin="SandText" position="2 7 226 24" name="DrowningTitle" align="Center Top HStretch"> + <Widget type="TextBox" skin="SandText" position="0 3 222 24" name="DrowningTitle" align="Center Top HStretch"> <Property key="Caption" value="#{sBreath}"/> <Property key="TextAlign" value="Center"/> <Property key="TextShadow" value="true"/> <Property key="TextShadowColour" value="0 0 0"/> </Widget> - <Widget type="Widget" skin="MW_Box" position="15 33 200 10" align="Stretch" name="BoundingBox"/> - <Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="17 35 196 6" align="Center Top" name="Drowning"> + <Widget type="Widget" skin="MW_Box" position="11 29 200 10" align="Stretch" name="BoundingBox"/> + <Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="13 31 196 6" align="Center Top" name="Drowning"> <Property key="NeedMouse" value="false"/> </Widget> - <Widget type="Widget" skin="MW_Progress_Drowning_Small" position="19 37 192 2" align="Center Top" name="Flash"/> + <Widget type="Widget" skin="MW_Progress_Drowning_Small" position="15 33 192 2" align="Center Top" name="Flash"/> </Widget> <!-- Equipped weapon/selected spell name display for a few seconds after it changes --> diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8c..76aa05b868 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layout"> - <Widget type="Widget" skin="MW_Dialog" layer="LoadingScreen" position="0 0 300 48" align="Center" name="_Main"> + <Widget type="Window" skin="MW_Dialog" layer="LoadingScreen" position="0 0 300 48" align="Center" name="_Main"> - <Widget type="TextBox" skin="SandText" position="20 8 260 18" align="Stretch" name="LoadingText"> + <Widget type="TextBox" skin="SandText" position="16 4 260 18" align="Stretch" name="LoadingText"> <Property key="TextAlign" value="Center"/> <Property key="Caption" value="#{sInPrisonTitle}"/> </Widget> - <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" name="ProgressBar"> + <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="16 26 260 6" name="ProgressBar"> </Widget> </Widget> diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e3..69df200221 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ <!-- The entire screen --> <Widget type="Widget" layer="LoadingScreen" position="0 0 300 300" name="_Main" align="Stretch"> - <Widget type="Widget" skin="MW_Dialog" position="0 245 300 48" align="Bottom HCenter" name="LoadingBox"> + <Widget type="Window" skin="MW_Dialog" position="0 245 300 48" align="Bottom HCenter" name="LoadingBox"> - <Widget type="TextBox" skin="SandText" position="20 9 260 18" align="Stretch" name="LoadingText"> + <Widget type="TextBox" skin="SandText" position="16 5 260 18" align="Stretch" name="LoadingText"> <Property key="TextAlign" value="Center"/> </Widget> - <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" align="Top HCenter" name="ProgressBar"> + <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="16 26 260 6" align="Top HCenter" name="ProgressBar"> </Widget> </Widget> 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 7d81b6ab3d..ed9dabd2dc 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 43b0518fd1..906ca23529 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ <Widget type="Window" skin="MW_DialogNoTransp" layer="Windows" position="0 0 244 248" align="Center" name="_Main"> <!-- Edit box --> - <Widget type="Widget" skin="MW_Box" position="8 8 220 192" align="Stretch" name="Client"/> + <Widget type="Widget" skin="MW_Box" position="8 8 220 192" align="Stretch"/> <Widget type="EditBox" skin="MW_TextBoxEdit" position="10 10 218 190" name="TextEdit" align="Left Top Stretch"> <Property key="MultiLine" value="true"/> diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b020..1ed3995728 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ <Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 588 433" name="_Main"> <Property key="MinSize" value="380 230"/> - <Widget type="Widget" skin="MW_Box" position="8 8 381 381" align="Stretch" name="Client"/> + <Widget type="Widget" skin="MW_Box" position="8 8 381 381" align="Stretch"/> <Widget type="Widget" position="15 15 364 370" align="Left Top Stretch"> <Widget type="BookPage" skin="MW_BookPage" position="0 0 364 370" name="History" align="Left Top Stretch"> diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1d..a1c4f608b4 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ <!-- The interior of the box --> - <Child type="Widget" skin="BlackBG" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="BlackBG" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> <Resource type="ResourceSkin" name="HUD_Box_Transparent" size="40 40"> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> <Resource type="ResourceSkin" name="HUD_Box_NoTransp" size="40 40"> <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> @@ -36,11 +36,11 @@ <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG_NoTransp_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG_NoTransp_Owned" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> @@ -48,11 +48,11 @@ <!-- The interior of the box --> - <Child type="Widget" skin="DialogBG_Owned" offset="0 0 40 40" align="Stretch" name="Client"/> + <Child type="Widget" skin="DialogBG_Owned" offset="0 0 40 40" align="Stretch"/> <!-- Borders --> - <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch" name="Client"/> + <Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="Left Stretch"/> </Resource> 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 0ce8ce951b..eeddc22dd4 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 8fe25a5dc0..366b0c4c6e 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ </Widget> <!-- Drowning bar --> - <Widget type="Widget" skin="MW_Dialog" position="0 36 230 58" align="Center Top" name="DrowningFrame"> + <Widget type="Window" skin="MW_Dialog" position="0 36 230 58" align="Center Top" name="DrowningFrame"> <Property key="Visible" value="false"/> - <Widget type="TextBox" skin="SandText" position="2 7 226 24" name="DrowningTitle" align="Center Top HStretch"> + <Widget type="TextBox" skin="SandText" position="0 3 222 24" name="DrowningTitle" align="Center Top HStretch"> <Property key="Caption" value="#{sBreath}"/> <Property key="TextAlign" value="Center"/> <Property key="TextShadow" value="true"/> <Property key="TextShadowColour" value="0 0 0"/> </Widget> - <Widget type="Widget" skin="MW_Box" position="15 33 200 10" align="Stretch" name="BoundingBox"/> - <Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="17 35 196 6" align="Center Top" name="Drowning"> + <Widget type="Widget" skin="MW_Box" position="11 29 200 10" align="Stretch" name="BoundingBox"/> + <Widget type="ProgressBar" skin="MW_Progress_Drowning_Full" position="13 31 196 6" align="Center Top" name="Drowning"> <Property key="NeedMouse" value="false"/> </Widget> - <Widget type="Widget" skin="MW_Progress_Drowning_Small" position="19 37 192 2" align="Center Top" name="Flash"/> + <Widget type="Widget" skin="MW_Progress_Drowning_Small" position="15 33 192 2" align="Center Top" name="Flash"/> </Widget> <!-- Equipped weapon/selected spell name display for a few seconds after it changes --> diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8c..76aa05b868 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layout"> - <Widget type="Widget" skin="MW_Dialog" layer="LoadingScreen" position="0 0 300 48" align="Center" name="_Main"> + <Widget type="Window" skin="MW_Dialog" layer="LoadingScreen" position="0 0 300 48" align="Center" name="_Main"> - <Widget type="TextBox" skin="SandText" position="20 8 260 18" align="Stretch" name="LoadingText"> + <Widget type="TextBox" skin="SandText" position="16 4 260 18" align="Stretch" name="LoadingText"> <Property key="TextAlign" value="Center"/> <Property key="Caption" value="#{sInPrisonTitle}"/> </Widget> - <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" name="ProgressBar"> + <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="16 26 260 6" name="ProgressBar"> </Widget> </Widget> diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e3..69df200221 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ <!-- The entire screen --> <Widget type="Widget" layer="LoadingScreen" position="0 0 300 300" name="_Main" align="Stretch"> - <Widget type="Widget" skin="MW_Dialog" position="0 245 300 48" align="Bottom HCenter" name="LoadingBox"> + <Widget type="Window" skin="MW_Dialog" position="0 245 300 48" align="Bottom HCenter" name="LoadingBox"> - <Widget type="TextBox" skin="SandText" position="20 9 260 18" align="Stretch" name="LoadingText"> + <Widget type="TextBox" skin="SandText" position="16 5 260 18" align="Stretch" name="LoadingText"> <Property key="TextAlign" value="Center"/> </Widget> - <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" align="Top HCenter" name="ProgressBar"> + <Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="16 26 260 6" align="Top HCenter" name="ProgressBar"> </Widget> </Widget> 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 7d81b6ab3d..ed9dabd2dc 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: <crussell187@DESKTOP-5S3VJRL.localdomain> 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 | 172 ++++++++++++++++++--- 3 files changed, 152 insertions(+), 154 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 4f76139d9e..b239ec6a17 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 d0fc9bab03..08a7466fa8 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<char> 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<unsigned short> &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); -} -void NIFStream::getFloats(std::vector<float> &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); -} -void NIFStream::getVector2s(std::vector<osg::Vec2f> &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); -} -void NIFStream::getVector3s(std::vector<osg::Vec3f> &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); -} -void NIFStream::getVector4s(std::vector<osg::Vec4f> &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); -} -void NIFStream::getQuaternions(std::vector<osg::Quat> &quat, size_t size) -{ - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); -} } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 860c62e641..d33771f458 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 <xmmintrin.h> #include <cassert> #include <stdint.h> #include <stdexcept> @@ -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>(*((uint16_t*)buffer)); + } + uint32_t read_le32() { + alignas(4) uint8_t buffer[4]; + inp->read((char*)buffer, 4); + return static_cast<uint32_t>(*((uint32_t*)buffer)); + } + uint64_t read_le64() { + alignas(8) uint8_t buffer[8]; + inp->read((char*)buffer, 8); + return static_cast<uint64_t>(*((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); - ///Read in a string of the length specified in the file - std::string getString(); - ///This is special since the version string doesn't start with a number, and ends with "\n" - std::string getVersionString(); + std::string getString(size_t length) { + std::vector<char> str(length + 1, 0); - void getUShorts(std::vector<unsigned short> &vec, size_t size); - void getFloats(std::vector<float> &vec, size_t size); - void getVector2s(std::vector<osg::Vec2f> &vec, size_t size); - void getVector3s(std::vector<osg::Vec3f> &vec, size_t size); - void getVector4s(std::vector<osg::Vec4f> &vec, size_t size); - void getQuaternions(std::vector<osg::Quat> &quat, size_t size); + inp->read(&str[0], length); + + return &str[0]; + } + ///Read in a string of the length specified in the file + 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() { + std::string result; + std::getline(*inp, result); + return result; + } + + void getUShorts(std::vector<unsigned short> &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getUShort(); + } + void getFloats(std::vector<float> &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); + } + void getVector2s(std::vector<osg::Vec2f> &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector<osg::Vec3f> &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector<osg::Vec4f> &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } + void getQuaternions(std::vector<osg::Quat> &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 <andrei.kortunov@yandex.ru> 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 bfe8812e6d..861135dfb9 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?= <tastyfish@sznam.cz> 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 2329e7afa3..68c07c1ab6 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 c04233fcf0..b5d7d1a6af 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?= <tastyfish@sznam.cz> 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 b5d7d1a6af..6e4edfb84d 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?= <tastyfish@sznam.cz> 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 6e4edfb84d..867a24a701 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: <crussell187@DESKTOP-5S3VJRL.localdomain> 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 d33771f458..35c042e7d4 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 <xmmintrin.h> + #include <cassert> #include <stdint.h> #include <stdexcept> @@ -21,50 +21,38 @@ namespace Nif class NIFFile; +template <uint32_t numInstances, typename T> 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<typename type> 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>(*((uint16_t*)buffer)); - } - uint32_t read_le32() { - alignas(4) uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return static_cast<uint32_t>(*((uint32_t*)buffer)); - } - uint64_t read_le64() { - alignas(8) uint8_t buffer[8]; - inp->read((char*)buffer, 8); - return static_cast<uint64_t>(*((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<char>(inp); + } + short getShort() + { + return readLittleEndianType<short>(inp); + } + unsigned short getUShort() + { + return readLittleEndianType<unsigned short>(inp); + } + int getInt() + { + return readLittleEndianType<int>(inp); + } + unsigned int getUInt() + { + return readLittleEndianType<unsigned int>(inp); + } + float getFloat() + { + return readLittleEndianType<float>(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<uint32_t>(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: <crussell187@DESKTOP-5S3VJRL.localdomain> 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 35c042e7d4..4d7e39ecb8 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -41,6 +41,25 @@ template <uint32_t numInstances, typename T> inline void readLittleEndianBufferO #endif } +template <typename T> 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<typename type> type inline readLittleEndianType(Files::IStreamPtr &pIStream) { type val; @@ -146,28 +165,23 @@ public: void getUShorts(std::vector<unsigned short> &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); + readLittleEndianDynamicBufferOfType<unsigned short>(inp, &vec.front(), size); } void getFloats(std::vector<float> &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + readLittleEndianDynamicBufferOfType<float>(inp, &vec.front(), size); } void getVector2s(std::vector<osg::Vec2f> &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + readLittleEndianDynamicBufferOfType<osg::Vec2f>(inp, &vec.front(), size); } void getVector3s(std::vector<osg::Vec3f> &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + readLittleEndianDynamicBufferOfType<osg::Vec3f>(inp, &vec.front(), size); } void getVector4s(std::vector<osg::Vec4f> &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); + readLittleEndianDynamicBufferOfType<osg::Vec4f>(inp, &vec.front(), size); } void getQuaternions(std::vector<osg::Quat> &quat, size_t size) { quat.resize(size); From 4580024d76cbff2b3de7313f3ae13793f6e16637 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 c9be213222..0ba4839e71 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; i<mModel->getItemCount(); ++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; - if (!onTakeItem(item, item.mCount)) - break; + invStore.unequipItem(item.mBase, mPtr); + } + } - mModel->moveItem(item, item.mCount, playerModel); + mModel->update(); + + for (size_t i=0; i<mModel->getItemCount(); ++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 2fe540f22d..222243ec1d 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -1,5 +1,10 @@ #include "inventoryitemmodel.hpp" +#include <sstream> + +#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<int>(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<int>(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 dfc066bcd7..8457b33cbb 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 eef10b905d..cd04a425ba 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 f27ff1db96..dbb82cbda5 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 a6394757f2..b599b35839 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 90f7f77885..851abf4089 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?= <tastyfish@sznam.cz> 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 68c07c1ab6..9679533be9 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 867a24a701..bb56e95c6c 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 <andrei.kortunov@yandex.ru> 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 df62ca490d..681ca7f078 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<float, std::string>::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 9bcad09949..cc057e50de 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 <andrei.kortunov@yandex.ru> 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 681ca7f078..02da5ea56b 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 cc057e50de..3944c02784 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 <andrei.kortunov@yandex.ru> 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 02da5ea56b..adcd0ad685 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 3944c02784..b6dc967764 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 <andrei.kortunov@yandex.ru> 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 adcd0ad685..0e53f77df2 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<float>(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 b6dc967764..af90c18b80 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?= <tastyfish@sznam.cz> 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 bb56e95c6c..88ca33335e 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?= <tastyfish@sznam.cz> 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 88ca33335e..db319ac709 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?= <tastyfish@sznam.cz> 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 db319ac709..1e3a1e17bc 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: <crussell187@DESKTOP-5S3VJRL.localdomain> 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 4d7e39ecb8..290800042f 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,6 +14,8 @@ #include <osg/Vec4f> #include <osg/Quat> +#include <iostream> + #include "niftypes.hpp" namespace Nif @@ -21,49 +23,62 @@ namespace Nif class NIFFile; -template <uint32_t numInstances, typename T> inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +/* + readLittleEndianBufferOfType: This template should only be used with non POD data types +*/ +template <uint32_t numInstances, typename T, typename IntegerT> 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 <typename T> inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +/* + readLittleEndianDynamicBufferOfType: This template should only be used with non POD data types +*/ +template <typename T, typename IntegerT> 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<typename type> type inline readLittleEndianType(Files::IStreamPtr &pIStream) +template<typename type, typename IntegerT> 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<char>(inp); + return readLittleEndianType<char,char>(inp); } short getShort() { - return readLittleEndianType<short>(inp); + return readLittleEndianType<short,short>(inp); } unsigned short getUShort() { - return readLittleEndianType<unsigned short>(inp); + return readLittleEndianType<unsigned short,unsigned short>(inp); } int getInt() { - return readLittleEndianType<int>(inp); + return readLittleEndianType<int,int>(inp); } unsigned int getUInt() { - return readLittleEndianType<unsigned int>(inp); + return readLittleEndianType<unsigned int,unsigned int>(inp); } float getFloat() { - return readLittleEndianType<float>(inp); + return readLittleEndianType<float,uint32_t>(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<uint32_t>(inp); + size_t size = readLittleEndianType<uint32_t,uint32_t>(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<unsigned short> &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType<unsigned short>(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType<unsigned short,unsigned short>(inp, &vec.front(), size); } void getFloats(std::vector<float> &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType<float>(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, &vec.front(), size); } void getVector2s(std::vector<osg::Vec2f> &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType<osg::Vec2f>(inp, &vec.front(), size); + /* The packed storage of each Vec2f is 2 floats exactly */ + readLittleEndianDynamicBufferOfType<float,uint32_t>(inp,(float*) &vec.front(), size*2); } void getVector3s(std::vector<osg::Vec3f> &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType<osg::Vec3f>(inp, &vec.front(), size); + /* The packed storage of each Vec3f is 3 floats exactly */ + readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*3); } void getVector4s(std::vector<osg::Vec4f> &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType<osg::Vec4f>(inp, &vec.front(), size); + /* The packed storage of each Vec4f is 4 floats exactly */ + readLittleEndianDynamicBufferOfType<float,uint32_t>(inp, (float*) &vec.front(), size*4); } void getQuaternions(std::vector<osg::Quat> &quat, size_t size) { quat.resize(size); From 4921e7f5c1e2be8c4820bf8228ce83851ceccb16 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 6a19df0d5b..18da81b53c 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,6 +1,7 @@ #include "columnimp.hpp" #include <stdexcept> +#include <QVector> 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<const char*>(&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<Land>& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast<const signed char*>(array.data()); + DataType values = data.value<DataType>(); - 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<const char*>(&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<Land>& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast<const signed char*>(array.data()); + DataType values = data.value<DataType>(); - 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<Land>& 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<const char*>(&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<Land>& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const float* rawData = reinterpret_cast<const float*>(array.data()); + DataType values = data.value<DataType>(); - 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<const char*>(&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<Land>& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const unsigned char* rawData = reinterpret_cast<const unsigned char*>(array.data()); + DataType values = data.value<DataType>(); - 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<Land>& 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<const char*>(&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<Land>& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const uint16_t* rawData = reinterpret_cast<const uint16_t*>(array.data()); + DataType values = data.value<DataType>(); - 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 025b064c6b..d653ddecee 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 <cassert> +#include <cstdint> #include <sstream> #include <stdexcept> #include <QColor> +#include <QVector> #include <components/esm/loadbody.hpp> #include <components/esm/loadskil.hpp> @@ -2470,6 +2472,8 @@ namespace CSMWorld struct LandMapLodColumn : public Column<Land> { + using DataType = QVector<signed char>; + LandMapLodColumn(); QVariant get(const Record<Land>& record) const override; @@ -2479,6 +2483,8 @@ namespace CSMWorld struct LandNormalsColumn : public Column<Land> { + using DataType = QVector<signed char>; + LandNormalsColumn(); QVariant get(const Record<Land>& record) const override; @@ -2488,6 +2494,8 @@ namespace CSMWorld struct LandHeightsColumn : public Column<Land> { + using DataType = QVector<float>; + LandHeightsColumn(); QVariant get(const Record<Land>& record) const override; @@ -2497,6 +2505,8 @@ namespace CSMWorld struct LandColoursColumn : public Column<Land> { + using DataType = QVector<unsigned char>; + LandColoursColumn(); QVariant get(const Record<Land>& record) const override; @@ -2506,6 +2516,8 @@ namespace CSMWorld struct LandTexturesColumn : public Column<Land> { + using DataType = QVector<uint16_t>; + LandTexturesColumn(); QVariant get(const Record<Land>& record) const override; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b654eb00d6..79900c6c4c 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<uint16_t*>(mOld.data()); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value<DataType>(); // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(mOld.data(), mOld.size()); - uint16_t* newTextureData = reinterpret_cast<uint16_t*>(newTextureByteArray.data()); + DataType copy(mOld); // Perform touch/copy/etc... onRedo(); // Find all indices used std::unordered_set<int> 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<std::string> 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 aab0c54108..0f9d3591c3 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,12 +3,14 @@ #include "record.hpp" +#include <cstdint> #include <string> #include <map> #include <memory> #include <vector> #include <QVariant> +#include <QVector> #include <QUndoCommand> #include <QModelIndex> @@ -55,6 +57,8 @@ namespace CSMWorld protected: + using DataType = QVector<uint16_t>; + 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<std::string> mCreatedTextures; }; From 054e6a780e2c8fa4bbf1863751020ab036e5ad96 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 b41eea8f87..2c066ff6ce 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include <cstdint> #include <limits> +#include <map> #include <stdexcept> #include <components/esm/cellid.hpp> @@ -340,6 +341,15 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import { ImportResults results; + // Map existing textures to ids + std::map<std::string, std::string> reverseLookupMap; + for (int i = 0; i < idCollection()->getSize(); ++i) + { + auto& record = static_cast<const Record<LandTexture>&>(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<const Record<LandTexture>&>(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<const Record<LandTexture>&>(idCollection()->getRecord(oldRow)).get(); - const LandTexture& newLtex = dynamic_cast<const Record<LandTexture>&>(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<uint16_t>::max() - 1; - size_t Prime = (1 << 13) - 1; // A mersenne prime - - index = (index + Prime) % MaxIndex; + const size_t MaxIndex = std::numeric_limits<uint16_t>::max() - 1; + index = (index + 1) % MaxIndex; } while (index != startIndex); } From 3981f79d38af642f423b4adb5666b98a596a24f9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 2c066ff6ce..54d65ac3fb 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 <kyleacooley@gmail.com> 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 d653ddecee..e36e386c9e 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 0f9d3591c3..be86dd5080 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,17 +3,16 @@ #include "record.hpp" -#include <cstdint> #include <string> #include <map> #include <memory> #include <vector> #include <QVariant> -#include <QVector> #include <QUndoCommand> #include <QModelIndex> +#include "columnimp.hpp" #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -57,7 +56,7 @@ namespace CSMWorld protected: - using DataType = QVector<uint16_t>; + 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 <andrei.kortunov@yandex.ru> 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 0e53f77df2..6e1e075fb2 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: <crussell187@DESKTOP-5S3VJRL.localdomain> 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 290800042f..d00069be7f 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,8 +14,6 @@ #include <osg/Vec4f> #include <osg/Quat> -#include <iostream> - #include "niftypes.hpp" namespace Nif From b5f5268ff347a6730cac4526829c12ef3a2c44ba Mon Sep 17 00:00:00 2001 From: MiroslavR <miroslavr256@gmail.com> 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 6e716cb54e..ede8c34c45 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<ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end();) + { + if (isCleanable(*it)) + { + cleanupProjectile(*it); + it = mProjectiles.erase(it); + } + else + ++it; + } + + for (std::vector<MagicBoltState>::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<MagicBoltState>::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<ProjectileState>::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it) { - mParent->removeChild(it->mNode); + cleanupProjectile(*it); } mProjectiles.clear(); for (std::vector<MagicBoltState>::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 1ef72a0481..0dfbf60806 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<MagicBoltState> mMagicBolts; std::vector<ProjectileState> 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 <andrei.kortunov@yandex.ru> 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 b44b187adf..7f412b4d27 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 <andrei.kortunov@yandex.ru> 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 6e1e075fb2..ec65255bc1 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 <andrei.kortunov@yandex.ru> 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 40bc13c949..2a25d5bbcd 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 ab43df0f18..f9c445d368 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<std::string>::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) + for(std::vector<std::string>::const_iterator it = buttons.begin(); it != buttons.end(); ++it) { MyGUI::Button* button = mButtonsWidget->createWidget<MyGUI::Button>( MyGUI::WidgetStyle::Child, @@ -289,8 +288,7 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - std::vector<MyGUI::Button*>::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector<MyGUI::Button*>::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<MyGUI::Button*>::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector<MyGUI::Button*>::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<MyGUI::Button*>::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + std::vector<std::string> keywords { "sOk", "sYes" }; + for(std::vector<MyGUI::Button*>::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 b4121fed3b..38e6590b7a 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 e4fa8fc2b4..cc41b3831b 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 a76de00d1c..634c4884fc 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -85,14 +85,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> 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 00ae2fa4ab..43952afdb5 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 4560ab2700..37c3ce0d3c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -7,6 +7,8 @@ #include <map> #include <set> +#include <MyGUI_KeyCode.h> + #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 0000000000..840a12f1e0 --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -0,0 +1,140 @@ +#include "keyboardnavigation.hpp" + +#include <MyGUI_InputManager.h> +#include <MyGUI_WidgetManager.h> +#include <MyGUI_Button.h> + +#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<MyGUI::Widget*>& 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<int>(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<MyGUI::Button>(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 0000000000..86cc67962e --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWGUI_KEYBOARDNAVIGATION_H +#define OPENMW_MWGUI_KEYBOARDNAVIGATION_H + +#include <MyGUI_KeyCode.h> + +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 1526949a3b..5d7a547350 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<ResourceImageSetPointerFix>("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 4f06afb7d9..3e17046df0 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<KeyboardNavigation> 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 cc41b3831b..33f1edb6cf 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 5aee8de7ab..ac9bf042da 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -71,6 +71,7 @@ <Resource type="ResourceSkin" name="MW_Button" size="136 24" version="3.2.1"> <Property key="FontName" value="Default"/> <Property key="TextAlign" value="Center"/> + <Property key="NeedKey" value="true"/> <Child type="Widget" skin="BTN_Left" offset="0 4 4 16" align="VStretch Left"/> <Child type="Widget" skin="BTN_Right" offset="132 4 4 16" align="VStretch Right"/> 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 8e3f8ed690..ab0739c2cb 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(); + } - ImageBox::onMouseButtonReleased(_left, _top, _id); + Base::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 a539f15c97..509b1c8c28 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 fa5bfbe2f6..6da1f78069 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<ESM::Dialogue> &dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); @@ -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 33f8dbe3e8..f3a06f2451 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,6 +3,9 @@ #include <MyGUI_Button.h> #include <MyGUI_EditBox.h> +#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 2e80301d2d..9f59cd4438 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 5b5ae5b684..9f0b2245a1 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 5a435b9cf9..265b08fd6d 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<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it) + std::vector<std::string> allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; + for (std::vector<std::string>::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 39e77cb93c..c5eb573a7c 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -10,6 +10,7 @@ <Property key="Static" value="true"/> <Property key="WordWrap" value="true"/> <Property key="MultiLine" value="true"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="VBox" position="0 89 352 24" align="Center Bottom"> diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index 50bc178ed7..410426656f 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -9,6 +9,7 @@ <Property key="WordWrap" value="true"/> <Property key="MultiLine" value="1"/> <Property key="VisibleVScroll" value="1"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="Widget" skin="" position="0 0 500 400" align="Stretch" name="buttons"> </Widget> diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index f182184309..a7b7703de7 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -46,6 +46,7 @@ <Property key="Static" value="true"/> <Property key="MultiLine" value="true"/> <Property key="WordWrap" value="true"/> + <Property key="NeedKey" value="false"/> </Widget> diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 6d5dfb89b6..f9f24581f0 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -48,6 +48,10 @@ <Property key="TextAlign" value="Center"/> </Widget> + <Widget type="AutoSizedButton" skin="MW_Button" position="0 60 60 24" name="MaxSaleButton" align="Left Top"> + <Property key="Caption" value="#{sMaxSale}"/> + </Widget> + <Widget type="HBox" position="0 60 566 24" align="Right Bottom"> <Widget type="Widget"> <UserString key="HStretch" value="true"/> @@ -60,9 +64,6 @@ </Widget> </Widget> - <Widget type="AutoSizedButton" skin="MW_Button" position="0 60 60 24" name="MaxSaleButton" align="Left Top"> - <Property key="Caption" value="#{sMaxSale}"/> - </Widget> </Widget> </Widget> 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 840a12f1e0..ba09ce3699 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 854568f9bd..103cdcf14d 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -18,6 +18,7 @@ <!-- Command line --> <Widget type="EditBox" skin="MW_ConsoleCommand" position="0 338 384 28" align="HStretch Bottom" name="edit_Command"> <Property key="InvertSelected" value="false"/> + <UserString key="AcceptTab" value="true"/> </Widget> </Widget> 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 7379f3613d..c68bad02a7 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 e1f48d4a30..8b7bcaaca3 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 ecc011fc10..b4a6b7d2f0 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 c8ec9da098..c13d49838f 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 e1f5a165e7..2278b5141c 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 8206d6b037..2b205d12f9 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<int> 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 aeff7dc39a..62690a0f18 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 98e46a5596..1232036ca2 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 c9be213222..4f9201f060 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<PickpocketItemModel*>(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 520bce9d9d..65cfa35c7e 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 9f59cd4438..d9954a7928 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 9f0b2245a1..682baef3ce 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 c7d2ef7de6..25568da071 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 cb7c6c0d01..7c49ae54a7 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 6eb0c554e4..dcfb075db8 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 7614645402..fb5be34939 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 e96cc8b706..73b196cf8c 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 da8e932795..a068d71f3c 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 d49f7536df..36810665e0 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 ed9dabd2dc..7bc66fab47 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 312447a248..eae1cec7e2 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 9e27c0154e..9c706851fa 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<int>(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 8dcdfee121..5006b08a4b 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 f9c445d368..6b5ba506b1 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 e912193bf3..19dd6fa035 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 64db9043e0..d07cdef3d1 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 047f652639..374a5d3d89 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 b762745cd0..911bce577d 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 390a1f83c4..00af45695a 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 cc3db14df0..d963e9d662 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 4d6441450b..f917cef0f4 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 c50ba861a9..44c380b514 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 bf18e7355e..61a7a2ac0a 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 f21f2fa9d9..34dd5a7d4f 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 84d4ca959b..7a4c3a22e7 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 be0e47caba..2a49cf48a3 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 f46199c80f..4e8547d33c 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 2ac06dcaa8..447331574c 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 354253fa4f..6a36554d8b 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 6cdf74d103..d12115c889 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 5ce3fd1fe6..9261912b45 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 dcce10f9da..f8fead9ea6 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 1fe3cb68df..487953e002 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<MyGUI::Window>()); } + virtual void onOpen() { onWindowResize(mMainWidget->castType<MyGUI::Window>()); } 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 958b52dc08..169c9e742e 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 57dd34dd62..ccfa19c876 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 82218fef12..d2e7719187 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 7c45820626..95a35be7fe 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 ba58a9c690..476d19bd66 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 13df1f8aec..829659d16c 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 99b74529ef..1ba4c7ed68 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 43fb8901e7..400dc0ce49 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -22,9 +22,9 @@ namespace MWGui typedef MyGUI::delegates::CMultiDelegate1<WindowBase*> 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 83595fafd0..d49f57dded 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -3,7 +3,7 @@ <MyGUI type="Layout"> <Widget type="VBox" skin="MW_Dialog" layer="Windows" position="0 0 289 256" align="Center" name="_Main"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <!-- Class image --> diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index d620aadab4..200d345e33 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -2,7 +2,7 @@ <MyGUI type="Layout"> <Widget type="VBox" skin="MW_Dialog" layer="Windows" position="0 0 330 385" align="Center" name="_Main"> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="AutoSizedTextBox" skin="SandText" name="Label"> diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 340711bb1e..abc429594d 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -2,7 +2,7 @@ <MyGUI type="Layout"> <Widget type="VBox" skin="MW_Dialog" layer="Windows" position="0 0 330 385" align="Center" name="_Main"> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="AutoSizedTextBox" skin="SandText" name="Label"> diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index a7b7703de7..236eaaa61d 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -2,7 +2,7 @@ <MyGUI type="Layout"> <Widget type="VBox" skin="MW_DialogNoTransp" layer="Windows" position="0 0 600 400" align="Center" name="_Main"> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="HBox" skin=""> diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index a7eeabfa5d..c038066f13 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -32,7 +32,7 @@ <!-- Faction tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="FactionToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="AutoSizedEditBox" skin="SandText" position="8 8 436 0" align="Left Top" name="FactionText"> <Property key="MultiLine" value="true"/> @@ -44,7 +44,7 @@ <!-- Race tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 56" align="Stretch" name="RaceToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 284 18" align="Left Top" name="CenteredCaption"> @@ -61,7 +61,7 @@ <!-- Specialization tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 56" align="Stretch" name="SpecializationToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 140 18" align="Left Top" name="Caption"> <Property key="TextAlign" value="Center"/> @@ -77,7 +77,7 @@ <!-- Class tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 78" align="Stretch" name="ClassToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 284 18" align="Left Top" name="ClassName"> @@ -137,7 +137,7 @@ <!-- Attribute tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="AttributeToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Widget type="HBox"> @@ -159,7 +159,7 @@ <!-- Skill tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 98" align="Stretch" name="SkillToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="HBox"> <UserString key="HStretch" value="true"/> @@ -211,7 +211,7 @@ <!-- Skill tooltip (without progress bar) --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 52" align="Stretch" name="SkillNoProgressToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="HBox"> <UserString key="HStretch" value="true"/> @@ -245,7 +245,7 @@ <!-- Level tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 300 58" align="HStretch" name="LevelToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="AutoSizedTextBox" skin="NormalText" position="8 8 284 18" align="Left Top"> <Property key="Caption" value="#{sLevelProgress}"/> @@ -277,7 +277,7 @@ <!-- Magic effect tooltip --> <Widget type="VBox" skin="HUD_Box_NoTransp" position="0 0 0 0" align="Stretch" name="MagicEffectToolTip"> <Property key="AutoResize" value="true"/> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Widget type="HBox"> <UserString key="HStretch" value="true"/> diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 112fa6001a..4bc60ceb43 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -2,7 +2,7 @@ <MyGUI type="Layout"> <Widget type="VBox" skin="MW_Dialog" layer="Windows" position="0 0 600 200" align="Center" name="_Main"> - <Property key="Padding" value="12"/> + <Property key="Padding" value="8"/> <Property key="Spacing" value="8"/> <Property key="AutoResize" value="true"/> 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 73b196cf8c..a0e4240218 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 cc645ca441..c9bf0ef0a2 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 <memory> 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 <JournalViewModel> Model, bool questList); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 265b08fd6d..657f0e4ecc 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 fe256dc8ed..612f7d1bd8 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 6b5ba506b1..dd04950510 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 1ba4c7ed68..5ed5647371 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 5d7a547350..81edc4a00a 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<ESM::GameSetting>().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<GuiMode>::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; i<mWindows.size(); ++i) + { + bool visibilityMask = true; + if (i < mVisibilityMask.size()) + visibilityMask = mVisibilityMask[i]; + mWindows[i]->setVisible(visible && visibilityMask); + } + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3e17046df0..524575c6ae 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -494,6 +494,25 @@ namespace MWGui std::map<int, MWMechanics::SkillValue > mPlayerSkillValues; MyGUI::Gui *mGui; // Gui + + struct GuiModeState + { + GuiModeState(WindowBase* window) + { + mWindows.push_back(window); + } + GuiModeState(const std::vector<WindowBase*>& windows) + : mWindows(windows) {} + GuiModeState() {} + + void update(bool visible); + + std::vector<WindowBase*> mWindows; + std::vector<bool> 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<GuiMode, GuiModeState> mGuiModeStates; + // The currently active stack of GUI modes (top mode is the one we are in). std::vector<GuiMode> 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 | 120 +++--------------- 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, 127 insertions(+), 237 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37c3ce0d3c..242f358a9f 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 65f8c80d8e..d6926f11df 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<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ca6c85aba6..e7085bfbcd 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<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6da1f78069..fb4ba1016d 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<Interpreter::Type_Code>& code, const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index b3296e7a7f..ca697d0b6a 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 881b9997ce..e8a1a42ff7 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 fc4a984896..07753ab11e 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 d37f0c4e43..ec70146f26 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 62690a0f18..55a03bafdc 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 1232036ca2..927fdd5fe4 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 4f9201f060..6ea2e3e9a2 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 65cfa35c7e..2758f57c90 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 d9954a7928..d2d97a437b 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 25568da071..94e8b329de 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); + 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); + } - mBuyButton->setCaptionWithReplacing("#{sBuy}"); - - mChanceLayout->setVisible(false); - - mPtr = actor; - - 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 7c49ae54a7..41d6382cc3 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 0e1b2cc89d..ba4d05d751 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 9c706851fa..785b5ee48c 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 5006b08a4b..76ccd28ccd 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 00af45695a..54473746a8 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 d963e9d662..93f86ab657 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 f917cef0f4..295b8254b3 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 44c380b514..a2573d7804 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 a5d4c3324b..3649afe231 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<ESM::Book> *ref = mScroll.get<ESM::Book>(); Formatting::BookFormatter formatter; diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 961f1b675f..5ae8e972a0 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 0232eb7b32..104c81eab7 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 6a7376aa06..5923162743 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 37210819f7..b96896e4c1 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 6a36554d8b..d5982a1744 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 d12115c889..76038abb4c 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 ca0bb48e8f..60abf4ac7e 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 4b03c8d904..984f5a3949 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 d2e7719187..3079adb6d9 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 95a35be7fe..e52a889efb 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 3a7afe497d..4c4dc436c0 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 3230f897f2..529d5ebe16 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 400dc0ce49..73574ce7cc 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<WindowBase*> 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 81edc4a00a..54ff8c30f0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1206,25 +1206,32 @@ namespace MWGui } void WindowManager::pushGuiMode(GuiMode mode) + { + pushGuiMode(mode, MWWorld::Ptr()); + } + + void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg) { 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()) + 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); + + mGuiModes.push_back(mode); + + mGuiModeStates[mode].update(true); } - - if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(false); - - mGuiModes.push_back(mode); - - 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 524575c6ae..c267f505a8 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 0df451b18a..7ff6dd068c 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 454cc09f11..3bce25c6b3 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 b3ac772aeb..d2dc972fce 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<ESM::Book> *ref = getTarget().get<ESM::Book>(); 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 00a4756dda..c23bf29008 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 8e19927b80..191cf2063f 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 9aaa98f19d..6213d9e257 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 0ba180de86..6428a5b540 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 5ed5647371..e563d9aa9e 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 54ff8c30f0..2d17db643d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -16,6 +16,7 @@ #include <MyGUI_Gui.h> #include <MyGUI_ClipboardManager.h> #include <MyGUI_RenderManager.h> +#include <MyGUI_WidgetManager.h> #include <SDL_keyboard.h> #include <SDL_clipboard.h> @@ -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 c267f505a8..18ece21f98 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<std::string, int> 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<WindowModal*> 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 fa17d974dc..fe0ad33743 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 2d17db643d..4964af7d80 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 33f1edb6cf..3ed259c588 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 242f358a9f..243ec3ccf4 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 ca697d0b6a..7cabf68b1a 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<ESM::Book> *ref = mBook.get<ESM::Book>(); 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 3649afe231..ccbd1d7c0d 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 4964af7d80..70b95351b0 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<ESM::GameSetting>().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 18ece21f98..9fa921a4c7 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<WindowBase*> mWindows; std::vector<bool> 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<GuiMode, GuiModeState> mGuiModeStates; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3ed259c588..cf42db04bd 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 c68bad02a7..5b14898213 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 8b7bcaaca3..8dffaaad16 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 c13d49838f..86af14286c 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 7cabf68b1a..5abc63c55d 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 e8a1a42ff7..4f7224ea8f 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 2278b5141c..c63d470d7c 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 2b205d12f9..3a2573fd46 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<int> 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 07753ab11e..c4e50c8c2c 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 ec70146f26..fd66cfa80e 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 f3a06f2451..697d908621 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 745c7a1a53..2595793763 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 55a03bafdc..182b6ef974 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 927fdd5fe4..6257b56170 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 6ea2e3e9a2..85afc1aa3a 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 2758f57c90..3ae73a01fe 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 03cf1cab65..cf058caac3 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 7014b5fad9..766612f681 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<MyGUI::Widget*, int> EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d2d97a437b..48d2913251 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<MyGUI::Window>()->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 682baef3ce..12e2328f4e 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 94e8b329de..88973bd46a 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 41d6382cc3..ace63ae5c5 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 095f392b73..effd11d557 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 50e15a3fe1..07b6452a58 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<MWWorld::Ptr> EventHandle_Item; diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 7a544126db..36d19b5a96 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 7bc66fab47..8c7ec6bfe6 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 eae1cec7e2..ed6e4874f9 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 785b5ee48c..d3504ebc3a 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 76ccd28ccd..4e4e7164fd 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 19dd6fa035..6da7b09057 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 d07cdef3d1..c99d482ee3 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 911bce577d..c9e31d42de 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 54473746a8..0398112ba0 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 93f86ab657..f4602ce302 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 295b8254b3..a461f7b3dd 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 a2573d7804..f31625095f 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 34dd5a7d4f..8e9ec0ec79 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 7a4c3a22e7..e7c27b2685 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 2a49cf48a3..39e3d310a2 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 ccbd1d7c0d..a92ef92ab4 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 5ae8e972a0..596db06ad6 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 4e8547d33c..c239fc12f5 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 447331574c..4f8607fda3 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 5923162743..aeb5cfbe56 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 b96896e4c1..01cc6c2f9c 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 d5982a1744..8d0639d251 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 76038abb4c..f7bb8a101f 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 ccfa19c876..56c6632e14 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 60abf4ac7e..2a6c61a163 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 984f5a3949..55164b9348 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 3079adb6d9..ca6f2246e5 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 e52a889efb..d4785194ab 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 4c4dc436c0..02df6bd8e6 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 529d5ebe16..5ae4660475 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 476d19bd66..b39b1a8ab9 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 829659d16c..9bf8279bef 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 73574ce7cc..e6817358fa 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 70b95351b0..31a072fd10 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<std::string> &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 b4a6b7d2f0..92f29e3efc 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 c63d470d7c..33daa0ad14 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 48d2913251..2effcc7006 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 374a5d3d89..2b407ac934 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 8d0639d251..d5dee11396 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 ebda8873c9..4268b33a08 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -106,6 +106,7 @@ namespace MWGui Gui::SharedStateButton* t = mScrollView->createWidget<Gui::SharedStateButton>(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 bb707fa0d2..6221799b5e 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -32,18 +32,23 @@ <Widget type="HBox" position="0 8 350 24" align="Left Top HStretch" name="Categories"> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="AllButton"> <Property key="Caption" value="#{sAllTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="WeaponButton"> <Property key="Caption" value="#{sWeaponTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="ApparelButton"> <Property key="Caption" value="#{sApparelTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="MagicButton"> <Property key="Caption" value="#{sMagicTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 60 24" name="MiscButton"> <Property key="Caption" value="#{sMiscTab}"/> + <Property key="NeedKey" value="false"/> </Widget> </Widget> diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index f9f24581f0..d1f31c475d 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -9,18 +9,23 @@ <Widget type="HBox" position="8 8 566 24" align="Left Top HStretch" name="Categories"> <Widget type="AutoSizedButton" skin="MW_Button" name="AllButton"> <Property key="Caption" value="#{sAllTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" name="WeaponButton"> <Property key="Caption" value="#{sWeaponTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" name="ApparelButton"> <Property key="Caption" value="#{sApparelTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" name="MagicButton"> <Property key="Caption" value="#{sMagicTab}"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="AutoSizedButton" skin="MW_Button" name="MiscButton"> <Property key="Caption" value="#{sMiscTab}"/> + <Property key="NeedKey" value="false"/> </Widget> </Widget> 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 243ec3ccf4..190768f261 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 31a072fd10..2c58336da5 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<MyGUI::Widget>("",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 9fa921a4c7..17707d2c31 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 cf42db04bd..cd17c5175c 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 254da56d6e..6f2c146b1b 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 697d908621..65b079d85b 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 2595793763..ab52549ec9 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 8c7ec6bfe6..d3c1ec292a 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 ba09ce3699..c97532df55 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -28,10 +28,35 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector<MyGUI::Widget*>& 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<int, MyGUI::Widget*>::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<const int, MyGUI::Widget*>& 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 86cc67962e..fff36d862b 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -2,11 +2,12 @@ #define OPENMW_MWGUI_KEYBOARDNAVIGATION_H #include <MyGUI_KeyCode.h> +#include <MyGUI_IUnlinkWidget.h> 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<int, MyGUI::Widget*> mKeyFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2c58336da5..6306ef81a7 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 17707d2c31..30d19e9f14 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<std::string, int> 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<WindowModal*> 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 c97532df55..8ce26e1d0b 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -3,6 +3,7 @@ #include <MyGUI_InputManager.h> #include <MyGUI_WidgetManager.h> #include <MyGUI_Button.h> +#include <MyGUI_Gui.h> #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<MyGUI::Widget*>& 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 6306ef81a7..8266e3e8d2 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 db851e0674..c452a1f5fe 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 b39b1a8ab9..afcf23be3f 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 9bf8279bef..19c265204c 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 8266e3e8d2..bfd6fd20d7 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 6f2c146b1b..cea176ff6c 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 ba4d05d751..ed7273384f 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 e2ef52be0e..4ea9d7ac36 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 bfd6fd20d7..47557f3695 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<ESM::GameSetting>().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<MyGUI::Widget>("",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 30d19e9f14..90fcf89790 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<WindowBase*> 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 c4e50c8c2c..90ef32cedc 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 fd66cfa80e..23af6bc963 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 6257b56170..a68f1cb43d 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 3ae73a01fe..27b0e408b3 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 2effcc7006..ec6dcb2cbf 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 12e2328f4e..4ac5bd9d0c 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 ace63ae5c5..335e5fda96 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 dcfb075db8..735bf36825 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -589,11 +589,8 @@ namespace MWGui mEncumbranceBar->setValue(static_cast<int>(encumbrance), static_cast<int>(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 fb5be34939..5576b52ed0 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 657f0e4ecc..4e629403a7 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 612f7d1bd8..1beb9ee16d 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 01cc6c2f9c..6eb52366bb 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 f7bb8a101f..7bacda3852 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 9261912b45..601204aa1d 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 17e51e3383..bf505b00fd 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 2a6c61a163..feccfd942c 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 55164b9348..69fdc135b6 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 ca6f2246e5..c1f7f8ac17 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 e6817358fa..6889ad9ec2 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 47557f3695..9635f804e7 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 8dffaaad16..a27d9c7498 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 4f7224ea8f..b20498feb6 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 c99d482ee3..0070aa55b9 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 596db06ad6..35016e5dcb 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 4f8607fda3..c6e48819c0 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 6eb52366bb..36f7499a0d 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 6889ad9ec2..c9f9555b07 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 9635f804e7..3e55060f8e 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 23af6bc963..891106853f 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 a68f1cb43d..f243b83870 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 27b0e408b3..a53d4f7829 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 4ac5bd9d0c..224ecba665 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 335e5fda96..39614ebd1f 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 4ea9d7ac36..3dae2157f7 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 36f7499a0d..649aab3f23 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 7bacda3852..855016666c 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 69fdc135b6..00f38024da 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 d4785194ab..127c85f6a1 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 afcf23be3f..cd1d29854c 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 19c265204c..6bd90473f8 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 c9f9555b07..f183c97feb 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 3e55060f8e..b512d8fc8c 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 f5ec86cc31..3e5ab7ce62 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 190768f261..43d99b6b35 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 ed7273384f..87c1b2f3c5 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 3dae2157f7..fc335d1e74 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 b512d8fc8c..c9dec02873 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 90fcf89790..773eed4fc5 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 c9dec02873..906151ab12 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<ESM::GameSetting>().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 773eed4fc5..f315bb9063 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 be0346e882..1d04e871e7 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 b510e133a6..19468de3c9 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 906151ab12..29425e7c35 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 87c1b2f3c5..779e358d38 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 fc335d1e74..3542f3ebfe 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 29425e7c35..2cfafd0a24 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 2cfafd0a24..8349ca0bca 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<std::string> &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 85afc1aa3a..90ed1a596b 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 a53d4f7829..50c69da3b6 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 5abc63c55d..ae20b8e43c 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 b20498feb6..2459c34645 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 cf4a5b589a..a9319048ec 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -406,10 +406,11 @@ namespace MWGui MyGUI::EditBox* box = parent->createWidget<MyGUI::EditBox>("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 8ce26e1d0b..ddfd8f6624 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 a92ef92ab4..ea811f5b1a 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 35016e5dcb..adc0bd93e0 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 8ac133d76a..11d7466a81 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 a0e4240218..3a67e857db 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 15d9d555f8..f22d825dd1 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -51,8 +51,6 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("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 0398112ba0..32da7876c9 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 1d04e871e7..76e79a3481 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<MyGUI::ImageBox>(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 366b0c4c6e..cee3f46827 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -82,6 +82,7 @@ <!-- Sneak indicator box --> <Widget type="Button" skin="" position="162 146 36 36" align="Left Bottom" name="SneakBox"> + <Property key="Visible" value="false"/> <Widget type="Widget" skin="HUD_Box" position="0 0 36 36"> <Property key="NeedMouse" value="false"/> <Widget type="ImageBox" skin="ImageBox" position="2 2 32 32" align="Left Top" name="SneakImage"> 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 8349ca0bca..6c69dffbc4 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 cd17c5175c..c5b18ff17b 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 c1f7f8ac17..13a0a6883d 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 127c85f6a1..fb7b10debf 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 cd1d29854c..8a360435c0 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 6bd90473f8..c7ccee0254 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 6c69dffbc4..c572bce54d 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 5b14898213..0140653a1a 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 a27d9c7498..2d13a346a7 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 88973bd46a..74d80d2926 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -4,6 +4,7 @@ #include <MyGUI_Button.h> #include <MyGUI_ScrollView.h> +#include <MyGUI_EditBox.h> #include <components/widgets/list.hpp> #include <components/settings/settings.hpp> @@ -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 39614ebd1f..4906de9199 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 d5dee11396..4aa208d8f6 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 855016666c..ec90fa3cec 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 feccfd942c..c2e58b81ff 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 00f38024da..fc692a55a7 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 828a84589b..6e884a0910 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 20000b3d33..ca7674f229 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 c5b18ff17b..79c6895613 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 2b407ac934..64609cbe69 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 c572bce54d..d734d75408 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 79c6895613..b1f80cae66 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 ddfd8f6624..da99c72d0f 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 43d99b6b35..2df3113b32 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 76e79a3481..d1118848b6 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 19468de3c9..88dd0c57b1 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -14,7 +14,7 @@ namespace MWGui public: typedef std::shared_ptr<FadeOp> 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 13a0a6883d..120ab5cbae 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 fb7b10debf..69a0130591 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 d734d75408..6be7541093 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 f315bb9063..56e7d9b7b7 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 31a70191f2..f6c0996308 100644 --- a/files/mygui/openmw_map_window.skin.xml +++ b/files/mygui/openmw_map_window.skin.xml @@ -2,6 +2,7 @@ <MyGUI type="Resource" version="1.1"> <Resource type="ResourceSkin" name="MW_MapView" size="516 516"> + <Property key="NeedKey" value="false"/> <Child type="Widget" skin="" offset="0 0 516 516" align="Stretch" name="Client"/> <!-- invisible scroll bars, needed for setting the view offset --> diff --git a/files/mygui/openmw_scroll.skin.xml b/files/mygui/openmw_scroll.skin.xml index 415c2479a6..cff0ad7eb3 100644 --- a/files/mygui/openmw_scroll.skin.xml +++ b/files/mygui/openmw_scroll.skin.xml @@ -3,11 +3,13 @@ <MyGUI type="Resource" version="1.1"> <Resource type="ResourceSkin" name="MW_ScrollView" size="516 516"> + <Property key="NeedKey" value="false"/> <Child type="Widget" skin="" offset="0 0 502 516" align="Stretch" name="Client"/> <Child type="MWScrollBar" skin="MW_VScroll" offset="498 3 14 513" align="Right Top VStretch" name="VScroll"/> </Resource> <Resource type="ResourceSkin" name="MW_ScrollViewH" size="516 516"> + <Property key="NeedKey" value="false"/> <Child type="Widget" skin="" offset="0 0 516 502" align="Stretch" name="Client"/> <Child type="MWScrollBar" skin="MW_HScroll" offset="3 498 513 14" align="Left Bottom HStretch" name="HScroll"/> </Resource> 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 fb4ba1016d..bacbd7b2bf 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<ESM::NPC>* ref = mActor.get<ESM::NPC>(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } - else if (mActor.getTypeName() == typeid(ESM::Creature).name()) - { - MWWorld::LiveCellRef<ESM::Creature>* ref = mActor.get<ESM::Creature>(); - 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 5b89f40554..019baa2974 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 ec6dcb2cbf..86aa64e8b9 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -270,6 +270,11 @@ namespace MWGui mMainWidget->castType<MyGUI::Window>()->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 224ecba665..dbb33969ff 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 c2e58b81ff..341167ab7c 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<ESM::GameSetting>().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 fc692a55a7..514d24022d 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 6be7541093..76f0b029d5 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 bacbd7b2bf..c29476c7f5 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<ESM::Dialogue> &dialogs = - MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); - - MWWorld::Store<ESM::Dialogue>::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<ESM::Dialogue>().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 40a24a1f84..81bd2f2b98 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<std::string, ESM::Dialogue> mDialogueMap; std::set<std::string> mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. <Faction1, <Faction2, Difference> > @@ -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 86aa64e8b9..95fa042cfa 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<ESM::GameSetting> &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; i<mTopicsList->getItemCount(); ++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 c29476c7f5..dea9423494 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<ESM::NPC>()->mBase->getTransport().empty()) - || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get<ESM::Creature>()->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 95fa042cfa..e4d0af424b 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<ESM::NPC>()->mBase->getTransport().empty()) + || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get<ESM::Creature>()->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 dbb33969ff..af5fe5efc2 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 019baa2974..d7f30e0792 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 e4d0af424b..920183c61a 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 dea9423494..29bb49ca00 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<ESM::Dialogue> &dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); @@ -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 920183c61a..4ec3da50bd 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<DialogueText*>::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 af5fe5efc2..b854e6c1a1 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<std::string> 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 2df3113b32..51a17d3800 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 182b6ef974..6094111f84 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 f243b83870..f5647e9ea5 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 779e358d38..1db2691f4a 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 76f0b029d5..85f57a75eb 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 56e7d9b7b7..53b2dc33a5 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 67bb53e717..e8757e4a37 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<int> (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 4ec3da50bd..869b83928e 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 b854e6c1a1..83f1eb1def 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 29bb49ca00..ffa26e2112 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -330,14 +330,12 @@ namespace MWDialogue updateGlobals(); std::list<std::string> keywordList; - int choice = mChoice; - mChoice = -1; mActorKnownTopics.clear(); const MWWorld::Store<ESM::Dialogue> &dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, -1, mTalkedTo); for (MWWorld::Store<ESM::Dialogue>::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 | 127 +++++++-------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 24 ++- apps/openmw/mwgui/dialogue.cpp | 154 ++++++++++++------ 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, 231 insertions(+), 150 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 18f249e567..c928fa9405 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_DIALOGUEMANAGER_H #include <string> +#include <vector> +#include <list> #include <stdint.h> @@ -42,24 +44,29 @@ namespace MWBase virtual bool isInChoice() const = 0; - virtual void startDialogue (const MWWorld::Ptr& actor) = 0; + typedef std::pair<std::string, std::string> 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<std::pair<std::string, int> >& 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 bool checkServiceRefused () = 0; + virtual std::list<std::string> getAvailableTopics() = 0; - virtual void persuade (int type) = 0; + virtual bool checkServiceRefused (Response& response) = 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 51a17d3800..d8bce67e41 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 ffa26e2112..4ed3b82a92 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include <iterator> #include <list> +#include <iostream> #include <components/esm/loaddial.hpp> #include <components/esm/loadinfo.hpp> @@ -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<ESM::Dialogue> &dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>(); @@ -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<Interpreter::Type_Code>& 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<ESM::Dialogue> &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<std::string> keywordList; mActorKnownTopics.clear(); const MWWorld::Store<ESM::Dialogue> &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<std::string> DialogueManager::getAvailableTopics() + { + updateActorKnownTopics(); + + std::list<std::string> 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)); + } + + const std::vector<std::pair<std::string, int> >& DialogueManager::getChoices() + { + return mChoices; + } + + bool DialogueManager::isGoodbye() + { + return mGoodbye; } void DialogueManager::goodbye() { - mIsInChoice = true; - - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - - win->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<ESM::Dialogue>(); const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); std::vector<const ESM::DialInfo *> 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 81bd2f2b98..d9c622120c 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<std::pair<std::string, int> > 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<Interpreter::Type_Code>& 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<std::string> 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<std::pair<std::string, int> >& 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 869b83928e..a7f18561e9 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<MyGUI::Window>()->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<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); + 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<Link*>::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<std::string> keyWords) { mTopicsList->clear(); for (std::map<std::string, Link*>::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<ESM::NPC>()->mBase->getTransport().empty()) || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty()); - bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); @@ -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<std::pair<std::string, int> >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) + mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); + for (std::vector<std::pair<std::string, int> >::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<ESM::GameSetting>().find("sGoodbye")->getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, @@ -550,15 +581,35 @@ namespace MWGui reinterpret_cast<Link*>(link)->activated(); } + void DialogueWindow::onTopicActivated(const std::string &topicId) + { + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); + addResponse(response.first, response.second); + } + + void DialogueWindow::onChoiceActivated(int id) + { + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); + addResponse(response.first, response.second); + } + + void DialogueWindow::onGoodbyeActivated() + { + 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<int>(pos) * -1); } - void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) + void DialogueWindow::addResponse(const std::string &title, const std::string &text, bool needMargin) { mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); + updateTopics(); } void DialogueWindow::addMessageBox(const std::string& text) @@ -567,18 +618,6 @@ namespace MWGui updateHistory(); } - void DialogueWindow::addChoice(const std::string& choice, int id) - { - mChoices.push_back(std::make_pair(choice, id)); - updateHistory(); - } - - void DialogueWindow::clearChoices() - { - mChoices.clear(); - updateHistory(); - } - void DialogueWindow::updateDisposition() { bool dispositionVisible = false; @@ -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 83f1eb1def..c83906588f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -8,6 +8,8 @@ #include "../mwdialogue/keywordsearch.hpp" +#include <MyGUI_Delegate.h> + 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<const std::string&, const std::string&> EventHandle_Result; + EventHandle_Result eventPersuadeMsg; + virtual void onOpen(); private: @@ -53,6 +55,8 @@ namespace MWGui struct Topic : Link { + typedef MyGUI::delegates::CMultiDelegate1<const std::string&> 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<int> 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<std::string> 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<DialogueText*> mHistoryContents; std::vector<std::pair<std::string, int> > mChoices; + bool mGoodbye; std::vector<Link*> mLinks; std::map<std::string, Link*> mTopicLinks; + std::vector<Link*> mDeleteLater; + KeywordSearchT mKeywordSearch; BookPage* mHistory; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 74d80d2926..6b0b33a0a9 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 341167ab7c..939f70b596 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 120ab5cbae..1081ee81ec 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 02df6bd8e6..c9f19ad926 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 85f57a75eb..f5825f08d4 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 53b2dc33a5..f6b2707ad0 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 fcb7e8f3b2..21d8d469b9 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 051380ff52..c7bb6a26e6 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?= <tastyfish@sznam.cz> 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 5c22de12ec..3a66c264b1 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 e575456d97..f0087e43d2 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 9679533be9..68c07c1ab6 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 1e3a1e17bc..9c8e561917 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 <andrei.kortunov@yandex.ru> 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 ee368ad242..068ff31864 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -24,6 +24,7 @@ #include <components/esm/loadgmst.hpp> #include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/unrefqueue.hpp> +#include <components/settings/settings.hpp> #include <components/nifosg/particle.hpp> // 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 0000000000..e4f970a79a --- /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 aec667a9c4..f4c7f0a4a5 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 fe0ad33743..d81b2ed006 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 a356fe4e29..dff8cd73c0 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 f5825f08d4..7e3741ae6b 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 <andrei.kortunov@yandex.ru> 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 068ff31864..887189a851 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,5 +1,6 @@ #include "physicssystem.hpp" +#include <iostream> #include <stdexcept> #include <osg/Group> @@ -24,7 +25,6 @@ #include <components/esm/loadgmst.hpp> #include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/unrefqueue.hpp> -#include <components/settings/settings.hpp> #include <components/nifosg/particle.hpp> // 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; i<numSteps; ++i) { - position = MovementSolver::move(position, physicActor->getPtr(), 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 aaf55e2b61..3ef9990f53 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -220,6 +220,8 @@ namespace MWPhysics osg::ref_ptr<osg::Group> 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 e4f970a79a..0000000000 --- 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 f4c7f0a4a5..aec667a9c4 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 d9782ccf39..8c84fd1ed5 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 b1f80cae66..cf52cbd182 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 d8bce67e41..d454067c81 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 7e3741ae6b..8272568d3e 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 f6b2707ad0..612470a7e0 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 cf52cbd182..6f0b3b1b4e 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 eeddc22dd4..a7bd573f4f 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 70f73ce42f..467d4b82d2 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 ae20b8e43c..a86146f2ff 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,6 +1,7 @@ #include "bookwindow.hpp" #include <MyGUI_TextBox.h> +#include <MyGUI_InputManager.h> #include <components/esm/loadbook.hpp> @@ -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 | 75 +++++++++++++++++----------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 7c158af8dc..a7bea5eb5e 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -5,49 +5,50 @@ <Widget type="Window" skin="" layer="JournalBooks" align="Left Top" position="0 0 584 398" name="_Main"> <Widget type="ImageBox" skin="ImageBox" position="-71 0 728 398" align="Left Top" name="JImage"> - <Property key="ImageTexture" value="textures\tx_menubook.dds"/> - <Widget type="Widget" position="71 0 584 398" align="Left Top"> + <Property key="ImageTexture" value="textures\tx_menubook.dds"/> + <Widget type="Widget" position="71 0 584 398" align="Left Top"> - <Widget type="Widget" position="0 0 292 398"> - <Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> + <Widget type="ImageButton" skin="ImageBox" position="40 358 64 32" name="TakeButton"> + <Property key="ImageHighlighted" value="textures\tx_menubook_take_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_take_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_take_pressed.dds"/> </Widget> - </Widget> - <Widget type="Widget" position="292 0 292 398"> - <Widget type="ImageButton" skin="ImageBox" position="38 358 48 32" name="NextPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> + + <Widget type="Widget" position="0 0 292 398"> + <Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> + </Widget> + </Widget> + <Widget type="Widget" position="292 0 292 398"> + <Widget type="ImageButton" skin="ImageBox" position="38 358 48 32" name="NextPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> + </Widget> </Widget> - </Widget> - <Widget type="ImageButton" skin="ImageBox" position="40 358 64 32" name="TakeButton"> - <Property key="ImageHighlighted" value="textures\tx_menubook_take_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_take_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_take_pressed.dds"/> - </Widget> - <Widget type="ImageButton" skin="ImageBox" position="488 358 48 32" name="CloseButton"> - <Property key="ImageHighlighted" value="textures\tx_menubook_close_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_close_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_close_pressed.dds"/> - </Widget> + <Widget type="ImageButton" skin="ImageBox" position="488 358 48 32" name="CloseButton"> + <Property key="ImageHighlighted" value="textures\tx_menubook_close_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_close_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_close_pressed.dds"/> + </Widget> - <Widget type="TextBox" skin="NormalText" position="30 358 250 16" name="LeftPageNumber"> - <Property key="TextColour" value="0 0 0"/> - <Property key="TextAlign" value="Center"/> - <Property key="NeedMouse" value="false"/> - </Widget> - <Widget type="TextBox" skin="NormalText" position="310 358 250 16" name="RightPageNumber"> - <Property key="TextColour" value="0 0 0"/> - <Property key="TextAlign" value="Center"/> - <Property key="NeedMouse" value="false"/> - </Widget> + <Widget type="TextBox" skin="NormalText" position="30 358 250 16" name="LeftPageNumber"> + <Property key="TextColour" value="0 0 0"/> + <Property key="TextAlign" value="Center"/> + <Property key="NeedMouse" value="false"/> + </Widget> + <Widget type="TextBox" skin="NormalText" position="310 358 250 16" name="RightPageNumber"> + <Property key="TextColour" value="0 0 0"/> + <Property key="TextAlign" value="Center"/> + <Property key="NeedMouse" value="false"/> + </Widget> - <Widget type="Widget" skin="" position="30 15 250 328" name="LeftPage"/> - <Widget type="Widget" skin="" position="310 15 250 328" name="RightPage"/> - </Widget> + <Widget type="Widget" skin="" position="30 15 250 328" name="LeftPage"/> + <Widget type="Widget" skin="" position="310 15 250 328" name="RightPage"/> + </Widget> </Widget> </Widget> 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 9b89c3957c..a611b1f06f 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<MyGUI::EditBox>("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<MyGUI::EditBox>("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 a7bd573f4f..bf18cef5b9 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 467d4b82d2..66be007191 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 da99c72d0f..c9ad5a5876 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -4,6 +4,7 @@ #include <MyGUI_WidgetManager.h> #include <MyGUI_Button.h> #include <MyGUI_Gui.h> +#include <MyGUI_Window.h> #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -30,7 +31,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector<MyGUI::Widget*>& resu } } +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType<MyGUI::Window>(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<const int, MyGUI::Widget*>& 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<MyGUI::Button>(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<MyGUI::Button>(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 fff36d862b..15aa0d6a84 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<int, MyGUI::Widget*> mKeyFocus; + + MyGUI::Widget* mCurrentFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8272568d3e..950b1edc3a 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 c9ad5a5876..d4d0a8c43d 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 a7f18561e9..b7da86f4e8 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 c83906588f..6535ad4b24 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 d4d0a8c43d..6e1113a4fa 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 15aa0d6a84..728f16a3df 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<int, MyGUI::Widget*> mKeyFocus; MyGUI::Widget* mCurrentFocus; + MyGUI::Widget* mModalWindow; }; } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index e563d9aa9e..a0e7eeddeb 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 f183c97feb..56901c95af 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<WindowBase*> EventHandle_WindowBase; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 950b1edc3a..0b51b2b3f0 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 163b9d1341..edc103443b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -81,6 +81,7 @@ color_misc=0,205,205 # ???? <Resource type="ResourceSkin" name="SandTextButton" size="16 16"> <Property key="FontName" value="Default"/> <Property key="TextAlign" value="Left Bottom"/> + <Property key="NeedKey" value="true"/> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"> <State name="disabled" colour="#{fontcolour=disabled}" shift="0"/> <State name="normal" colour="#{fontcolour=normal}" shift="0"/> 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 a86146f2ff..c18548dad9 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 6e1113a4fa..2b06de2956 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 c5a459f22b..9318e32ed4 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 b7da86f4e8..b726bf0d9c 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<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); mHistoryContents.clear(); + + mKeywords.clear(); + updateTopicsPane(); } for (std::vector<Link*>::iterator it = mLinks.begin(); it != mLinks.end(); ++it) @@ -438,6 +442,16 @@ namespace MWGui } void DialogueWindow::setKeywords(std::list<std::string> keyWords) + { + if (mKeywords == keyWords && isCompanion() == mIsCompanion) + return; + mIsCompanion = isCompanion(); + mKeywords = keyWords; + + updateTopicsPane(); + } + + void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); for (std::map<std::string, Link*>::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) @@ -484,7 +498,7 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list<std::string>::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + for(std::list<std::string>::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 6535ad4b24..97a0e8b370 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<std::string> mKeywords; + std::vector<DialogueText*> mHistoryContents; std::vector<std::pair<std::string, int> > 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 90ef32cedc..739acee486 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 6b0b33a0a9..3616b8b62f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -9,7 +9,6 @@ #include <components/widgets/list.hpp> #include <components/settings/settings.hpp> -#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 aeb5cfbe56..d9c3a5f169 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 939f70b596..2eeeafe0d4 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 1081ee81ec..b6504d223f 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 c9f19ad926..7c7cdb63e0 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 8a360435c0..43c6f135a2 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,7 @@ #include "waitdialog.hpp" #include <MyGUI_ProgressBar.h> +#include <MyGUI_InputManager.h> #include <components/misc/rng.hpp> @@ -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<int>(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 c7ccee0254..eb6a556404 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 3a67e857db..30a440b581 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -8,6 +8,7 @@ #include <MyGUI_TextBox.h> #include <MyGUI_Button.h> +#include <MyGUI_InputManager.h> #include <components/misc/stringops.hpp> #include <components/widgets/imagebutton.hpp> @@ -84,10 +85,16 @@ namespace void adviseButtonClick (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender)) { - getWidget <Gui::ImageButton> (name) -> + getWidget <MyGUI::Widget> (name) -> eventMouseButtonClick += newDelegate(this, Handler); } + void adviseKeyPress (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)) + { + getWidget <MyGUI::Widget> (name) -> + eventKeyButtonPressed += newDelegate(this, Handler); + } + MWGui::BookPage* getPage (char const * name) { return getWidget <MWGui::BookPage> (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<Gui::MWList>(QuestsList); list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); @@ -237,6 +250,8 @@ namespace --page; } updateShowingPages(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget<MyGUI::Widget>(CloseBTN)); } void onClose() @@ -348,8 +363,19 @@ namespace relPages = 0; } - setVisible (PrevPageBTN, page > 0); - setVisible (NextPageBTN, relPages > 2); + MyGUI::Widget* nextPageBtn = getWidget<MyGUI::Widget>(NextPageBTN); + MyGUI::Widget* prevPageBtn = getWidget<MyGUI::Widget>(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 1131b1bbcd..964b5ea955 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -3,32 +3,27 @@ <MyGUI type="Layout"> <Widget type="Window" skin="" layer="JournalBooks" align="Left|Top" position="0 0 565 390" name="_Main"> - <Property key="NeedKey" value="false"/> <!-- pages --> <Widget type="ImageBox" skin="ImageBox" position="-70 0 705 390" align="Top|Right" name="JImage"> <Property key="ImageTexture" value="textures\tx_menubook.dds"/> <Widget type="Widget" position="70 0 565 390" align="Top|Right"> - <Widget type="Widget" position="0 0 282 390"> - <Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> - </Widget> - </Widget> - <Widget type="Widget" position="282 0 282 390"> - <Widget type="ImageButton" skin="ImageBox" position="18 350 48 32" name="NextPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> - </Widget> - </Widget> - - <!-- buttons --> <Widget type="ImageButton" skin="ImageBox" position="40 350 64 32" name="OptionsBTN"> <!-- Image set at runtime since it may not be available in all versions of the game --> </Widget> + + <Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> + </Widget> + <Widget type="ImageButton" skin="ImageBox" position="300 350 48 32" name="NextPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> + </Widget> + <Widget type="TextBox" skin="NormalText" position="150 350 32 16" name="PageOneNum"> <Property key="TextColour" value="0 0 0"/> </Widget> @@ -36,11 +31,14 @@ <Widget type="TextBox" skin="NormalText" position="410 350 32 16" name="PageTwoNum"> <Property key="TextColour" value="0 0 0"/> </Widget> + + <Widget type="ImageButton" skin="ImageBox" position="460 350 48 32" name="CloseBTN"> <Property key="ImageHighlighted" value="textures\tx_menubook_close_over.dds"/> <Property key="ImageNormal" value="textures\tx_menubook_close_idle.dds"/> <Property key="ImagePushed" value="textures\tx_menubook_close_pressed.dds"/> </Widget> + <Widget type="ImageButton" skin="ImageBox" position="460 350 64 32" name="JournalBTN"> <Property key="ImageHighlighted" value="textures\tx_menubook_journal_over.dds"/> <Property key="ImageNormal" value="textures\tx_menubook_journal_idle.dds"/> 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 edc103443b..5f96d0a57c 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -66,6 +66,7 @@ color_misc=0,205,205 # ???? <Resource type="ResourceSkin" name="SandTextButtonC" size="16 16"> <Property key="FontName" value="Default"/> <Property key="TextAlign" value="Top HCenter"/> + <Property key="NeedKey" value="true"/> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"> <State name="disabled" colour="#{fontcolour=disabled}" shift="0"/> <State name="normal" colour="#{fontcolour=normal}" shift="0"/> @@ -97,6 +98,7 @@ color_misc=0,205,205 # ???? <Resource type="ResourceSkin" name="SandTextButtonDisabled" size="16 16"> <Property key="FontName" value="Default"/> <Property key="TextAlign" value="Left Bottom"/> + <Property key="NeedKey" value="true"/> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"> <State name="normal" colour="#{fontcolour=disabled}" shift="0"/> </BasisSkin> @@ -104,6 +106,7 @@ color_misc=0,205,205 # ???? <Resource type="ResourceSkin" name="SpellTextUnequipped" size="16 16"> <Property key="FontName" value="Default"/> + <Property key="NeedKey" value="true"/> <Property key="TextAlign" value="Left Bottom"/> <BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"> <State name="disabled" colour="#{fontcolour=disabled}" shift="0"/> 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 744ef236fa..45767bf01d 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 0140653a1a..80284e9b2a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,6 +1,8 @@ #include "alchemywindow.hpp" #include <MyGUI_Gui.h> +#include <MyGUI_Button.h> +#include <MyGUI_EditBox.h> #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 2d13a346a7..d1e54241a1 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 739acee486..ad71be7dff 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 891106853f..8ca3506176 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 b726bf0d9c..4e36fe117a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include <MyGUI_LanguageManager.h> #include <MyGUI_Window.h> #include <MyGUI_ProgressBar.h> +#include <MyGUI_ScrollBar.h> +#include <MyGUI_Button.h> #include <components/widgets/list.hpp> #include <components/translation/translation.hpp> @@ -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 32da7876c9..26a364f726 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 a461f7b3dd..11a8aece29 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 e7c27b2685..0e4ff1cf45 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 43c6f135a2..a7ad687cb6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,7 @@ #include <MyGUI_ProgressBar.h> #include <MyGUI_InputManager.h> +#include <MyGUI_ScrollBar.h> #include <components/misc/rng.hpp> @@ -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 6f0b3b1b4e..0637b6d837 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 8809f44cd6..cba7fc7431 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 0e4ff1cf45..eb7f158d78 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 39e3d310a2..a51124705b 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 eb7f158d78..423dbb0360 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 8c84fd1ed5..02eb30da06 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?= <tastyfish@sznam.cz> 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 9c8e561917..f7f87ce77f 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 <andrei.kortunov@yandex.ru> 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 5d9ef726a3..574444a8f2 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?= <tastyfish@sznam.cz> 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 f7f87ce77f..23bd688abd 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 0637b6d837..e6acbbd522 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 b38097dce5..8d45022f88 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -31,6 +31,7 @@ <!-- World button --> <Widget type="AutoSizedButton" skin="MW_Button" position="213 233 61 22" align="Bottom Right" name="WorldButton"> <Property key="ExpandDirection" value="Left"/> + <Property key="NeedKey" value="false"/> </Widget> </Widget> 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 4e629403a7..00e4e30a58 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 0b51b2b3f0..fbee52c827 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 6b79b94178..f5a462977b 100644 --- a/files/mygui/openmw_interactive_messagebox_notransp.layout +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -9,6 +9,7 @@ <Property key="WordWrap" value="true"/> <Property key="MultiLine" value="1"/> <Property key="VisibleVScroll" value="1"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="Widget" skin="" position="0 0 500 400" align="Stretch" name="buttons"> </Widget> 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 38e6590b7a..53b2774162 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 a068d71f3c..286405f797 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 fc11ddfd7d..66855373ae 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_strength.dds"/> <Property key="Caption" value="#{sAttributeStrength}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal1"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal1"> </Widget> </Widget> @@ -64,7 +64,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_int.dds"/> <Property key="Caption" value="#{sAttributeIntelligence}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal2"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal2"> </Widget> </Widget> @@ -78,7 +78,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_wilpower.dds"/> <Property key="Caption" value="#{sAttributeWillpower}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal3"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal3"> </Widget> </Widget> @@ -92,7 +92,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_agility.dds"/> <Property key="Caption" value="#{sAttributeAgility}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal4"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal4"> </Widget> </Widget> @@ -107,7 +107,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_speed.dds"/> <Property key="Caption" value="#{sAttributeSpeed}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal5"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal5"> </Widget> </Widget> @@ -121,7 +121,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_endurance.dds"/> <Property key="Caption" value="#{sAttributeEndurance}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal6"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal6"> </Widget> </Widget> @@ -135,7 +135,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_personality.dds"/> <Property key="Caption" value="#{sAttributePersonality}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal7"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal7"> </Widget> </Widget> @@ -149,7 +149,7 @@ <UserString key="ImageTexture_AttributeImage" value="icons\k\attribute_luck.dds"/> <Property key="Caption" value="#{sAttributeLuck}"/> </Widget> - <Widget type="AutoSizedTextBox" skin="SandTextButton" name="AttribVal8"> + <Widget type="AutoSizedTextBox" skin="SandText" name="AttribVal8"> </Widget> </Widget> </Widget> 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 6094111f84..2d016ddf19 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 f5647e9ea5..7ee39770d8 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 dd04950510..6c421de5ea 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<MessageBox*>::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 4e36fe117a..27a5003dbb 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<ESM::GameSetting> &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 27a5003dbb..95fa004696 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?= <tastyfish@sznam.cz> 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 3a66c264b1..23fc4ec285 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 f0087e43d2..1673003c4d 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 e6aa013ec4..5bf5dbcb31 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1305,13 +1305,19 @@ public: std::vector<osg::ref_ptr<AlphaFader> > 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<osg::Material> 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 863ecc77d3..8278c71013 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,6 +4,7 @@ #include <string> #include <memory> #include <vector> +#include <iostream> #include <osg/ref_ptr> #include <osg/Vec4f> diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 23bd688abd..9da7abc010 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?= <tastyfish@sznam.cz> 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 9da7abc010..ee7ac62553 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 a611b1f06f..e6de9c42c9 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?= <tastyfish@sznam.cz> 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 ee7ac62553..931422d5e6 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 c239fc12f5..9bf6e4385f 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; i<mResolutionList->getItemCount(); ++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<MyGUI::Button>()->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?= <tastyfish@sznam.cz> 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 23fc4ec285..3826fd5f62 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 1673003c4d..43059ab6d4 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 5bf5dbcb31..178c753c68 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 8278c71013..59a8ddc4e0 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 <andrei.kortunov@yandex.ru> 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 2a25d5bbcd..9c7fba9fa7 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 <kyleacooley@gmail.com> 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 54d65ac3fb..bde5af3d93 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include <algorithm> +#include <cctype> #include <cstdint> #include <limits> #include <map> @@ -346,8 +348,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import for (int i = 0; i < idCollection()->getSize(); ++i) { auto& record = static_cast<const Record<LandTexture>&>(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<const Record<LandTexture>&>(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 95fa004696..8dd027c4ac 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 2d016ddf19..e8ac33f6db 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 7ee39770d8..bbff34c8da 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 <andrei.kortunov@yandex.ru> 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 57c756762f..a70d833c7e 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 <andrei.kortunov@yandex.ru> 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 d9068b285b..398439ad8d 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 e6de9c42c9..a9930db4fc 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 bb2affc637..2793e65441 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 fbee52c827..e96743b912 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 574444a8f2..950cf8a014 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 1bf3a8d227..ee4cf28af2 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 <andrei.kortunov@yandex.ru> 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 950cf8a014..525749c385 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<MWWorld::Ptr>::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 <andrei.kortunov@yandex.ru> 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 4ed3b82a92..6fac03e922 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<ESM::Dialogue>().find(topic); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef4295047..d0fe5a7557 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1232,13 +1232,17 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits<float>::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 <andrei.kortunov@yandex.ru> 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 d6926f11df..2e16b13aa7 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<MWWorld::Action>(new MWWorld::FailedAction("")); + if(stats.getKnockedDown()) + return std::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("")); + return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr)); } From c5fcb9684efe3c0b41a0d7901af4887d7b9ca003 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 525749c385..da98e7f5f5 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 <andrei.kortunov@yandex.ru> 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 cef4295047..69ccdf9e44 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 <kyleacooley@gmail.com> 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 36ff8cf675..f10525e084 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 0000000000..cf33fab9ec --- /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 0000000000..bbedecb538 --- /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 3cccaaa223..34ecd57d07 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 <kyleacooley@gmail.com> 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 bde5af3d93..fcfc8577e9 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<std::string>& ids) { ImportResults results; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ccc5ac4043..4136061e4e 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<std::string>& 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 a7bea5eb5e..c83c4982b2 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -14,19 +14,15 @@ <Property key="ImagePushed" value="textures\tx_menubook_take_pressed.dds"/> </Widget> - <Widget type="Widget" position="0 0 292 398"> - <Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> - </Widget> + <Widget type="ImageButton" skin="ImageBox" position="205 358 48 32" name="PrevPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_prev_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_prev_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_prev_pressed.dds"/> </Widget> - <Widget type="Widget" position="292 0 292 398"> - <Widget type="ImageButton" skin="ImageBox" position="38 358 48 32" name="NextPageBTN"> - <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> - <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> - <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> - </Widget> + <Widget type="ImageButton" skin="ImageBox" position="330 358 48 32" name="NextPageBTN"> + <Property key="ImageHighlighted" value="textures\tx_menubook_next_over.dds"/> + <Property key="ImageNormal" value="textures\tx_menubook_next_idle.dds"/> + <Property key="ImagePushed" value="textures\tx_menubook_next_pressed.dds"/> </Widget> <Widget type="ImageButton" skin="ImageBox" position="488 358 48 32" name="CloseButton"> From c598f1313c4233af2aec6dcb92e4924408120961 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <nikolaykasyanov@users.noreply.github.com> 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 25e1c95172..86e8fb81b9 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 8dd027c4ac..e13e626aee 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 e96743b912..fdf4da8a77 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 <andrei.kortunov@yandex.ru> 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 a70d833c7e..74ed4fff9c 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 d62cd16b04..4796386725 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 7ced6ae343..c6ecafd46e 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 390bb0586a..ffcf9075eb 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 20955b2065..bc6be8023a 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 238fb59131..ec4b378a04 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 61f0569b5e..1b08ec4856 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 45aa261df3..e294ebe077 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 4731cbb8a6..6ddb019b0d 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 a9930db4fc..af6bf4726b 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<MWWorld::Ptr>(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); + bool isAllowedToUse = checkOwned(); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); } else if (type == "ItemModelIndex") { std::pair<ItemModel::ModelIndex, ItemModel*> pair = *focus->getUserData<std::pair<ItemModel::ModelIndex, ItemModel*> >(); 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<MWGui::ToolTipInfo>(), false); + tooltipSize = createToolTip(*focus->getUserData<MWGui::ToolTipInfo>()); } 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 2793e65441..1ef473b5a9 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 ae3feb61c4..a26294a0e7 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 1bfee9b2ae..cdb949c49f 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 da98e7f5f5..2c7b6a500d 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 fdf4da8a77..a9ca9bd195 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 612470a7e0..bdd2aa0944 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<WindowModal*> mCurrentModals; + std::vector<WindowModal*> 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 a9ca9bd195..9a7a7437a4 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; i<mWindows.size(); ++i) - { - bool visibilityMask = true; - if (i < mVisibilityMask.size()) - visibilityMask = mVisibilityMask[i]; - mWindows[i]->setVisible(visible && visibilityMask); - } + mWindows[i]->setVisible(visible); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bdd2aa0944..c8bc8d21e6 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<WindowBase*> mWindows; - std::vector<bool> 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 9a7a7437a4..eae706ec3a 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 d1118848b6..9a9a1ae01a 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -2,6 +2,7 @@ #include <MyGUI_RenderManager.h> #include <MyGUI_ImageBox.h> +#include <MyGUI_Gui.h> 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<MyGUI::ImageBox>(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 88dd0c57b1..79bea30e5e 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 eae706ec3a..504bef964f 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 f22d825dd1..4753c39f2c 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -50,6 +50,8 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mSceneImage = MyGUI::Gui::getInstance().createWidgetReal<BackgroundImage>("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 2f8831fdc5..8536972a37 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<std::string> mSplashScreens; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7c7cdb63e0..7586bb66a7 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 cd8a9f7608..5e4a74978f 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <MyGUI type="Layer" version="1.0"> + <Layer name="Scene" overlapped="false" pick="false"/> <Layer name="Overlay" overlapped="false" pick="false"/> <Layer name="AdditiveOverlay" type="AdditiveLayer" pick="false"/> <Layer name="HUD" overlapped="false" pick="true"/> 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 423dbb0360..6a290bef1b 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 a51124705b..0a87b6600d 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 00e4e30a58..5017b88932 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 1beb9ee16d..82553d22e4 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 504bef964f..a81c3a6146 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 e6acbbd522..06ebeb0b8b 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 c831652395..0a27cf257a 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 2b06de2956..d271852047 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<MyGUI::Window>(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<MyGUI::Widget*>& results) { @@ -24,18 +29,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector<MyGUI::Widget*>& 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<MyGUI::Window>(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 <andrei.kortunov@yandex.ru> 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 0715eb1771..a144911c51 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 b599b35839..77141f2692 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 851abf4089..49991c1646 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 <andrei.kortunov@yandex.ru> 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 af6bf4726b..b2991a0344 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<MWWorld::Ptr>(); - 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 a81c3a6146..ccdd6916c0 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 <kyleacooley@gmail.com> 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 e36e386c9e..f1025acb92 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<typename ESXRecordT> struct MapColourColumn : public Column<ESXRecordT> { - /// \todo Replace Display_Integer with something that displays the colour value more directly. MapColourColumn() : Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Colour) {} virtual QVariant get (const Record<ESXRecordT>& 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<ESXRecordT>& record, const QVariant& data) { - ESXRecordT record2 = record.get(); - - QColor colour = data.value<QColor>(); - - 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 1a89fc675e..15a07b42cf 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<QColor>()); + 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 <andrei.kortunov@yandex.ru> 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 4796386725..9f7a9965c3 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<ItemStack>::iterator itemStack = mItems.begin(); for (; itemStack != mItems.end(); ++itemStack) { From dc127fbb93316865f8023977ccb29b91b8f3ad5b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" <ace@haxalot.com> 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 0050104cf3..50c0d5455a 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 b6504d223f..04b051e169 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 69a0130591..2edad1f27c 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 <krizdjali+github@gmail.com> 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 14998a3c61..a7f30d7ed3 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 50c0d5455a..2bf2896dad 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 32abbbfbf8..0eefe01e62 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 6573265bd7..08b36017bd 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 88de179039..bb22e047c6 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 ed673c5d6a..49b833e382 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 5ca0d1e832..5833a592fe 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 <krizdjali+github@gmail.com> 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 0eefe01e62..786ac23ed6 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 <krizdjali+github@gmail.com> 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 bb22e047c6..a8b7f1fd22 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 <krizdjali+github@gmail.com> 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 786ac23ed6..ff719d72a7 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 08b36017bd..aac38a7f6b 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 a8b7f1fd22..b8ade0a674 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 <krizdjali+github@gmail.com> 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 aac38a7f6b..ed1023c5de 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 <krizdjali+github@gmail.com> 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 ed1023c5de..5e6efaa0f5 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 <krizdjali+github@gmail.com> 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 5e6efaa0f5..18b410d3e7 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 <krizdjali+github@gmail.com> 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 18b410d3e7..c3ba197e4a 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 <krizdjali+github@gmail.com> 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 c3ba197e4a..5f66705e74 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 <krizdjali+github@gmail.com> 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 b8ade0a674..e9b992e02d 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 <golebiewski96@gmail.com> 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 9fbb82dbac..e9e518c7d2 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 77141f2692..7c3271cc20 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 <golebiewski96@gmail.com> 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 7c3271cc20..c28e6a1090 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<std::vector<int>, 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<int>::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 <golebiewski96@gmail.com> 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 c28e6a1090..40f9c741ad 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 06ebeb0b8b..a5bb93b6c3 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<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel); mInputManager->warpMouse(static_cast<int>(mGuiCursorX/mInvUiScalingFactor), static_cast<int>(mGuiCursorY/mInvUiScalingFactor)); + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } } if (mMouseLookEnabled) From 83a5c7c3d87f4e5740b67f271c6007ad16f73d8f Mon Sep 17 00:00:00 2001 From: glbwsk <golebiewski96@gmail.com> 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 e9e518c7d2..672c3ec189 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 40f9c741ad..50ee97d1c1 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<std::vector<int>, 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<int>::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 02eb30da06..839a04e42b 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 <andrei.kortunov@yandex.ru> 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 a808b82853..a09436d148 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 3a918cf19b..9f8ad94e1e 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -380,6 +380,7 @@ static std::map<short,std::string> 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 11d7466a81..9fa5927ac9 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 <kyleacooley@gmail.com> 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 | 161 ++++++--------------- apps/opencs/model/tools/mergestages.hpp | 37 ++--- 3 files changed, 65 insertions(+), 137 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9b595046a6..cbd2abe0d7 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 176d359141..eea0656b70 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) +int CSMTools::PopulateLandTexturesMergeStage::setup() { - const CSMWorld::Record<CSMWorld::Land>& 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<uint16_t, int> key; - key.second = land.mPlugin; - - for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i) - { - key.first = data->mTextures[i]; - - mState.mTextureIndices[key] = -1; - } - } - } -} - - -CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) -: mState (state), mNext (mState.mTextureIndices.end()) -{} - -int CSMTools::MergeLandTexturesStage::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<CSMWorld::LandTexture>& 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<CSMWorld::LandTexture> 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); - - CSMWorld::Land newLand (land); - - newLand.mPlugin = 0; - - if (land.mDataTypes & ESM::Land::DATA_VTEX) - { - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) - { - std::pair<uint16_t, int> key; - key.second = land.mPlugin; - - for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i) - { - key.first = data->mTextures[i]; - std::map<std::pair<uint16_t, int>, int>::const_iterator iter = - mState.mTextureIndices.find (key); - - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; - } - } - } - - CSMWorld::Record<CSMWorld::Land> newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); - - mState.mTarget->getData().getLand().appendRecord (newRecord); + mState.mTarget->getData().getLand().appendRecord (record); + } +} + + +CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} + +int CSMTools::FixLandsAndLandTexturesMergeStage::setup() +{ + // We will have no more than the source + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + if (stage < mState.mTarget->getData().getLand().getSize()) + { + CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&>( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + + CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + + std::string id = mState.mTarget->getData().getLand().getId(stage); + + 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 f88f5be9f6..96339ed4cc 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -116,29 +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); - - 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. - }; - - class MergeLandTexturesStage : public CSMDoc::Stage - { - MergeState& mState; - std::map<std::pair<uint16_t, int>, int>::iterator mNext; - - public: - - MergeLandTexturesStage (MergeState& state); + PopulateLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -161,6 +146,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + /// Flattens the added land and land texture records. + class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + FixLandsAndLandTexturesMergeStage (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 98c38ad7d1201fe951d8c94ffcff4175f7c90875 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 cbd2abe0d7..b15b4b83f1 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 eea0656b70..897c3329c5 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<CSMWorld::Land>& oldRecord = + mState.mTarget->getData().getLand().getRecord (stage); + + CSMWorld::Record<CSMWorld::Land> 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 96339ed4cc..9a16e03ab1 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 <kyleacooley@gmail.com> 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 fcfc8577e9..3e503a80cf 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 441fd82123..000a833cf7 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<osg::Image> 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<osg::Image> 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; s<image->s(); ++s) + for (int t=0; t<image->t(); ++t) + for (int r=0; r<image->r(); ++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 <kyleacooley@gmail.com> 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 18da81b53c..49e4bebe6a 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 f3f72e88ad..a91dfe3d3d 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 7be954b3eb..2163c30fc7 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?= <tastyfish@sznam.cz> 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 3826fd5f62..37abb1ec34 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 178c753c68..0603c18a19 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -39,6 +39,7 @@ #include <components/sceneutil/statesetupdater.hpp> #include <components/sceneutil/controller.hpp> #include <components/sceneutil/visitor.hpp> +#include <components/nifosg/particle.hpp> #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<osgParticle::BoxPlacer> 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 59a8ddc4e0..37c999563f 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,8 @@ #include <osg/ref_ptr> #include <osg/Vec4f> +#include <apps/openmw/mwrender/renderingmanager.hpp> + 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<osg::Group> mRootNode; osg::ref_ptr<osg::Group> mEarlyRenderBinRoot; From 33a1459b11b3efca1ed566f8d58f3f3c16871648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= <tastyfish@sznam.cz> 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 0603c18a19..cce2e1b1d9 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<osgParticle::BoxPlacer> 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 37c999563f..fdcd27e5a3 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -177,7 +177,7 @@ namespace MWRender osg::ref_ptr<osg::Group> mRootNode; osg::ref_ptr<osg::Group> mEarlyRenderBinRoot; - osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode; + osg::ref_ptr<osg::Group> mParticleNode; osg::ref_ptr<osg::Node> mParticleEffect; std::vector<osg::ref_ptr<AlphaFader> > mParticleFaders; osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 62360b9d64..547b710348 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 7a2377f9d7..df93d5cede 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 74b9be63df..202e6373e6 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 209f2d9bd3..973f44646c 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?= <tastyfish@sznam.cz> 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 | 65 ++++++++++++++--------- apps/openmw/mwrender/sky.hpp | 7 +-- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 37abb1ec34..3826fd5f62 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 cce2e1b1d9..81494d8e2b 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(); - osg::Vec3 cameraOffset = osg::Vec3( - mRangeX - fmod(cameraPos.x(), mRangeX / 2), - mRangeY - fmod(cameraPos.y(), mRangeY / 2), - 0); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); - 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); + osg::Vec3 cameraOffset = osg::Vec3( + fmod(cameraPos.x(), mRangeX), + fmod(cameraPos.y(), mRangeY), + 0.0); - for(int i = 0; i < ps->numParticles(); i++) - ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); + std::vector<osg::Vec3> positionBackups; - ps->drawImplementation(renderInfo); + 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()); + + 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)); + } + + 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<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1422,7 +1432,8 @@ void SkyManager::createRain() emitter->setPlacer(placer); osg::ref_ptr<osgParticle::ConstantRateCounter> counter (new osgParticle::ConstantRateCounter); - counter->setNumberOfParticlesPerSecondToCreate(600.0); +// counter->setNumberOfParticlesPerSecondToCreate(600.0); + counter->setNumberOfParticlesPerSecondToCreate(2000); emitter->setCounter(counter); osg::ref_ptr<RainShooter> 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 fdcd27e5a3..59a8ddc4e0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,8 +9,6 @@ #include <osg/ref_ptr> #include <osg/Vec4f> -#include <apps/openmw/mwrender/renderingmanager.hpp> - 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<osg::Group> mRootNode; osg::ref_ptr<osg::Group> mEarlyRenderBinRoot; - osg::ref_ptr<osg::Group> mParticleNode; + osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode; osg::ref_ptr<osg::Node> mParticleEffect; std::vector<osg::ref_ptr<AlphaFader> > mParticleFaders; osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch; From 38bfa64100414a4ab76c71805a569185c6cd8485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= <tastyfish@sznam.cz> 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 81494d8e2b..de1fb780cf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1361,24 +1361,38 @@ public: std::vector<osg::Vec3> positionBackups; + osg::Matrix toWorld, toLocal; + + toWorld.makeIdentity(); + toLocal.makeIdentity(); + + std::vector<osg::Matrix> worldMatrices = drawable->getWorldMatrices(); + + if (!worldMatrices.empty()) + { + toWorld = worldMatrices[0]; + toLocal.invert(toWorld); + } + for (int i = 0; i < ps->numParticles(); i++) - { - osgParticle::Particle *particle = ps->getParticle(i); + { + osgParticle::Particle *particle = ps->getParticle(i); + positionBackups.push_back(particle->getPosition()); + particle->setPosition(toWorld.preMult(particle->getPosition())); + particle->setPosition(particle->getPosition() - cameraOffset); - positionBackups.push_back(particle->getPosition()); + 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)); - particle->setPosition(particle->getPosition() - cameraOffset); + 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().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<osgParticle::ConstantRateCounter> counter (new osgParticle::ConstantRateCounter); -// counter->setNumberOfParticlesPerSecondToCreate(600.0); - counter->setNumberOfParticlesPerSecondToCreate(2000); + counter->setNumberOfParticlesPerSecondToCreate(600.0); emitter->setCounter(counter); osg::ref_ptr<RainShooter> 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?= <tastyfish@sznam.cz> 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 de1fb780cf..fb3e477bbc 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<osg::Vec3> 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 202e6373e6..2f6123e34d 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 973f44646c..265fd6d02a 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<osg::Node *> 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?= <tastyfish@sznam.cz> Date: Thu, 12 Oct 2017 15:28:54 +0200 Subject: [PATCH 413/521] wrap weather around in all directions --- apps/openmw/mwrender/sky.cpp | 86 +++++++++++++++++----------------- components/nifosg/particle.cpp | 5 -- components/nifosg/particle.hpp | 1 - 3 files changed, 44 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index fb3e477bbc..eaa93ab886 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,6 +18,8 @@ #include <osg/PolygonOffset> #include <osg/observer_ptr> +#include <OpenThreads/ReadWriteMutex> + #include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystemUpdater> #include <osgParticle/ModularEmitter> @@ -39,7 +41,6 @@ #include <components/sceneutil/statesetupdater.hpp> #include <components/sceneutil/controller.hpp> #include <components/sceneutil/visitor.hpp> -#include <components/nifosg/particle.hpp> #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<osg::Material> createAlphaTrackingUnlitMaterial() { osg::ref_ptr<osg::Material> 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<osg::Vec3> positionBackups; osg::Matrix toWorld, toLocal; - toWorld.makeIdentity(); - toLocal.makeIdentity(); - std::vector<osg::Matrix> 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); + { + 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)); + for (int j = 0; j < 3; j++) // wrap-around effect in all 3 directions + { + osg::Vec3 newPosition = particle->getPosition(); - 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)); + 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(toLocal.preMult(particle->getPosition())); + 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<osgParticle::BoxPlacer> 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<osgParticle::ParticleSystem *>(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 547b710348..62360b9d64 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 df93d5cede..7a2377f9d7 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?= <tastyfish@sznam.cz> 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 3826fd5f62..aa7b35b440 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 eaa93ab886..1338a127c0 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,8 +18,6 @@ #include <osg/PolygonOffset> #include <osg/observer_ptr> -#include <OpenThreads/ReadWriteMutex> - #include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystemUpdater> #include <osgParticle/ModularEmitter> @@ -27,6 +25,9 @@ #include <osgParticle/ConstantRateCounter> #include <osgParticle/RadialShooter> +#include <osgParticle/Operator> +#include <osgParticle/ModularProgram> + #include <components/misc/rng.hpp> #include <components/misc/resourcehelpers.hpp> @@ -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; + virtual osg::Object *clone(const osg::CopyOp &op) const override + { + return NULL; + } - osgParticle::ParticleSystem::ScopedReadLock *lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); + virtual void operate(osgParticle::Particle *P, double dt) override + { + } - osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); - - osg::Vec3 cameraOffset = osg::Vec3( - fmod(cameraPos.x(), mWrapRange.x()), - fmod(cameraPos.y(), mWrapRange.y()), - fmod(cameraPos.z(), mWrapRange.z())); - - std::vector<osg::Vec3> 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<osg::Matrix> worldMatrices = drawable->getWorldMatrices(); - + std::vector<osg::Matrix> 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<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1463,6 +1472,11 @@ void SkyManager::createRain() osg::ref_ptr<osgParticle::ParticleSystemUpdater> updater (new osgParticle::ParticleSystemUpdater); updater->addParticleSystem(mRainParticleSystem); + osg::ref_ptr<osgParticle::ModularProgram> 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<osgParticle::ParticleSystem *>(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<osgParticle::ParticleSystem *>(findPSVisitor.mFoundNodes[i]); + + osg::ref_ptr<osgParticle::ModularProgram> 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 59a8ddc4e0..097405b248 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,11 @@ #include <osg/ref_ptr> #include <osg/Vec4f> +namespace osg +{ + class Camera; +} + namespace osg { class Group; @@ -161,6 +166,8 @@ namespace MWRender void listAssetsToPreload(std::vector<std::string>& models, std::vector<std::string>& 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<osg::Group> mRootNode; osg::ref_ptr<osg::Group> mEarlyRenderBinRoot; From 28ff677337f9e6231a6be62cc4ec79aca6d3dd73 Mon Sep 17 00:00:00 2001 From: AnyOldName3 <krizdjali+github@gmail.com> 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 a897806c2a..a1b5cc99ee 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 <krizdjali+github@gmail.com> 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 a1b5cc99ee..62aa034ee9 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<QString, QString> // 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 5316255ad7..7c3956a293 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 <krizdjali+github@gmail.com> 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 62aa034ee9..0ea28dceb4 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -126,6 +126,7 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap<QString, QString> 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 <andrei.kortunov@yandex.ru> 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 2c7b6a500d..dfbcf0ea2b 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 6606b02902..d173ef6f29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,8 @@ addons: project: name: "OpenMW/openmw" description: "<Your project description here>" - 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 49f5340658..bb70d7d373 100644 --- a/extern/osg-ffmpeg-videoplayer/License.txt +++ b/extern/osg-ffmpeg-videoplayer/License.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 Jannik Heller <scrawl@baseoftrash.de>, 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 c1a7eb8f38..53b08b8be0 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -141,10 +141,7 @@ osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string & node->accept(visitor); shape = visitor.getShape(); if (!shape) - { - mCache->addEntryToObjectCache(normalized, NULL); return osg::ref_ptr<BulletShape>(); - } } mCache->addEntryToObjectCache(normalized, shape); @@ -158,7 +155,8 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(const std::s mVFS->normalizeFilename(normalized); osg::ref_ptr<BulletShapeInstance> 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 266139f3cf..d6639d3aec 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<OpenThreads::Mutex> lock(_objectCacheMutex); _objectCache.insert(std::make_pair(filename, object)); } diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index de0fa7a404..e8c082f91b 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<OpenThreads::Mutex> 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 6a290bef1b..43e5111447 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 887189a851..7f880d7166 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 97a0e8b370..5e362e9b50 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<std::string> mKeywords; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1db2691f4a..23eb499dee 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 3542f3ebfe..73428c034c 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 649aab3f23..3414c1b940 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 bf505b00fd..d3d487579d 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 7f412b4d27..255874d881 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 54ad75135a..13cd4232db 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 12961dc4b8..8b93ca2040 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 7f880d7166..34932e3608 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 3865b17a5d..9e9fe3759a 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -49,7 +49,7 @@ BulletNifLoader::~BulletNifLoader() { } -osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr nif) +osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr& nif) { mShape = new Resource::BulletShape; diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index a30bf8fdf1..fff51933fe 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -50,7 +50,7 @@ public: abort(); } - osg::ref_ptr<Resource::BulletShape> load(const Nif::NIFFilePtr file); + osg::ref_ptr<Resource::BulletShape> 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 8810f171a2..a3b81338e5 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<unsigned int> mipmapVector; for (unsigned int i=0; i<pixelData->mipmaps.size()-3; ++i) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 53b08b8be0..a3d09311a5 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<GetTriangleFunctor> functor; - functor.setTriMesh(mTriangleMesh); + functor.setTriMesh(mTriangleMesh.get()); functor.setMatrix(worldMat); drawable.accept(functor); } @@ -86,14 +86,12 @@ public: return osg::ref_ptr<BulletShape>(); osg::ref_ptr<BulletShape> 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<btTriangleMesh> mTriangleMesh; }; BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 3add3bb236..eec302965b 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 d8fefdb291..1090997404 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 cc40506f00..2cd1ec806d 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 ab801ab82f..9c5a2a14e8 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -244,12 +244,9 @@ namespace Resource void SceneManager::recreateShaders(osg::ref_ptr<osg::Node> 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<Shader::ShaderVisitor> 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<Shader::ShaderVisitor> 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 b223353c29..4f1523eced 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<Shader::ShaderManager> mShaderManager; bool mForceShaders; bool mClampLighting; From 654bd401fb9e005fef5bc2c243386616e2dc2123 Mon Sep 17 00:00:00 2001 From: AnyOldName3 <krizdjali+github@gmail.com> 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 86c87962dd..334674aa76 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -90,16 +90,16 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options"); desc.add_options() - ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("data-local", boost::program_options::value<std::string>()->default_value("")) + ("data", boost::program_options::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing()) + ("data-local", boost::program_options::value<Files::EscapeHashString>()->default_value("")) ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value<std::string>()->default_value("win1252")) - ("resources", boost::program_options::value<std::string>()->default_value("resources")) - ("fallback-archive", boost::program_options::value<std::vector<std::string> >()-> - default_value(std::vector<std::string>(), "fallback-archive")->multitoken()) + ("encoding", boost::program_options::value<Files::EscapeHashString>()->default_value("win1252")) + ("resources", boost::program_options::value<Files::EscapeHashString>()->default_value("resources")) + ("fallback-archive", boost::program_options::value<Files::EscapeStringVector>()-> + default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken()) ("fallback", boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") - ("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "") + ("script-blacklist", boost::program_options::value<Files::EscapeStringVector>()->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<bool>()->implicit_value(true) ->default_value(true), "enable script blacklisting"); @@ -109,24 +109,24 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi mCfgMgr.readConfiguration(variables, desc, quiet); mDocumentManager.setEncoding ( - ToUTF8::calculateEncoding (variables["encoding"].as<std::string>())); + ToUTF8::calculateEncoding (variables["encoding"].as<Files::EscapeHashString>().toStdString())); - mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>()); + mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString()); mDocumentManager.setFallbackMap (variables["fallback"].as<FallbackMap>().mMap); if (variables["script-blacklist-use"].as<bool>()) mDocumentManager.setBlacklistedScripts ( - variables["script-blacklist"].as<std::vector<std::string> >()); + variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector()); mFsStrict = variables["fs-strict"].as<bool>(); Files::PathContainer dataDirs, dataLocal; if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>()); + dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>())); } - std::string local = variables["data-local"].as<std::string>(); + std::string local = variables["data-local"].as<Files::EscapeHashString>().toStdString(); if (!local.empty()) { dataLocal.push_back(Files::PathContainer::value_type(local)); } @@ -157,7 +157,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi mFileDialog.addFiles(path); } - return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string> >()); + return std::make_pair (dataDirs, variables["fallback-archive"].as<Files::EscapeStringVector>().toStdStringVector()); } void CS::Editor::createGame() From 6d7a24224b489c6fee804fc3d05350e615c77046 Mon Sep 17 00:00:00 2001 From: Kyle Cooley <kyleacooley@gmail.com> 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 9a16e03ab1..4b41c5a04f 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 be86dd5080..58a1b1d1c5 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<std::string> 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?= <tastyfish@seznam.com> 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 aa7b35b440..7585ee32a6 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 43059ab6d4..f9e98b2693 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 1338a127c0..cffa9909af 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<osg::ref_ptr<AlphaFader> >::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 097405b248..816dbf7980 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -8,6 +8,7 @@ #include <osg/ref_ptr> #include <osg/Vec4f> +#include <osg/Uniform> 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<osg::Group> mRootNode; osg::ref_ptr<osg::Group> mEarlyRenderBinRoot; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab6..8935eb37a1 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 33b314c511..6c7adac37d 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -6,6 +6,7 @@ #include <osg/ref_ptr> #include <osg/Vec3f> +#include <osg/Uniform> #include <components/settings/settings.hpp> @@ -50,6 +51,8 @@ namespace MWRender { static const int CELL_SIZE = 8192; + osg::Uniform* mRainIntensityUniform; + osg::ref_ptr<osg::Group> mParent; osg::ref_ptr<osg::Group> mSceneRoot; osg::ref_ptr<osg::PositionAttitudeTransform> 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?= <tastyfish@seznam.com> 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 cffa9909af..05937742f8 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<osg::Material*>(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<SceneUtil::CompositeStateSetUpdater*>(callback))) break; + callback = callback->getNestedCallback(); } - osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader); + osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader(mRainIntensityUniform)); if (composite) composite->addController(alphaFader); @@ -1312,10 +1320,12 @@ public: private: std::vector<osg::ref_ptr<AlphaFader> > 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<SceneUtil::ControllerSource>(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?= <tastyfish@seznam.com> 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 7585ee32a6..6c4cc802b7 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 f9e98b2693..f0087e43d2 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 05937742f8..97633a6b92 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<osg::Material*>(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> alphaFader (new AlphaFader(mRainIntensityUniform)); + osg::ref_ptr<AlphaFader> 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<osg::ref_ptr<AlphaFader> > 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<SceneUtil::ControllerSource>(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 816dbf7980..4357d468c2 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?= <tastyfish@seznam.com> 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 97633a6b92..6c599fc3fa 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 8935eb37a1..52b659984e 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 6c7adac37d..a4fd1ed367 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<osg::Uniform> mRainIntensityUniform; osg::ref_ptr<osg::Group> mParent; osg::ref_ptr<osg::Group> mSceneRoot; From 4d4d247565338db653111fe92deb23c099966d3a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov <andrei.kortunov@yandex.ru> 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 ec65255bc1..03acfdaf22 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 <krizdjali+github@gmail.com> 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 9e44f237e0..ac891b9804 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<Files::EscapeHashString>().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 <krizdjali+github@gmail.com> 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 334674aa76..35ce513379 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -127,7 +127,11 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi } std::string local = variables["data-local"].as<Files::EscapeHashString>().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 <krizdjali+github@gmail.com> 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 774753b6ce..c130c9d5b9 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<int, int>& contentFileMap); + const std::map<int, int>& 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<ESM::ESMReader>& 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<DoorMarker>& out); + virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& 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<char> &chances); + virtual void modRegion(const std::string ®ionid, const std::vector<char> &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<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &targets); + virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &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<MWWorld::Ptr>& out); + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out); + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& 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<std::string>& getContentFiles() const; + virtual const std::vector<std::string>& 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<MWWorld::Ptr>& 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 <krizdjali@gmail.com> 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 c130c9d5b9..83b81d22c3 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<ESM::ESMReader>& getEsmReader(); + virtual std::vector<ESM::ESMReader>& getEsmReader() override; virtual LocalScripts& getLocalScripts() override; From 7440cf37bc96556771f5cf21fc591e8cc9d2505b Mon Sep 17 00:00:00 2001 From: AnyOldName3 <krizdjali@gmail.com> 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 83b81d22c3..784c015930 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<int, int>& 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<ESM::ESMReader>& getEsmReader() override; + std::vector<ESM::ESMReader>& 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<DoorMarker>& out) override; + void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& 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<char> &chances) override; + void modRegion(const std::string ®ionid, const std::vector<char> &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<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &targets) override; + std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &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<MWWorld::Ptr>& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& 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<std::string>& getContentFiles() const override; + const std::vector<std::string>& 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<MWWorld::Ptr>& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& 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 <krizdjali@gmail.com> 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 784c015930..d7fec2fec2 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 <krizdjali+github@gmail.com> 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 2bf2896dad..b47678e7d5 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 <kyleacooley@gmail.com> 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 7257b2fe3c..7a825ba39d 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 <sean.stach@gmail.com> 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 50ee97d1c1..3d3c8e4ef5 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 <golebiewski96@gmail.com> 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 735bf36825..2f3099c09a 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 5576b52ed0..dde46558f8 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 <krizdjali+github@gmail.com> 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 d7fec2fec2..5b772b4b1a 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<MWWorld::Ptr>& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out) override; ///< get all containers in active cells owned by this Npc - void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector<MWWorld::Ptr>& 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<std::string>& getContentFiles() const override; + const std::vector<std::string>& 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<MWWorld::Ptr>& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& 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 <krizdjali+github@gmail.com> 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 5b772b4b1a..7af7b29688 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 <golebiewski96@gmail.com> 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 2f3099c09a..d0af00e5f8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,5 @@ #include "inventorywindow.hpp" -#include <stdexcept> - #include <MyGUI_Window.h> #include <MyGUI_ImageBox.h> #include <MyGUI_RenderManager.h> @@ -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 dde46558f8..5576b52ed0 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 <andrei.kortunov@yandex.ru> 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 3d3c8e4ef5..ba3ea23817 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 <andrei.kortunov@yandex.ru> 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 e13e626aee..39c73a23d4 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 5e362e9b50..472996a6c7 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 <golebiewski96@gmail.com> 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 d0af00e5f8..b3697008c8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,5 +1,7 @@ #include "inventorywindow.hpp" +#include <stdexcept> + #include <MyGUI_Window.h> #include <MyGUI_ImageBox.h> #include <MyGUI_RenderManager.h> @@ -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 <marcin@baszczewski.pl> 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 0ea28dceb4..b35612ee4d 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 6fac03e922..acfe7f5eeb 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 d9c622120c..a914d9a3e3 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -8,6 +8,7 @@ #include <components/compiler/streamerrorhandler.hpp> #include <components/translation/translation.hpp> +#include <components/misc/stringops.hpp> #include "../mwworld/ptr.hpp" @@ -22,13 +23,13 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::set<std::string> mKnownTopics;// Those are the topics the player knows. + std::set<std::string, Misc::StringUtils::CiComp> mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. <Faction1, <Faction2, Difference> > typedef std::map<std::string, std::map<std::string, int> > ModFactionReactionMap; ModFactionReactionMap mChangedFactionReaction; - std::set<std::string> mActorKnownTopics; + std::set<std::string, Misc::StringUtils::CiComp> 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 27a3b31b52..41eaed0809 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" <ace@haxalot.com> 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 a7f30d7ed3..39cb37bed2 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 376a28aa76..7c89c49793 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 c928fa9405..a9afae7867 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<std::string, std::string> 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<std::string> 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 acfe7f5eeb..88e65e535a 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<ESM::Dialogue> &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 a914d9a3e3..f267f7542d 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<Interpreter::Type_Code>& 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<std::string> 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 39c73a23d4..8a7ae85ea7 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<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); - 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<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) + delete (*it); + mHistoryContents.clear(); + mKeywords.clear(); + mTopicsList->clear(); + for (std::vector<Link*>::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<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); - mHistoryContents.clear(); - - mKeywords.clear(); - updateTopicsPane(); - } - - for (std::vector<Link*>::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 472996a6c7..2770325137 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<const std::string&, const std::string&> EventHandle_Result; - EventHandle_Result eventPersuadeMsg; + PersuasionDialog(ResponseCallback* callback); virtual void onOpen(); virtual MyGUI::Widget* getDefaultKeyFocus(); private: + std::unique_ptr<ResponseCallback> 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<ResponseCallback> mCallback; + std::unique_ptr<ResponseCallback> 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 851a6a29c5..e999097db3 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 98b1a6b47c..1067b55361 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -131,16 +131,14 @@ namespace MWScript } }; + template <class R> class OpOnActivate : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast<InterpreterContext&> (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<ImplicitRef>); + interpreter.installSegment5 (Compiler::Misc::opcodeOnActivateExplicit, new OpOnActivate<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeActivateExplicit, new OpActivate<ExplicitRef>); interpreter.installSegment3 (Compiler::Misc::opcodeLock, new OpLock<ImplicitRef>); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index eb3e1e4eee..cd5bf7ef73 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 b2333032b3..6a6552467b 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?= <tastyfish@seznam.com> 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 6c4cc802b7..4fbcdc4d52 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 52b659984e..c4dffb7a4d 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<osg::Shader> fragmentShader (shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT)); osg::ref_ptr<osg::Texture2D> 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<osg::Program> 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 41eaed0809..b56db1ebd6 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 <krizdjali@gmail.com> 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 e9b992e02d..e9c8726289 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 <krizdjali@gmail.com> 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 5f66705e74..fe2837a09d 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 e9c8726289..fb78bd4323 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 <krizdjali@gmail.com> 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 fb78bd4323..a0b426a163 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 <psi29a@gmail.com> 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 b47678e7d5..f4b912c709 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?= <tastyfish@seznam.com> 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 34932e3608..36041a85e5 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?= <tastyfish@seznam.com> 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 03acfdaf22..dc910c577f 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 af90c18b80..c03702ef22 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?= <tastyfish@seznam.com> 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 dc910c577f..83c7ce8442 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 <rexelion@users.noreply.github.com> 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 7bdeba132c..44d3501154 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<int, int> compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 7c1f9bf4df..01ff97be27 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<ESM::Script>().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 c22a5da81f..3835be26e4 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<int, int> compileAll(); ///< Compile all scripts /// \return count, success From 4e6f53d6f16572086ad1c0d5455e16ed3ce359af Mon Sep 17 00:00:00 2001 From: rexelion <rexelion@users.noreply.github.com> 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 b3697008c8..8586cfb5bb 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,6 +1,7 @@ #include "inventorywindow.hpp" #include <stdexcept> +#include <algorithm> #include <MyGUI_Window.h> #include <MyGUI_ImageBox.h> @@ -149,6 +150,15 @@ namespace MWGui mItemView->setModel(NULL); } + void InventoryWindow::activateItems() + { + for (std::vector<MWWorld::Ptr>::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 5576b52ed0..3f88d88226 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<MWWorld::Ptr> mItemsToActivate; + MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c0..e2a10ccc3d 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?= <tastyfish@seznam.com> 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 83c7ce8442..a2e07fc5cf 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 c03702ef22..af90c18b80 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?= <tastyfish@seznam.com> 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 b3697008c8..a92c777605 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 <rexelion@users.noreply.github.com> 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 44d3501154..7bdeba132c 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<int, int> compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8586cfb5bb..5fe644d45d 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 01ff97be27..7c1f9bf4df 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<ESM::Script>().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 3835be26e4..c22a5da81f 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<int, int> compileAll(); ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f6fa3556fa..95b0fb3e0b 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 75eec6742d..4dfa9e91c4 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?= <tastyfish@seznam.cz> 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 a2e07fc5cf..f262850a40 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 <rexelion@users.noreply.github.com> 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 5fe644d45d..1e9f534d6a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,6 @@ #include "inventorywindow.hpp" #include <stdexcept> -#include <algorithm> #include <MyGUI_Window.h> #include <MyGUI_ImageBox.h> @@ -150,15 +149,6 @@ namespace MWGui mItemView->setModel(NULL); } - void InventoryWindow::activateItems() - { - for (std::vector<MWWorld::Ptr>::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 3f88d88226..5576b52ed0 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<MWWorld::Ptr> mItemsToActivate; - MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2a10ccc3d..ccdd6916c0 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 d858859a69..52e30c8ac7 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 <rexelion@users.noreply.github.com> 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 03acfdaf22..c3ca8f512d 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 af90c18b80..0654b85341 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 <rexelion@users.noreply.github.com> 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 c3ca8f512d..dffc095e9c 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 0654b85341..af8415e352 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 <rexelion@users.noreply.github.com> 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 1e9f534d6a..063bc5c016 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 52e30c8ac7..d858859a69 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 95b0fb3e0b..f6fa3556fa 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 4dfa9e91c4..75eec6742d 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 <rexelion@users.noreply.github.com> 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 063bc5c016..e1301edd43 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 <rexelion@users.noreply.github.com> 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 dffc095e9c..deb9daa93c 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 <rexelion@users.noreply.github.com> 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 deb9daa93c..ade9d635bb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,6 +20,7 @@ #include "character.hpp" #include <iostream> +#include <random> #include <components/misc/rng.hpp> @@ -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<int> 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 af8415e352..12b4d6adcb 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?= <tastyfish@seznam.cz> 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 f9884eb6d4..8359664674 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 <rexelion@users.noreply.github.com> 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 ade9d635bb..83d6cc1f37 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,7 +20,6 @@ #include "character.hpp" #include <iostream> -#include <random> #include <components/misc/rng.hpp> @@ -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<int> 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 12b4d6adcb..0b9e60c110 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 839a04e42b..c4190343d6 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?= <tastyfish@seznam.cz> 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 b47678e7d5..507c89c451 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 94a9ed024d..9cecc1d466 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. - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> + {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: - <program> Copyright (C) <year> <name of author> + {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 aa6ae47b4a..3e5556cb49 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 <rexelion@users.noreply.github.com> 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 83d6cc1f37..0f99725fd9 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 0b9e60c110..6de18fe628 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?= <tastyfish@seznam.cz> 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 f262850a40..107ccf09b0 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 <dr.west@zoho.com> 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 f28870c703..3c3d04d518 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<std::string>(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 2017c2ed27..64410f3abc 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?= <tastyfish@seznam.cz> 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 8359664674..27d4ab0cbd 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 <rexelion@users.noreply.github.com> 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 d444989668..df636dd56d 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<ESM::GameSetting>().find("fCombatDistance")->getFloat(); + static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().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 <rexelion@users.noreply.github.com> 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 68d282d0c5..cd9211a3ff 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<Action> 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<Action> 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 <dr.west@zoho.com> 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 9acd817100..12c222036f 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,6 +2,7 @@ #define MISC_STRINGOPS_H #include <cctype> +#include <cstring> #include <string> #include <algorithm> @@ -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 <dr.west@zoho.com> 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 3c3d04d518..93ae9b8851 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,6 +1,6 @@ #include "escape.hpp" -#include <boost/algorithm/string/replace.hpp> +#include <components/misc/stringops.hpp> 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<std::string>(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 64410f3abc..d01bd8d980 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -30,7 +30,6 @@ namespace Files private: std::queue<int> 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 <dr.west@zoho.com> 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 12c222036f..9f4931d72f 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 8aec54835b..640f2932b6 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -116,7 +116,10 @@ namespace Terrain osg::ref_ptr<osg::Shader> vertexShader = shaderManager->getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); osg::ref_ptr<osg::Shader> 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 7cb49c6cb5..5efd1b86ea 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<osg::Shader> 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 a7ad687cb6..61febf3153 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 eb6a556404..2aecb002f8 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 8211c2f5f9..ece57c2735 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<ESM::Light>()->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 cd04a425ba..981f63e346 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 <rexelion@users.noreply.github.com> 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 cd9211a3ff..6e32688317 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -504,13 +504,8 @@ namespace MWMechanics targetWeapon = *weaponSlot; } - std::shared_ptr<Action> 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 <andrei.kortunov@yandex.ru> 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 74ed4fff9c..be3cb15225 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<PickpocketItemModel*>(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 4796386725..ee89f1350b 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -2,12 +2,15 @@ #include <algorithm> +#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 c6ecafd46e..a0dbc2cf9f 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<MWWorld::Ptr> mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 222243ec1d..b807a58f4b 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 f58ee29390..95afeb5d44 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 ffcf9075eb..5a6afdf028 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 bc6be8023a..c4a3a03e83 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 ec4b378a04..e610854c18 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -3,15 +3,24 @@ #include <components/misc/rng.hpp> #include <components/esm/loadskil.hpp> +#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 1b08ec4856..ad8788da78 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<ItemStack> mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index e294ebe077..932f362fba 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 6ddb019b0d..e99726b0f2 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 <andrei.kortunov@yandex.ru> 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 be3cb15225..3fa07b0702 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<ESM::Container>* ref = mPtr.get<ESM::Container>(); - if (ref->mBase->mFlags & ESM::Container::Organic) - { - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - return; - } + bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount); - // 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; - } - } - - 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 ee89f1350b..ef7aa8215b 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; -bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + MWWorld::Ptr target = mItemSources[0]; + + if (target.getTypeName() != typeid(ESM::Container).name()) + return true; + + // check container organic flag + MWWorld::LiveCellRef<ESM::Container>* ref = target.get<ESM::Container>(); + 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 a0dbc2cf9f..fb57096efa 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<MWWorld::Ptr> mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index b807a58f4b..aed08feb15 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 95afeb5d44..c5ca80eed5 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 5a6afdf028..25dce728ae 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 c4a3a03e83..78c646e332 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 e610854c18..ba8fd7d759 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -4,6 +4,7 @@ #include <components/esm/loadskil.hpp> #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 ad8788da78..a759cd993f 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 932f362fba..15c7fbfcb4 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 e99726b0f2..fa8d836b59 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 <andrei.kortunov@yandex.ru> 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 3fa07b0702..03c7b54be3 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<PickpocketItemModel*>(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 50c69da3b6..cf02d165dc 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 ef7aa8215b..8e42b3ebc3 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 fb57096efa..e8d1c53280 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 aed08feb15..c9f55d3520 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 c5ca80eed5..38730bd4d1 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 25dce728ae..c59bc8bf45 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 78c646e332..d50718e5d2 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 ba8fd7d759..b073ef73fa 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 a759cd993f..9aa686c39b 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<ItemStack> mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 15c7fbfcb4..1ee3cf6316 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 fa8d836b59..98da8d8c93 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 <rexelion@users.noreply.github.com> 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 6e32688317..07fb455f3e 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 d1f31c475d..ebfe9b30ff 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -53,18 +53,17 @@ <Property key="TextAlign" value="Center"/> </Widget> - <Widget type="AutoSizedButton" skin="MW_Button" position="0 60 60 24" name="MaxSaleButton" align="Left Top"> - <Property key="Caption" value="#{sMaxSale}"/> - </Widget> - - <Widget type="HBox" position="0 60 566 24" align="Right Bottom"> + <Widget type="HBox" position="0 60 566 24" align="Left Bottom HStretch"> + <Widget type="AutoSizedButton" skin="MW_Button" name="MaxSaleButton"> + <Property key="Caption" value="#{sMaxSale}"/> + </Widget> <Widget type="Widget"> <UserString key="HStretch" value="true"/> </Widget> - <Widget type="AutoSizedButton" skin="MW_Button" name="OfferButton" align="Right Top"> + <Widget type="AutoSizedButton" skin="MW_Button" name="OfferButton"> <Property key="Caption" value="#{sBarterDialog8}"/> </Widget> - <Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton" align="Right Top"> + <Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton"> <Property key="Caption" value="#{sCancel}"/> </Widget> </Widget> 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 a5bb93b6c3..5aa795c109 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 90b69de8e5..a1aa248710 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 5aec80f5d6..8ac78babca 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<osg::Group> parent, const ESM::Light *light); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 735c0b66d3..827b576c33 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 ece57c2735..08e376f083 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 9c5a2a14e8..03b850fac1 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 5aa795c109..9ef5033f0a 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 <andrei.kortunov@yandex.ru> 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 398439ad8d..7a33d6e57f 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 b073ef73fa..4c32eafcd9 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 2c7b6a500d..a4e258ada4 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 ee4cf28af2..baee5233e0 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 <andrei.kortunov@yandex.ru> 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 7a33d6e57f..5fb3bd4007 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 c59bc8bf45..834c351dc8 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<std::string> 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<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); - - for (MWWorld::Store<ESM::GameSetting>::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 a4e258ada4..92031b80be 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<std::string> 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<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); + + for (MWWorld::Store<ESM::GameSetting>::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 baee5233e0..bf3b7c79c1 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 <andrei.kortunov@yandex.ru> 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 03c7b54be3..444eaff85b 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 834c351dc8..e3f38a54c1 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 d50718e5d2..e8e348a8a9 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 4c32eafcd9..e85715e87f 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 9aa686c39b..83caf2ffd4 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 <rexelion@users.noreply.github.com> 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 07fb455f3e..ee1013fe4e 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 <andrei.kortunov@yandex.ru> 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 a144911c51..ce8ad8f664 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1230,8 +1230,13 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits<float>::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 <grigorii.latyshev@cern.ch> 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 27d4ab0cbd..fd8b5752a2 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 103cdcf14d..a58327a481 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -13,6 +13,7 @@ <Property key="TextAlign" value="Left Top"/> <Property key="TextColour" value="1 1 1"/> <Property key="InvertSelected" value="false"/> + <Property key="WordWrap" value="true"/> </Widget> <!-- Command line --> 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 8a7ae85ea7..14bbe81ef6 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 2770325137..2538602c6c 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 88e65e535a..1f6de04e54 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<HyperTextParser::Token> hypertext = HyperTextParser::parseHyperText(text); for (std::vector<HyperTextParser::Token>::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 6de18fe628..016d882891 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 3e5ab7ce62..e2b63232d0 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 bf144bfedd..2fff91c7e5 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?= <tastyfish@seznam.cz> 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 ccdd6916c0..4992716aa2 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 <yeah_piece_of_cake@yahoo.de> 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 25105f1e20..4f2be8c421 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 <andrei.kortunov@yandex.ru> 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 30a440b581..3fbe44f95f 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -203,9 +203,20 @@ namespace int cancelLeft = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left; int cancelRight = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left + getWidget<MyGUI::Widget>(CancelBTN)->getSize().width; - getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); getWidget<MyGUI::Widget>(QuestsBTN)->setPosition(cancelRight, getWidget<MyGUI::Widget>(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<MyGUI::Widget>(TopicsBTN)->getSize().width == 64) + { + getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().left; + getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget<MyGUI::Widget>(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 6e884a0910..ee2c30a7ba 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 ebfe9b30ff..4e2fc6e6d6 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -43,9 +43,11 @@ <Widget type="Button" skin="MW_Button" position="0 0 40 24" name="IncreaseButton" align="Left Top"> <Property key="Caption" value="+"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="Button" skin="MW_Button" position="0 28 40 24" name="DecreaseButton" align="Left Top"> <Property key="Caption" value="-"/> + <Property key="NeedKey" value="false"/> </Widget> <Widget type="TextBox" skin="SandText" position="48 0 140 24" name="TotalBalanceLabel" align="Left Top "/> 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 8a1bf1347b..a8e5431fbf 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -76,9 +76,7 @@ <Widget type="HBox" skin="" position="110 374 452 24" align="Bottom Right"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="CreateButton"> <Property key="Caption" value="#{sCreate}"/> diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index d93249c033..a137d83d13 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -17,9 +17,7 @@ <!-- Dialog buttons --> <Widget type="HBox" position="0 338 511 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="BackButton"> <Property key="Caption" value="#{sBack}"/> </Widget> diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index d875fae22f..98c8e4fded 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -74,9 +74,7 @@ <!-- Dialog buttons --> <Widget type="HBox" position="0 276 475 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="BackButton"> <Property key="Caption" value="#{sBack}"/> </Widget> diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index e2920c7423..c04cfe0646 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -75,9 +75,7 @@ <!-- Dialog buttons --> <Widget type="HBox" position="0 158 482 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="DescriptionButton"> <Property key="Caption" value="#{sCreateClassMenu1}"/> </Widget> diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 04bd9cc538..31f0436d57 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -76,9 +76,7 @@ <!-- Dialog buttons --> <Widget type="HBox" position="0 393 572 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" position="471 397 53 23" name="BackButton"> <Property key="Caption" value="#{sBack}"/> diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 1099fcd3b7..927296fadc 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -112,9 +112,7 @@ <!-- Dialogue Buttons --> <Widget type="HBox" position="0 388 525 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="BackButton"> <Property key="Caption" value="#{sBack}"/> </Widget> diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 376e87efae..c2429d24bf 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -94,9 +94,7 @@ </Widget> <Widget type="HBox" position="8 266 336 24"> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="DeleteButton"> <Property key="Caption" value="#{sDelete}"/> diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index 7039c719e7..edf53bde75 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -16,9 +16,7 @@ <Widget type="HBox" position="13 200 303 24"> <Property key="Spacing" value="6"/> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="DeleteButton"> <Property key="Caption" value="#{sDelete}"/> </Widget> diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 6a08e6fd03..ed3cfb03e8 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -36,9 +36,7 @@ <Widget type="ItemWidget" skin="MW_ItemIconBox" position="0 0 50 50" name="ItemBox"> </Widget> - <Widget type="Widget" position="0 0 8 0"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedTextBox" skin="NormalText"> <Property key="Caption" value="#{sSoulGem}"/> @@ -141,9 +139,7 @@ <UserString key="Caption_Text" value="#{sEnchantmentHelp7}"/> </Widget> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedTextBox" skin="NormalText" name="PriceTextLabel"> <Property key="Caption" value="#{sBarterDialog7}"/> diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 66855373ae..7849d507f6 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -156,9 +156,7 @@ <Widget type="HBox" skin="" position="0 0 330 24"> <UserString key="HStretch" value="true"/> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" position="0 0 0 24" name="OkButton"> <Property key="Caption" value="#{sOk}"/> </Widget> diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 200d345e33..6260390653 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -27,9 +27,7 @@ </Widget> </Widget> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton"> <Property key="Caption" value="#{sCancel}"/> diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index abc429594d..bf58b6c811 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -34,9 +34,7 @@ </Widget> </Widget> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton"> <Property key="Caption" value="#{sCancel}"/> diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index e14674ad60..e7c27655d1 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -68,9 +68,7 @@ <Widget type="HBox" position="0 336 558 60"> <Property key="Padding" value="16"/> - <Widget type="Widget" position="0 0 0 0"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedTextBox" skin="NormalText"> <Property key="Caption" value="#{sBarterDialog7}"/> diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index c038066f13..bdc224ecd4 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -103,9 +103,7 @@ <Widget type="VBox"> <UserString key="VStretch" value="true"/> <Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HandToHandImage"/> - <Widget type="Widget"> - <UserString key="VStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> </Widget> <Widget type="AutoSizedTextBox" skin="SandText" position="44 8 248 284" align="Left Top" name="HandToHandText"> @@ -122,9 +120,7 @@ <Widget type="VBox"> <UserString key="VStretch" value="true"/> <Widget type="ImageBox" skin="ImageBox" position="8 8 32 32" align="Left Top" name="HealthImage"/> - <Widget type="Widget"> - <UserString key="VStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> </Widget> <Widget type="AutoSizedEditBox" skin="SandText" position="44 8 392 0" align="Left Top" name="HealthDescription"> diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 4bc60ceb43..b02db37640 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -26,9 +26,7 @@ <Widget type="HBox"> <UserString key="HStretch" value="true"/> - <Widget type="Widget"> - <UserString key="HStretch" value="true"/> - </Widget> + <Widget type="Spacer"/> <Widget type="AutoSizedButton" skin="MW_Button" name="UntilHealedButton"> <Property key="Caption" value="#{sUntilHealed}"/>