From 8d769033929240228713fab782fdd6ce16b44830 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 2 Apr 2017 03:15:32 +0200 Subject: [PATCH 001/136] Ini-importer progress bar fills the whole width of the ui element now --- files/ui/settingspage.ui | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 7f5e4a7de..617e54890 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -131,15 +131,18 @@ - - - - 4 - - - + + + + 4 + + + false + + + From 13517e723af13cabdadcba4cc0172923b91dd20b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Apr 2017 10:05:57 +0200 Subject: [PATCH 002/136] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b4e9ad4b..ec7e2577c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 41) +set(OPENMW_VERSION_MINOR 42) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index d38dfaeb2..1ed377936 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.41.0 +* Version: 0.42.0 * License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From 59a9a7aafb458b382cd2f7573ee0d4f083069c0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Apr 2017 10:28:08 +0200 Subject: [PATCH 003/136] updated changelog --- CHANGELOG.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d826753..b390169c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,82 @@ +0.42.0 +------ + + Bug #1956: Duplicate objects after loading the game, when a mod was edited + Bug #2100: Falling leaves in Vurt's Leafy West Gash II not rendered correctly + Bug #2116: Cant fit through some doorways pressed against staircases + Bug #2289: Some modal dialogs are not centered on the screen when the window resizes + Bug #2409: Softlock when pressing weapon/magic switch keys during chargen, afterwards switches weapons even though a text field is selected + Bug #2483: Previous/Next Weapon hotkeys triggered while typing the name of game save + Bug #2629: centeroncell, coc causes death / fall damage time to time when teleporting from high + Bug #2645: Cycling weapons is possible while console/pause menu is open + Bug #2678: Combat with water creatures do not end upon exiting water + Bug #2759: Light Problems in Therana's Chamber in Tel Branora + Bug #2771: unhandled sdl event of type 0x302 + Bug #2777: (constant/on cast) disintegrate armor/weapon on self is seemingly not working + Bug #2838: Editor: '.' in a record name should be allowed + Bug #2909: NPCs appear floating when standing on a slope + Bug #3093: Controller movement cannot be used while mouse is moving + Bug #3134: Crash possible when using console with open container + Bug #3254: AI enemies hit between them. + Bug #3344: Editor: Verification results sorting by Type is not alphabetical. + Bug #3345: Editor: Cloned and added pathgrids are lost after reopen of saved omwgame file + Bug #3355: [MGSO] Physics maxing out in south cornerclub Balmora + Bug #3484: Editor: camera position is not set when changing cell via drag&drop + Bug #3508: Slowfall kills Jump momentum + Bug #3580: Crash: Error ElementBufferObject::remove BufferData<0> out of range + Bug #3581: NPCs wander too much + Bug #3601: Menu Titles not centered vertically + Bug #3607: [Mac OS] Beginning of NPC speech cut off (same issue as closed bug #3453) + Bug #3613: Can not map "next weapon" or "next spell" to controller + Bug #3617: Enchanted arrows don't explode when hitting the ground + Bug #3645: Unable to use steps in Vivec, Palace of Vivec + Bug #3650: Tamriel Rebuilt 16.09.1 – Hist Cuirass GND nif is rendered inside a Pink Box + Bug #3652: Item icon shadows get stuck in the alchemy GUI + Bug #3653: Incorrect swish sounds + Bug #3666: NPC collision should not be disabled until death animation has finished + Bug #3669: Editor: Text field was missing from book object editing dialogue + Bug #3670: Unhandled SDL event of type 0x304 + Bug #3671: Incorrect local variable value after picking up bittercup + Bug #3686: Travelling followers doesn't increase travel fee + Bug #3689: Problematic greetings from Antares Big Mod that override the appropriate ones. + Bug #3690: Certain summoned creatures do not engage in combat with underwater creatures + Bug #3691: Enemies do not initiate combat with player followers on sight + Bug #3695: [Regression] Dispel does not always dispel spell effects in 0.41 + Bug #3699: Crash on MWWorld::ProjectileManager::moveMagicBolts + Bug #3700: Climbing on rocks and mountains + Bug #3704: Creatures don't auto-equip their shields on creation + Bug #3705: AI combat engagement logic differs from vanilla + Bug #3707: Animation playing does some very odd things if pc comes in contact with the animated mesh + Bug #3712: [Mod] Freeze upon entering Adanumuran with mod Adanumuran Reclaimed + Bug #3713: [Regression] Cancelling dialogue or using travel with creatures throws a (possibly game-breaking) exception + Bug #3719: Dropped identification papers can't be picked up again + Bug #3722: Command spell doesn't bring enemies out of combat + Bug #3727: Using "Activate" mid-script-execution invalidates interpreter context + Bug #3746: Editor: Book records show attribute IDs instead of skill IDs for teached skills entry. + Bug #3755: Followers stop following after loading from savegame + Bug #3772: ModStat lowers attribute to 100 if it was greater + Bug #3781: Guns in Clean Hunter Rifles mod use crossbow sounds + Bug #3797: NPC and creature names don't show up in combat when RMB windows are displayed + Bug #3800: Wrong tooltip maximum width + Bug #3801: Drowning widget is bugged + Bug #3802: BarterOffer shouldn't limit pcMercantile + Bug #3813: Some fatal error + Bug #3816: Expression parser thinks the -> token is unexpected when a given explicit refID clashes with a journal ID + Bug #3822: Custom added creatures are not animated + Feature #451: Water sounds + Feature #2691: Light particles sometimes not shown in inventory character preview + Feature #3523: Light source on magic projectiles + Feature #3644: Nif NiSphericalCollider Unknown Record Type + Feature #3675: ess-Importer: convert mark location + Feature #3693: ess-Importer: convert last known exterior cell + Feature #3748: Editor: Replace "Scroll" check box in Book records with "Book Type" combo box. + Feature #3751: Editor: Replace "Xyz Blood" check boxes in NPC and Creature records with "Blood Type" combo box + Feature #3752: Editor: Replace emitter check boxes in Light records with "Emitter Type" combo box + Feature #3756: Editor: Replace "Female" check box in NPC records with "Gender" combo box + Feature #3757: Editor: Replace "Female" check box in BodyPart records with "Gender" combo box + Task #3092: const version of ContainerStoreIterator + Task #3795: /deps folder not in .gitignore + 0.41.0 ------ From fe4fb82646102a78d443c96708b8111ad744dbe4 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Apr 2017 01:01:50 +0900 Subject: [PATCH 004/136] Cache allies found while iterating engageCombat (Fixes #3814) --- apps/openmw/mwmechanics/actors.cpp | 47 ++++++++++++++++++++++++------ apps/openmw/mwmechanics/actors.hpp | 4 ++- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0b398a046..89cff3fa1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -280,7 +280,7 @@ namespace MWMechanics } } - void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer) { CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1); if (creatureStats1.getAiSequence().isInCombat(actor2)) @@ -306,7 +306,8 @@ namespace MWMechanics // Get actors allied with actor1. Includes those following or escorting actor1, actors following or escorting those actors, (recursive) // and any actor currently being followed or escorted by actor1 std::set allies1; - getActorsSidingWith(actor1, allies1); + + getActorsSidingWith(actor1, allies1, cachedAllies); // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 for (std::set::const_iterator it = allies1.begin(); it != allies1.end(); ++it) @@ -328,10 +329,10 @@ namespace MWMechanics aggressive = true; } - std::set playerFollowersAndEscorters; - getActorsSidingWith(MWMechanics::getPlayer(), playerFollowersAndEscorters); + std::set playerAllies; + getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies); - bool isPlayerFollowerOrEscorter = std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end(); + bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end(); // If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them // Doesn't apply for player followers/escorters @@ -341,7 +342,9 @@ namespace MWMechanics if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(actor1)) { std::set allies2; - getActorsSidingWith(actor2, allies2); + + getActorsSidingWith(actor2, allies2, cachedAllies); + // Check that an ally of actor2 is also in combat with actor1 for (std::set::const_iterator it = allies2.begin(); it != allies2.end(); ++it) { @@ -383,11 +386,11 @@ namespace MWMechanics // Do aggression check if actor2 is the player or a player follower or escorter if (!aggressive) { - if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end()) + if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end()) { // Player followers and escorters with high fight should not initiate combat with the player or with // other player followers or escorters - if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) == playerFollowersAndEscorters.end()) + if (std::find(playerAllies.begin(), playerAllies.end(), actor1) == playerAllies.end()) aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } @@ -1072,6 +1075,8 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate + std::map > cachedAllies; // will be filled as engageCombat iterates + // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -1123,7 +1128,7 @@ namespace MWMechanics { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; - engageCombat(iter->first, it->first, it->first == player); + engageCombat(iter->first, it->first, cachedAllies, it->first == player); } } if (timerUpdateHeadTrack == 0) @@ -1588,6 +1593,30 @@ namespace MWMechanics getActorsSidingWith(*it, out); } + void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { + std::list followers = getActorsSidingWith(actor); + + // If we have already found actor's allies, use the cache + std::map >::const_iterator search = cachedAllies.find(actor); + if (search != cachedAllies.end()) + out = search->second; + else + { + for (std::list::iterator it = followers.begin(); it != followers.end(); ++it) + if (out.insert(*it).second) + getActorsSidingWith(*it, out); + + // Cache ptrs and their sets of allies + cachedAllies.insert(std::make_pair(actor, out)); + for (std::set::const_iterator it = out.begin(); it != out.end(); ++it) + { + search = cachedAllies.find(*it); + if (search == cachedAllies.end()) + cachedAllies.insert(std::make_pair(*it, out)); + } + } + } + std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 20aef4c17..362c2f126 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -88,7 +88,7 @@ namespace MWMechanics @Notes: If againstPlayer = true then actor2 should be the Player. If one of the combatants is creature it should be actor1. */ - void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); + void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); @@ -127,6 +127,8 @@ namespace MWMechanics void getActorsFollowing(const MWWorld::Ptr &actor, std::set& out); /// Recursive version of getActorsSidingWith void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out); + /// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies + void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); From 56dfa615e1e11539842350e4794f4247f7308135 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Apr 2017 03:57:59 +0900 Subject: [PATCH 005/136] Minor changes to getActorsSidingWith --- apps/openmw/mwmechanics/actors.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89cff3fa1..80564de9f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1594,17 +1594,16 @@ namespace MWMechanics } void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { - std::list followers = getActorsSidingWith(actor); - // If we have already found actor's allies, use the cache std::map >::const_iterator search = cachedAllies.find(actor); if (search != cachedAllies.end()) - out = search->second; + out.insert(search->second.begin(), search->second.end()); else { + std::list followers = getActorsSidingWith(actor); for (std::list::iterator it = followers.begin(); it != followers.end(); ++it) if (out.insert(*it).second) - getActorsSidingWith(*it, out); + getActorsSidingWith(*it, out, cachedAllies); // Cache ptrs and their sets of allies cachedAllies.insert(std::make_pair(actor, out)); From 1c5c82dd9f27688e053ebe8f70f37ed56cd0afda Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 23 Apr 2017 18:05:41 +0200 Subject: [PATCH 006/136] Fix wrong incrementation in InventoryStore::visitEffectSources (Fixes #3838) --- apps/openmw/mwworld/inventorystore.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index df3f30bea..d251e824c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -823,7 +823,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito int i=0; for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt) + effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) { // Don't get spell icon display information for enchantments that weren't actually applied if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0) @@ -833,8 +833,6 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito magnitude *= params.mMultiplier; if (magnitude > 0) visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); - - ++i; } } } From 7704dcfcce3b43b7a20b4f0452e601b094267ee9 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sun, 28 May 2017 17:30:01 +0200 Subject: [PATCH 007/136] Fix build with osg >= 3.5.6 --- components/resource/bulletshapemanager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index ef35b31ef..010917572 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -42,7 +43,11 @@ struct GetTriangleFunctor return btVector3(vec.x(), vec.y(), vec.z()); } +#if OSG_MIN_VERSION_REQUIRED(3,5,6) + void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3 ) +#else void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3, bool _temp ) +#endif { if (mTriMesh) mTriMesh->addTriangle( toBullet(mMatrix.preMult(v1)), toBullet(mMatrix.preMult(v2)), toBullet(mMatrix.preMult(v3))); From 62b24eb078b4ed4c95e507caed162ff119a0647c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 16 Jun 2017 12:20:31 +0400 Subject: [PATCH 008/136] Combat AI: do not use range weapons under water --- apps/openmw/mwmechanics/aicombat.cpp | 4 ++++ apps/openmw/mwmechanics/aicombataction.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a00890cea..68d282d0c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -535,6 +535,10 @@ namespace MWMechanics // opponent's weapon range, or not backing up if opponent is also using a ranged weapon if (isDistantCombat && distToTarget < rangeAttack / 4) { + // actor should not back up into water + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) + return; + mMovement.mPosition[1] = -1; } } diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 46d37eb3d..e55ceaeac 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -118,7 +118,19 @@ namespace MWMechanics 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) { From a2be73295b3c2c8540b38db746ff609df171c5ef Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 16 Jun 2017 13:33:42 +0400 Subject: [PATCH 009/136] Combat AI: take in account enemy weapon resistance --- apps/openmw/mwmechanics/aicombataction.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index e55ceaeac..d07e4dd0a 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -135,6 +135,9 @@ namespace MWMechanics 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 { @@ -145,6 +148,8 @@ namespace MWMechanics rating += weapon->mData.mChop[i]; } rating /= 6.f; + + MWMechanics::resistNormalWeapon(enemy, actor, item, rating); } if (item.getClass().hasItemHealth(item)) @@ -182,6 +187,10 @@ namespace MWMechanics 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; } From 1a8f2bfc11fbc70f75c0a3b187d523957da20401 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 16 Jun 2017 16:11:12 +0400 Subject: [PATCH 010/136] Combat AI: select target by priority --- apps/openmw/mwmechanics/aicombataction.cpp | 73 ++++++++++++++++++++++ apps/openmw/mwmechanics/aicombataction.hpp | 1 + apps/openmw/mwmechanics/aisequence.cpp | 9 ++- 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index d07e4dd0a..624fe3a3d 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -854,6 +854,79 @@ namespace MWMechanics return bestAction; } + float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) + { + Spells& spells = actor.getClass().getCreatureStats(actor).getSpells(); + + float bestActionRating = 0.f; + // Default to hand-to-hand combat + if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) + { + return bestActionRating; + } + + if (actor.getClass().hasInventoryStore(actor)) + { + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + float rating = rateMagicItem(*it, actor, enemy); + if (rating > bestActionRating) + { + bestActionRating = rating; + } + } + + float bestArrowRating = 0; + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Arrow); + if (rating > bestArrowRating) + { + bestArrowRating = rating; + } + } + + float bestBoltRating = 0; + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + float rating = rateWeapon(*it, actor, enemy, ESM::Weapon::Bolt); + if (rating > bestBoltRating) + { + bestBoltRating = rating; + } + } + + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + std::vector equipmentSlots = it->getClass().getEquipmentSlots(*it).first; + if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight) + == equipmentSlots.end()) + continue; + + float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating); + if (rating > bestActionRating) + { + bestActionRating = rating; + } + } + } + + for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + const ESM::Spell* spell = it->first; + + float rating = rateSpell(spell, actor, enemy); + if (rating > bestActionRating) + { + bestActionRating = rating; + } + } + + return bestActionRating; + } + float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool minusZDist) { diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 3db88269b..393bd9f5d 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -101,6 +101,7 @@ namespace MWMechanics float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); std::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy); float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, bool minusZDist=false); float getMaxAttackDistance(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 82a2e2c3d..2b3709b75 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -16,6 +16,7 @@ #include "aifollow.hpp" #include "aiactivate.hpp" #include "aicombat.hpp" +#include "aicombataction.hpp" #include "aipursue.hpp" #include "actorutil.hpp" @@ -208,6 +209,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac float nearestDist = std::numeric_limits::max(); osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); + float bestRating = 0.f; + for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) { if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; @@ -222,6 +225,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } else { + float rating = MWMechanics::getBestActionRating(actor, target); + const ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (targetPos.asVec3() - vActorPos).length(); @@ -230,10 +235,12 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac if (it == mPackages.begin()) distTo = std::max(0.f, distTo - 50.f); - if (distTo < nearestDist) + // if a target has higher priority than current target or has same priority but closer + if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating)) { nearestDist = distTo; itActualCombat = it; + bestRating = rating; } ++it; } From ec458ef385cb49b24f39b916f4e45d92e22b9acb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 Jun 2017 13:08:55 +0200 Subject: [PATCH 011/136] Don't reset idle time when there is no camera movement (Fixes #3902) --- apps/openmw/mwinput/inputmanagerimp.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 234a17cc3..9979bd5d6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -417,18 +417,21 @@ namespace MWInput { float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; - resetIdleTime(); + if (xAxis != 0 || yAxis != 0) + { + resetIdleTime(); - float rot[3]; - rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; - rot[1] = 0.0f; - rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + float rot[3]; + rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + rot[1] = 0.0f; + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); - // Only actually turn player when we're not in vanity mode - if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) - { - mPlayer->yaw(rot[2]); - mPlayer->pitch(rot[0]); + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } } } From 143fdae6fea2b69828fdcb6422199731f4d0c6ab Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 28 Jun 2017 11:01:08 +0400 Subject: [PATCH 012/136] Make spell priority calculation close to vanilla (bug #3937). --- apps/openmw/mwmechanics/aicombataction.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 46d37eb3d..3c20179a4 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -558,8 +558,6 @@ namespace MWMechanics return 0.f; } - rating *= magicEffect->mData.mBaseCost; - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) { rating *= -1.f; @@ -594,13 +592,17 @@ namespace MWMechanics return 0.f; } } - else - { - rating *= (effect.mMagnMin + effect.mMagnMax)/2.f; - } - if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - rating *= effect.mDuration; + rating *= ((effect.mMagnMin + effect.mMagnMax) * (effect.mDuration > 0 ? effect.mDuration : 1) + effect.mArea); + rating *= magicEffect->mData.mBaseCost; + + if (effect.mRange == ESM::RT_Target) + rating *= 1.5f; + + static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fEffectCostMult")->getFloat(); + + rating *= fEffectCostMult * 0.05; // 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. From 9c94244b284562fcd7e152cf0c35abcb99cc6eb1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 30 Jun 2017 00:51:26 +0200 Subject: [PATCH 013/136] Fix crash introduced by commit 1d8a9ff62243cb6b8e218840d839e6d554f3e8d9 (Fixes #3940) --- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a22075abd..7fbf2965a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -378,8 +378,11 @@ namespace MWWorld return; case ESM::REC_PLAY: mPlayer->readRecord(reader, type); - mWorldScene->preloadCell(getPlayerPtr().getCell(), true); - mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + if (getPlayerPtr().isInCell()) + { + mWorldScene->preloadCell(getPlayerPtr().getCell(), true); + mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + } break; default: if (!mStore.readRecord (reader, type) && From 37952c9a790ce33bf24078319060cf62407b4cc9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 14 Jun 2017 12:44:18 +0400 Subject: [PATCH 014/136] Added door detection based by ray casting --- apps/openmw/mwbase/world.hpp | 4 +++ apps/openmw/mwmechanics/aipackage.cpp | 4 ++- apps/openmw/mwmechanics/aiwander.cpp | 9 +++-- apps/openmw/mwmechanics/obstacle.cpp | 52 ++++++++++----------------- apps/openmw/mwmechanics/obstacle.hpp | 9 ++--- apps/openmw/mwworld/worldimp.cpp | 9 +++-- apps/openmw/mwworld/worldimp.hpp | 3 ++ 7 files changed, 45 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 86d26d3a7..ce6cf38eb 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -10,6 +10,7 @@ #include "../mwworld/ptr.hpp" #include "../mwrender/rendermode.hpp" +#include "../mwphysics/physicssystem.hpp" namespace osg { @@ -299,6 +300,9 @@ namespace MWBase virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; ///< cast a Ray and return true if there is an object in the ray path. + virtual MWPhysics::PhysicsSystem::RayResult castRayTest (float x1, float y1, float z1, float x2, float y2, float z2) = 0; + ///< cast a rendering ray and return ray result. + virtual bool toggleCollisionMode() = 0; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 529e7ca41..f837ad2ee 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -176,7 +176,9 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur if (!mObstacleCheck.check(actor, duration)) return; // first check if obstacle is a door - MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + + MWWorld::Ptr door = getNearbyDoor(actor, distance); if (door != MWWorld::Ptr()) { // note: AiWander currently does not open doors diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a992bc8d4..3888aaf6d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -440,11 +440,14 @@ 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 if (mDistance && // actor is not intended to be stationary - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + proximityToDoor(actor, distance*1.6f)) { storage.setState(Wander_MoveNow); storage.mTrimCurrentNode = false; // just in case @@ -516,10 +519,12 @@ 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 - if (proximityToDoor(actor)) // NOTE: checks interior cells only + if (proximityToDoor(actor, distance)) { // remove allowed points then select another random destination storage.mTrimCurrentNode = true; diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 5d99fe723..8e932f351 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,8 +1,11 @@ #include "obstacle.hpp" +#include + #include #include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -23,51 +26,34 @@ namespace MWMechanics { -1.0f, -1.0f } // move to side and backwards }; - // Proximity check function for interior doors. Given that most interior cells - // do not have many doors performance shouldn't be too much of an issue. - // - // Limitation: there can be false detections, and does not test whether the - // actor is facing the door. - bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr) + bool proximityToDoor(const MWWorld::Ptr& actor, float minDist) { - if(getNearbyDoor(actor, minSqr)!=MWWorld::Ptr()) + if(getNearbyDoor(actor, minDist)!=MWWorld::Ptr()) return true; else return false; } - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr) + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) { - MWWorld::CellStore *cell = actor.getCell(); + osg::Vec3f origin = MWBase::Environment::get().getWorld()->getActorHeadTransform(actor).getTrans(); + + osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) + * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); - if(cell->getCell()->isExterior()) - return MWWorld::Ptr(); // check interior cells only + osg::Vec3f direction = orient * osg::Vec3f(0,1,0); + osg::Vec3f dest = origin + direction * minDist; - // Check all the doors in this cell - const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); - const MWWorld::CellRefList::List& refList = doors.mList; - MWWorld::CellRefList::List::const_iterator it = refList.begin(); osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); + MWPhysics::PhysicsSystem::RayResult result = MWBase::Environment::get().getWorld()->castRayTest(pos.x(), pos.y(), pos.z(), dest.x(), dest.y(), dest.z()); - /// TODO: How to check whether the actor is facing a door? Below code is for - /// the player, perhaps it can be adapted. - //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); - //if(!ptr.isEmpty()) - //std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl; + if (!result.mHit || result.mHitObject.isEmpty()) + return MWWorld::Ptr(); // none found - /// TODO: The in-game observation of rot[2] value seems to be the - /// opposite of the code in World::activateDoor() ::confused:: - for (; it != refList.end(); ++it) - { - const MWWorld::LiveCellRef& ref = *it; - if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr - && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) - { - // FIXME cast - return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching - } - } - return MWWorld::Ptr(); // none found + if (result.mHitObject.getClass().getTypeName() == typeid(ESM::Door).name() && !result.mHitObject.getCellRef().getTeleport()) + return result.mHitObject; + + return MWWorld::Ptr(); } ObstacleCheck::ObstacleCheck(): diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 1d7cf1e0e..f71207346 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -10,19 +10,14 @@ namespace MWMechanics { struct Movement; - /// NOTE: determined empirically based on in-game behaviour - static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; - static const int NUM_EVADE_DIRECTIONS = 4; /// tests actor's proximity to a closed door by default - bool proximityToDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED); + bool proximityToDoor(const MWWorld::Ptr& actor, float minDist); /// Returns door pointer within range. No guarantee is given as to which one /** \return Pointer to the door, or NULL if none exists **/ - MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, - float minSqr = MIN_DIST_TO_DOOR_SQUARED); + MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist); class ObstacleCheck { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0421ecb24..86943a7e7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1451,11 +1451,16 @@ namespace MWWorld } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) + { + MWPhysics::PhysicsSystem::RayResult result = castRayTest(x1, y1, z1, x2, y2, z2); + return result.mHit; + } + + MWPhysics::PhysicsSystem::RayResult World::castRayTest (float x1, float y1, float z1, float x2, float y2, float z2) { osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); - return result.mHit; + return mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); } void World::processDoors(float duration) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ce6e27672..951a837da 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -407,6 +407,9 @@ namespace MWWorld virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); ///< cast a Ray and return true if there is an object in the ray path. + virtual MWPhysics::PhysicsSystem::RayResult castRayTest (float x1, float y1, float z1, float x2, float y2, float z2); + ///< cast a rendering ray and return ray result. + virtual bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. From 3ba0a336b7786646346f2bbf921f36366d399201 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 30 Jun 2017 16:27:18 +0400 Subject: [PATCH 015/136] Move spell magicka cost calculation to standalone function --- apps/openmw/mwgui/spellcreationdialog.cpp | 23 +++------- apps/openmw/mwmechanics/aicombataction.cpp | 14 ++---- apps/openmw/mwmechanics/autocalcspell.cpp | 33 +++++++++----- apps/openmw/mwmechanics/spellcasting.cpp | 50 +++++++++++++++++++--- apps/openmw/mwmechanics/spellcasting.hpp | 4 ++ 5 files changed, 83 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 64d4d86c6..0bb9184d2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -440,22 +440,11 @@ namespace MWGui for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - float x = 0.5f * (it->mMagnMin + it->mMagnMax); + const ESM::ENAMstruct& effect = *it; - const ESM::MagicEffect* effect = - store.get().find(it->mEffectID); + y += std::max(1.f, MWMechanics::calcEffectCost(effect)); - x *= 0.1f * effect->mData.mBaseCost; - x *= 1 + it->mDuration; - x += 0.05f * std::max(1, it->mArea) * effect->mData.mBaseCost; - - float fEffectCostMult = - store.get().find("fEffectCostMult")->getFloat(); - - y += x * fEffectCostMult; - y = std::max(1.f,y); - - if (it->mRange == ESM::RT_Target) + if (effect.mRange == ESM::RT_Target) y *= 1.5; } @@ -475,8 +464,10 @@ namespace MWGui mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); - float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWMechanics::getPlayer()); - mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); + float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), NULL); + + int intChance = std::min(100, int(chance)); + mSuccessChance->setCaption(MyGUI::utility::toString(intChance)); } // ------------------------------------------------------------------------------------------------ diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 3c20179a4..1408dce6b 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -593,16 +593,7 @@ namespace MWMechanics } } - rating *= ((effect.mMagnMin + effect.mMagnMax) * (effect.mDuration > 0 ? effect.mDuration : 1) + effect.mArea); - rating *= magicEffect->mData.mBaseCost; - - if (effect.mRange == ESM::RT_Target) - rating *= 1.5f; - - static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fEffectCostMult")->getFloat(); - - rating *= fEffectCostMult * 0.05; + 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. @@ -619,6 +610,9 @@ namespace MWMechanics for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) { rating += rateEffect(*it, actor, enemy); + + if (it->mRange == ESM::RT_Target) + rating *= 1.5f; } return rating; } diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index af814edb0..f655a68b4 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -1,4 +1,5 @@ #include "autocalcspell.hpp" +#include "spellcasting.hpp" #include #include @@ -255,27 +256,39 @@ namespace MWMechanics void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) { + // Morrowind for some reason uses a formula slightly different from magicka cost calculation float minChance = std::numeric_limits::max(); const ESM::EffectList& effects = spell->mEffects; for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) { const ESM::ENAMstruct& effect = *it; - float x = static_cast(effect.mDuration); - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) - x = std::max(1.f, x); - x *= 0.1f * magicEffect->mData.mBaseCost; - x *= 0.5f * (effect.mMagnMin + effect.mMagnMax); - x += effect.mArea * 0.05f * magicEffect->mData.mBaseCost; - if (effect.mRange == ESM::RT_Target) - x *= 1.5f; + int minMagn = 1; + int maxMagn = 1; + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + minMagn = effect.mMagnMin; + maxMagn = effect.mMagnMax; + } - static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fEffectCostMult")->getFloat(); + int duration = 0; + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + duration = effect.mDuration; + + static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() + .get().find("fEffectCostMult")->getFloat(); + + float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn)); + x *= 0.1 * magicEffect->mData.mBaseCost; + x *= 1 + duration; + x += 0.05 * std::max(1, effect.mArea) * magicEffect->mData.mBaseCost; x *= fEffectCostMult; + if (effect.mRange == ESM::RT_Target) + x *= 1.5f; + float s = 2.f * actorSkills[mapSchoolToSkill(magicEffect->mData.mSchool)]; if (s - x < minChance) { diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5cfaccb84..7fde66ebe 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -44,8 +44,36 @@ namespace MWMechanics return schoolSkillMap[school]; } - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + float calcEffectCost(const ESM::ENAMstruct& effect) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + + int minMagn = 1; + int maxMagn = 1; + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + minMagn = effect.mMagnMin; + maxMagn = effect.mMagnMax; + } + + int duration = 0; + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + duration = effect.mDuration; + + static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() + .get().find("fEffectCostMult")->getFloat(); + + float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn)); + x *= 0.1 * magicEffect->mData.mBaseCost; + x *= 1 + duration; + x += 0.05 * std::max(1, effect.mArea) * magicEffect->mData.mBaseCost; + + return x * fEffectCostMult; + } + + float calcSpellBaseSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool) { + // Morrowind for some reason uses a formula slightly different from magicka cost calculation float y = std::numeric_limits::max(); float lowestSkill = 0; @@ -54,8 +82,10 @@ namespace MWMechanics float x = static_cast(it->mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( it->mEffectID); + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) x = std::max(1.f, x); + x *= 0.1f * magicEffect->mData.mBaseCost; x *= 0.5f * (it->mMagnMin + it->mMagnMax); x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost; @@ -75,6 +105,18 @@ namespace MWMechanics } } + CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); + int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); + + float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck); + + return castChance; + } + + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + { bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); CreatureStats& stats = actor.getClass().getCreatureStats(actor); @@ -98,10 +140,8 @@ namespace MWMechanics float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); - int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); - int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - - float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); + float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; + castChance *= stats.getFatigueTerm(); if (!cap) return std::max(0.f, castChance); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 8e48681b6..9991c583d 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -1,6 +1,7 @@ #ifndef MWMECHANICS_SPELLSUCCESS_H #define MWMECHANICS_SPELLSUCCESS_H +#include #include #include "../mwworld/ptr.hpp" @@ -21,6 +22,8 @@ namespace MWMechanics ESM::Skill::SkillEnum spellSchoolToSkill(int school); + float calcEffectCost(const ESM::ENAMstruct& effect); + bool isSummoningEffect(int effectId); /** @@ -62,6 +65,7 @@ namespace MWMechanics bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer); int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + float calcSpellBaseSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool); /// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed /// @return Was the effect a tickable effect with a magnitude? From 548814bfbc0e7aacbc8585f6b3e3d10751b96eb8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 25 Jul 2017 09:51:55 +0400 Subject: [PATCH 016/136] Added AiBreathe package (feature #1374) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 11 ++++++ apps/openmw/mwmechanics/aibreathe.cpp | 54 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/aibreathe.hpp | 28 +++++++++++++ apps/openmw/mwmechanics/aipackage.hpp | 5 ++- apps/openmw/mwmechanics/aisequence.cpp | 3 +- 6 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 apps/openmw/mwmechanics/aibreathe.cpp create mode 100644 apps/openmw/mwmechanics/aibreathe.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a06678488..1aa311fd2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -81,7 +81,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actorutil - drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor + 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 diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 431ad09b3..44a457cb6 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -25,6 +25,8 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwmechanics/aibreathe.hpp" + #include "spellcasting.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" @@ -814,6 +816,15 @@ namespace MWMechanics if (stats.getTimeToStartDrowning() == -1.f) stats.setTimeToStartDrowning(fHoldBreathTime); + if (ptr.getClass().isNpc() && stats.getTimeToStartDrowning() < fHoldBreathTime / 2) + { + if(ptr != MWMechanics::getPlayer() ) { + MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once + seq.stack(MWMechanics::AiBreathe(), ptr); + } + } + MWBase::World *world = MWBase::Environment::get().getWorld(); bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); if((world->isSubmerged(ptr) || knockedOutUnderwater) diff --git a/apps/openmw/mwmechanics/aibreathe.cpp b/apps/openmw/mwmechanics/aibreathe.cpp new file mode 100644 index 000000000..4e0076824 --- /dev/null +++ b/apps/openmw/mwmechanics/aibreathe.cpp @@ -0,0 +1,54 @@ +#include "aibreathe.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" + +#include "npcstats.hpp" + +#include "movement.hpp" +#include "steering.hpp" + +MWMechanics::AiBreathe::AiBreathe() +: AiPackage() +{ + +} + +bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) +{ + static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->getFloat(); + + const MWWorld::Class& actorClass = actor.getClass(); + if (actorClass.isNpc()) + { + if (actorClass.getNpcStats(actor).getTimeToStartDrowning() < fHoldBreathTime / 2) + { + actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + + actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + smoothTurn(actor, -180, 0); + + return false; + } + } + + return true; +} + +MWMechanics::AiBreathe *MWMechanics::AiBreathe::clone() const +{ + return new AiBreathe(*this); +} + +int MWMechanics::AiBreathe::getTypeId() const +{ + return TypeIdBreathe; +} + +unsigned int MWMechanics::AiBreathe::getPriority() const +{ + return 2; +} diff --git a/apps/openmw/mwmechanics/aibreathe.hpp b/apps/openmw/mwmechanics/aibreathe.hpp new file mode 100644 index 000000000..263ab8c2b --- /dev/null +++ b/apps/openmw/mwmechanics/aibreathe.hpp @@ -0,0 +1,28 @@ +#ifndef GAME_MWMECHANICS_AIBREATHE_H +#define GAME_MWMECHANICS_AIBREATHE_H + +#include "aipackage.hpp" + +namespace MWMechanics +{ + /// \brief AiPackage to have an actor resurface to breathe + // The AI will go up if lesser than half breath left + class AiBreathe : public AiPackage + { + public: + AiBreathe(); + + virtual AiBreathe *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + + virtual int getTypeId() const; + + virtual unsigned int getPriority() const; + + virtual bool canCancel() const { return false; } + virtual bool shouldCancelPreviousAi() const { return false; } + }; +} +#endif + diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 5e23e085e..acbd87908 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -41,12 +41,13 @@ namespace MWMechanics TypeIdFollow = 3, TypeIdActivate = 4, - // These 4 are not really handled as Ai Packages in the MW engine + // These 5 are not really handled as Ai Packages in the MW engine // For compatibility do *not* return these in the getCurrentAiPackage script function.. TypeIdCombat = 5, TypeIdPursue = 6, TypeIdAvoidDoor = 7, - TypeIdFace = 8 + TypeIdFace = 8, + TypeIdBreathe = 9 }; ///Default constructor diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2f33d6e4e..d9652ef54 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -182,7 +182,8 @@ bool isActualAiPackage(int packageTypeId) return (packageTypeId != AiPackage::TypeIdCombat && packageTypeId != AiPackage::TypeIdPursue && packageTypeId != AiPackage::TypeIdAvoidDoor - && packageTypeId != AiPackage::TypeIdFace); + && packageTypeId != AiPackage::TypeIdFace + && packageTypeId != AiPackage::TypeIdBreathe); } void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) From 072fbcaee374e9b93c9faaa9cc37b7ea484268d0 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Tue, 25 Jul 2017 22:12:29 -0500 Subject: [PATCH 017/136] UI adjustments to prevent parchment scroll from being cut off (fixes #3910) --- files/ui/mainwindow.ui | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index a9e493926..45578ef9e 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -7,13 +7,13 @@ 0 0 635 - 575 + 565 635 - 535 + 565 @@ -57,6 +57,18 @@ + + 0 + + + 0 + + + 0 + + + 0 + From 6ab36c05399ebcefceb5bec1bffbcc56c8a71697 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 27 Jul 2017 13:20:18 +0400 Subject: [PATCH 018/136] Spellbuying menu improvements --- apps/openmw/mwgui/spellbuyingwindow.cpp | 38 ++++++++++++++++++------- apps/openmw/mwgui/spellbuyingwindow.hpp | 9 ++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 806b17a90..6a7376aa0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -22,7 +22,6 @@ namespace MWGui SpellBuyingWindow::SpellBuyingWindow() : WindowBase("openmw_spell_buying_window.layout") - , mLastPos(0) , mCurrentY(0) { getWidget(mCancelButton, "CancelButton"); @@ -37,13 +36,20 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); } - void SpellBuyingWindow::addSpell(const std::string& spellId) + bool SpellBuyingWindow::sortSpells (const ESM::Spell* left, const ESM::Spell* right) + { + std::string leftName = Misc::StringUtils::lowerCase(left->mName); + std::string rightName = Misc::StringUtils::lowerCase(right->mName); + + return leftName.compare(rightName) < 0; + } + + void SpellBuyingWindow::addSpell(const ESM::Spell& spell) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); + int price = static_cast(spell.mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -64,13 +70,13 @@ namespace MWGui mCurrentY += sLineHeight; toAdd->setUserData(price); - toAdd->setCaptionWithReplacing(spell->mName+" - "+MyGUI::utility::toString(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing(spell.mName+" - "+MyGUI::utility::toString(price)+"#{sgp}"); toAdd->setSize(mSpellsView->getWidth(),sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); - toAdd->setUserString("Spell", spellId); + toAdd->setUserString("Spell", spell.mId); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick); - mSpellsWidgetMap.insert(std::make_pair (toAdd, spellId)); + mSpellsWidgetMap.insert(std::make_pair (toAdd, spell.mId)); } void SpellBuyingWindow::clearSpells() @@ -82,7 +88,7 @@ namespace MWGui mSpellsWidgetMap.clear(); } - void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor) + void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor, int startOffset) { center(); mPtr = actor; @@ -90,6 +96,8 @@ namespace MWGui MWMechanics::Spells& merchantSpells = actor.getClass().getCreatureStats (actor).getSpells(); + std::vector spellsToSort; + for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) { const ESM::Spell* spell = iter->first; @@ -109,15 +117,25 @@ namespace MWGui if (playerHasSpell(iter->first->mId)) continue; - addSpell (iter->first->mId); + spellsToSort.push_back(iter->first); } + std::stable_sort(spellsToSort.begin(), spellsToSort.end(), sortSpells); + + for (std::vector::iterator it = spellsToSort.begin() ; it != spellsToSort.end(); ++it) + { + addSpell(**it); + } + + spellsToSort.clear(); + updateLabels(); // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mSpellsView->setVisibleVScroll(false); mSpellsView->setCanvasSize (MyGUI::IntSize(mSpellsView->getWidth(), std::max(mSpellsView->getHeight(), mCurrentY))); mSpellsView->setVisibleVScroll(true); + mSpellsView->setViewOffset(MyGUI::IntPoint(0, startOffset)); } bool SpellBuyingWindow::playerHasSpell(const std::string &id) @@ -143,7 +161,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - startSpellBuying(mPtr); + startSpellBuying(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 2a6dcfdcc..37210819f 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -4,6 +4,8 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" +#include "../mwworld/esmstore.hpp" + namespace MyGUI { class Gui; @@ -23,7 +25,7 @@ namespace MWGui public: SpellBuyingWindow(); - void startSpellBuying(const MWWorld::Ptr& actor); + void startSpellBuying(const MWWorld::Ptr& actor, int startOffset); virtual void exit(); @@ -38,7 +40,7 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onSpellButtonClick(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); - void addSpell(const std::string& spellID); + void addSpell(const ESM::Spell& spell); void clearSpells(); int mLastPos,mCurrentY; @@ -49,6 +51,9 @@ namespace MWGui virtual void onReferenceUnavailable(); bool playerHasSpell (const std::string& id); + + private: + static bool sortSpells (const ESM::Spell* left, const ESM::Spell* right); }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bc77eb069..21dde4e0a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2001,7 +2001,7 @@ namespace MWGui void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) { pushGuiMode(GM_SpellBuying); - mSpellBuyingWindow->startSpellBuying(actor); + mSpellBuyingWindow->startSpellBuying(actor, 0); } void WindowManager::startTrade(const MWWorld::Ptr &actor) From 622e7589095154475cb09a11f9227490209ff441 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Thu, 27 Jul 2017 16:44:17 -0500 Subject: [PATCH 019/136] Fixing link to bug tracker Bug tracker link was pointing to 0.41 bugs, but the Readme was talking about pre-1.0 features. Pointing to the main page makes more sense. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d38dfaeb2..e866767f4 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Font Licenses: Current Status -------------- -The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. +The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page. From f2fc8351bb2b1b3622939c390110f8e6847079aa Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 28 Jul 2017 10:42:30 +0200 Subject: [PATCH 020/136] remove breath/doxygen autodoc --- docs/requirements.txt | 1 - docs/source/conf.py | 40 +-- docs/source/index.rst | 2 - 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 -------- 20 files changed, 1 insertion(+), 1613 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/docs/requirements.txt b/docs/requirements.txt index 6ee8d6987..72c2aaa12 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,2 @@ -breathe parse_cmake sphinx diff --git a/docs/source/conf.py b/docs/source/conf.py index 273b2f7d5..b18b40c50 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,7 +11,6 @@ # # All configuration values have a default; values that are commented out # serve to show the default. -import glob import os import sys @@ -21,12 +20,6 @@ import sys project_root = os.path.abspath('../../') sys.path.insert(0, project_root) - -def insensitive_glob(pattern): - def either(c): - return '[%s%s]' % (c.lower(), c.upper()) if c.isalpha() else c - return glob.glob(''.join(map(either, pattern))) - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -43,37 +36,6 @@ extensions = [ 'sphinx.ext.viewcode', ] -try: - import breathe - extensions.append('breathe') -except ImportError: - print("WARNING: Unable to import breathe, code documentation won't be generated.") - -# Where breathe can find the source files -openmw_path = os.path.join(project_root, "apps", "openmw") -openmw_sub_dirs = os.walk(openmw_path).next()[1] -openmw_headers = insensitive_glob(os.path.join(openmw_path, "*.hpp")) -for dir in openmw_sub_dirs: - openmw_headers += insensitive_glob(os.path.join(openmw_path, dir, "*.hpp")) -# massage the headers to get the relative path needed -openmw_headers = [os.path.relpath(x, openmw_path) for x in openmw_headers] - -opencs_path = os.path.join(project_root, "apps", "opencs") -opencs_sub_dirs = os.walk(opencs_path).next()[1] -opencs_headers = insensitive_glob(os.path.join(opencs_path, "*.hpp")) -opencs_sub_sub_dirs = [] -for dir in opencs_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, "*.hpp")) - opencs_sub_sub_dirs += os.walk(os.path.join(opencs_path, dir)).next()[1] - for sub_dir in opencs_sub_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, sub_dir, "*.hpp")) -opencs_headers = [os.path.relpath(x, opencs_path) for x in opencs_headers] - -breathe_projects_source = { - "openmw": (openmw_path, openmw_headers), - "opencs": (opencs_path, opencs_headers), -} - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -88,7 +50,7 @@ master_doc = 'index' # General information about the project. project = u'OpenMW' -copyright = u'2016, OpenMW Team' +copyright = u'2017, OpenMW Team' # The version info for the project you're documenting, acts as replacement for diff --git a/docs/source/index.rst b/docs/source/index.rst index f51cda909..0308d88de 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,8 +9,6 @@ Sections manuals/index reference/index - source/index - Indices and Tables ================== diff --git a/docs/source/source/index.rst b/docs/source/source/index.rst deleted file mode 100644 index b58bf2b37..000000000 --- a/docs/source/source/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Project Source Documentation -============================ - -.. toctree:: - :maxdepth: 2 - - openmw/index - opencs/index \ No newline at end of file diff --git a/docs/source/source/opencs/index.rst b/docs/source/source/opencs/index.rst deleted file mode 100644 index b648bc49c..000000000 --- a/docs/source/source/opencs/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -OpenMW-CS Source Documentation -############################## - -.. toctree:: - :maxdepth: 2 - - model/index - view/index - -.. autodoxygenfile:: editor.hpp - :project: opencs \ No newline at end of file diff --git a/docs/source/source/opencs/model/index.rst b/docs/source/source/opencs/model/index.rst deleted file mode 100644 index 38ca0c31c..000000000 --- a/docs/source/source/opencs/model/index.rst +++ /dev/null @@ -1,358 +0,0 @@ -./opencs/model -############## - -doc ---- - .. autodoxygenfile:: model/doc/blacklist.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/document.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/documentmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/messages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operationholder.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/runner.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/saving.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstate.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/stage.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/state.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: model/filter/andnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/booleannode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/leafnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/narynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/node.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/notnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/ornode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/parser.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/textnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/unarynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/valuenode.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: model/prefs/boolsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/category.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/coloursetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/doublesetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/enumsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/intsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/modifiersetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/setting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcuteventhandler.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcut.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/state.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: model/tools/birthsigncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/bodypartcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/classcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/factioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/gmstcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/journalcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/magiceffectcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mandatoryid.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergeoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestages.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestate.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/pathgridcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/racecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referenceablecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referencecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/regioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/reportmodel.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/scriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/search.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchstage.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/skillcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundgencheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/spellcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/startscriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/tools.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/topicinfocheck.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: model/world/cellcoordinates.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cell.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cellselection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collectionbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columns.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commanddispatcher.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commandmacro.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commands.hpp - :project: opencs - - .. autodoxygenfile:: model/world/data.hpp - :project: opencs - - .. autodoxygenfile:: model/world/defaultgmsts.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcompletionmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtablebase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtree.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/info.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infoselectwrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infotableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/land.hpp - :project: opencs - - .. autodoxygenfile:: model/world/landtexture.hpp - :project: opencs - - .. autodoxygenfile:: model/world/metadata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcoladapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcolumnadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedinfocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtablewrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: model/world/record.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/ref.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refiddata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resources.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcesmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcetable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scope.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scriptcontext.hpp - :project: opencs - - .. autodoxygenfile:: model/world/subcellcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/tablemimedata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/universalid.hpp - :project: opencs - diff --git a/docs/source/source/opencs/view/index.rst b/docs/source/source/opencs/view/index.rst deleted file mode 100644 index 54d00ccc0..000000000 --- a/docs/source/source/opencs/view/index.rst +++ /dev/null @@ -1,340 +0,0 @@ -./opencs/view -############# - -doc ---- - .. autodoxygenfile:: view/doc/adjusterwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filedialog.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/globaldebugprofilemenu.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/newgame.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operations.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/runlogsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/sizehint.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/startup.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactory.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactoryimp.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/view.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/viewmanager.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: view/filter/editwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/filterbox.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/recordfilterbox.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: view/prefs/dialogue.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/keybindingpage.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/pagebase.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/page.hpp - :project: opencs - -render ------- - .. autodoxygenfile:: view/render/cameracontroller.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellarrow.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellborder.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cell.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellmarker.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellwater.hpp - :project: opencs - - .. autodoxygenfile:: view/render/editmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemovemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instanceselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingbright.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingday.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lighting.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingnight.hpp - :project: opencs - - .. autodoxygenfile:: view/render/mask.hpp - :project: opencs - - .. autodoxygenfile:: view/render/object.hpp - :project: opencs - - .. autodoxygenfile:: view/render/orbitcameramode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/previewwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/scenewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/selectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/tagbase.hpp - :project: opencs - - .. autodoxygenfile:: view/render/terrainstorage.hpp - :project: opencs - - .. autodoxygenfile:: view/render/unpagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/worldspacewidget.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: view/tools/merge.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reportsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reporttable.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchbox.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/subviews.hpp - :project: opencs - -widget ------- - .. autodoxygenfile:: view/widget/coloreditor.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/colorpickerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/completerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/droplineedit.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/modebutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/pushbutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolbar.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetool.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolmode.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolrun.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle2.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: view/world/cellcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/colordelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/creator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/datadisplaydelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguespinbox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragdroputils.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragrecordtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/enumdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/extendedcommandconfigurator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/genericcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/globalcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idcompletiondelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idtypedelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idvalidator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/infocreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/nestedtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/pathgridcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/previewsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordbuttonbar.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordstatusdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referenceablecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referencecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmapsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scenesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptedit.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripterrortable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripthighlighter.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/startscriptcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/subviews.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablebottombox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tableeditidaction.hpp - :project: opencs - - .. autodoxygenfile:: view/world/table.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/util.hpp - :project: opencs - - .. autodoxygenfile:: view/world/vartypedelegate.hpp - :project: opencs diff --git a/docs/source/source/openmw/index.rst b/docs/source/source/openmw/index.rst deleted file mode 100644 index 5367995de..000000000 --- a/docs/source/source/openmw/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -OpenMW Source Documentation -########################### - -.. toctree:: - :maxdepth: 2 - - mwbase - mwclass - mwdialogue - mwgui - mwinput - mwmechanics - mwphysics - mwrender - mwscript - mwsound - mwstate - mwworld - -.. autodoxygenfile:: engine.hpp - :project: openmw - -.. autodoxygenfile:: doc.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwbase.rst b/docs/source/source/openmw/mwbase.rst deleted file mode 100644 index 8fd7ffc1e..000000000 --- a/docs/source/source/openmw/mwbase.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwbase -######## - -.. autodoxygenfile:: mwbase/dialoguemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/environment.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/inputmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/journal.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/mechanicsmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/scriptmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/soundmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/statemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/windowmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/world.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwclass.rst b/docs/source/source/openmw/mwclass.rst deleted file mode 100644 index 3365d2582..000000000 --- a/docs/source/source/openmw/mwclass.rst +++ /dev/null @@ -1,68 +0,0 @@ -./mwclass -######### - -.. autodoxygenfile:: mwclass/activator.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/apparatus.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/armor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/bodypart.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/book.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/classes.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/clothing.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/container.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creature.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creaturelevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/ingredient.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/itemlevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/light.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/lockpick.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/misc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/npc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/potion.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/probe.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/static.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/weapon.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwdialogue.rst b/docs/source/source/openmw/mwdialogue.rst deleted file mode 100644 index 1f3522f2c..000000000 --- a/docs/source/source/openmw/mwdialogue.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwdialogue -############ - -.. autodoxygenfile:: mwdialogue/dialoguemanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/filter.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/hypertextparser.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalentry.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/keywordsearch.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/quest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/scripttest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/selectwrapper.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/topic.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwgui.rst b/docs/source/source/openmw/mwgui.rst deleted file mode 100644 index 0e3726832..000000000 --- a/docs/source/source/openmw/mwgui.rst +++ /dev/null @@ -1,227 +0,0 @@ -./mwgui -####### - -.. autodoxygenfile:: mwgui/alchemywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/backgroundimage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/birth.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookpage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/charactercreation.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/class.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/confirmationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/console.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/container.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/containeritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/controllers.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/countdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/cursor.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/debugwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/dialogue.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/draganddrop.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/enchantingdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/exposedwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/formatting.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/hud.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventoryitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventorywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemchargeview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemselection.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemwidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/jailscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalbooks.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalviewmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/layout.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/levelupdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/loadingscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mainmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mapwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/merchantrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/messagebox.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mode.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/pickpocketitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/quickkeysmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/race.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/recharge.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/referenceinterface.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/review.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/savegamedialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/screenfader.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/scrollwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/settingswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/sortfilteritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/soulgemdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellbuyingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellcreationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellicons.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/statswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/textinput.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/timeadvancer.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tooltips.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradeitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradewindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/trainingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/travelwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/videowidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/waitdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/widgets.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowbase.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowpinnablebase.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwinput.rst b/docs/source/source/openmw/mwinput.rst deleted file mode 100644 index b24d8dfdb..000000000 --- a/docs/source/source/openmw/mwinput.rst +++ /dev/null @@ -1,5 +0,0 @@ -./mwinput -######### - -.. autodoxygenfile:: mwinput/inputmanagerimp.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwmechanics.rst b/docs/source/source/openmw/mwmechanics.rst deleted file mode 100644 index 3427b712a..000000000 --- a/docs/source/source/openmw/mwmechanics.rst +++ /dev/null @@ -1,137 +0,0 @@ -./mwmechanics -############# - -.. autodoxygenfile:: mwmechanics/activespells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actors.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actorutil.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiactivate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiavoiddoor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombataction.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiescort.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiface.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aifollow.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipackage.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipursue.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aisequence.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aistate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aitravel.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiwander.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/alchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/autocalcspell.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/character.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/combat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/coordinateconverter.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/creaturestats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/difficultyscaling.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/disease.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/drawstate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/enchanting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/levelledlist.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/magiceffects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/mechanicsmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/movement.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/npcstats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/obstacle.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathfinding.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pickpocket.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/security.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spellcasting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/stat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/steering.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/summoning.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/trading.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwphysics.rst b/docs/source/source/openmw/mwphysics.rst deleted file mode 100644 index 6eebab4d9..000000000 --- a/docs/source/source/openmw/mwphysics.rst +++ /dev/null @@ -1,15 +0,0 @@ -./mwphysics -########### - -.. autodoxygenfile:: mwphysics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/collisiontype.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/convert.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/physicssystem.hpp - :project: openmw - diff --git a/docs/source/source/openmw/mwrender.rst b/docs/source/source/openmw/mwrender.rst deleted file mode 100644 index d284f6586..000000000 --- a/docs/source/source/openmw/mwrender.rst +++ /dev/null @@ -1,77 +0,0 @@ -./mwrender -########## - -.. autodoxygenfile:: mwrender/actoranimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/animation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/bulletdebugdraw.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/camera.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/cell.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/characterpreview.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/creatureanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/effectmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/globalmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/localmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/npcanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderbin.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderinginterface.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderingmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rendermode.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/ripplesimulation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rotatecontroller.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/sky.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/terrainstorage.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/util.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/vismask.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/water.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/weaponanimation.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwscript.rst b/docs/source/source/openmw/mwscript.rst deleted file mode 100644 index 8db8f40e2..000000000 --- a/docs/source/source/openmw/mwscript.rst +++ /dev/null @@ -1,65 +0,0 @@ -./mwscript -########## - -.. autodoxygenfile:: mwscript/aiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/animationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/cellextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/compilercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/consoleextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/containerextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/controlextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/dialogueextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/extensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/globalscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/guiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/interpretercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/locals.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/miscextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/ref.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/scriptmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/skyextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/soundextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/statsextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/transformationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/userextensions.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwsound.rst b/docs/source/source/openmw/mwsound.rst deleted file mode 100644 index d4fcb0e6b..000000000 --- a/docs/source/source/openmw/mwsound.rst +++ /dev/null @@ -1,29 +0,0 @@ -./mwsound -######### - -.. autodoxygenfile:: mwsound/ffmpeg_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/loudness.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/movieaudiofactory.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/openal_output.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_buffer.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/soundmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_output.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwstate.rst b/docs/source/source/openmw/mwstate.rst deleted file mode 100644 index 2618c6ff0..000000000 --- a/docs/source/source/openmw/mwstate.rst +++ /dev/null @@ -1,11 +0,0 @@ -./mwstate -######### - -.. autodoxygenfile:: mwstate/character.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/charactermanager.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/statemanagerimp.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwworld.rst b/docs/source/source/openmw/mwworld.rst deleted file mode 100644 index 21026b3e2..000000000 --- a/docs/source/source/openmw/mwworld.rst +++ /dev/null @@ -1,132 +0,0 @@ -./mwworld -######### - -.. autodoxygenfile:: mwworld/actionalchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionapply.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiondoor.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actioneat.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionequip.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/action.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionopen.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionread.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionsoulgem.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontake.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontalk.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionteleport.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontrap.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellpreloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellreflist.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cells.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellvisitors.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/class.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/containerstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/contentloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/customdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/failedaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/globals.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/inventorystore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/livecellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/localscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/manualref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/nullaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/player.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/projectilemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/ptr.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/recordcmp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/refdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/scene.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/store.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/timestamp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/weather.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/worldimp.hpp - :project: openmw - From 69359b6b4befe26909133febae34318fe0dbc621 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 28 Jul 2017 13:13:45 +0200 Subject: [PATCH 021/136] expand to max-depth 3 and remove indices and tables --- docs/source/index.rst | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 0308d88de..3781733cb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,14 +5,7 @@ Sections -------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 manuals/index reference/index - -Indices and Tables -================== - -* :ref:`genindex` -* :ref:`search` - From 920021c61b52ed6fc7f1393a0522cd5c3d3ef463 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 28 Jul 2017 16:50:52 +0400 Subject: [PATCH 022/136] Update effects during rest (bug #3679) --- apps/openmw/mwmechanics/actors.cpp | 5 +++++ apps/openmw/mwworld/worldimp.cpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 431ad09b3..e13723044 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1447,6 +1447,11 @@ namespace MWMechanics calculateCreatureStatModifiers (iter->first, duration); if (iter->first.getClass().isNpc()) calculateNpcStatModifiers(iter->first, duration); + + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first); + if (animation) + animation->updateEffects(duration); + } fastForwardAi(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 08b0e7182..da1cf1396 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -823,7 +823,10 @@ namespace MWWorld mWeatherManager->advanceTime (hours, incremental); if (!incremental) + { + mRendering->notifyWorldSpaceChanged(); mProjectileManager->clear(); + } hours += mGameHour->getFloat(); From ac7b1bf97db6ef85c14dabad79d606d6638217a4 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Fri, 28 Jul 2017 19:16:32 +0200 Subject: [PATCH 023/136] appstream to new location: https://lintian.debian.org/tags/appstream-metadata-in-legacy-location.html --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56b42ed5d..be0519882 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,7 +413,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") From 6d4bb9e130f350f905925a3fd1b37684c3435913 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 28 Jul 2017 21:58:23 +0000 Subject: [PATCH 024/136] Add policy on original engine "fixes" Since the topic came up again on #1350, I figured to write down this policy. It is what I gathered from many discussions in the past and some "bugs" that we had fixed then later reverted when complaints came in. Do we all agree on this? --- CONTRIBUTING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 466910ca3..df5497885 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,3 +33,25 @@ Furthermore, we advise to: * Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. * If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). * Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway. + +Policy on original engine "fixes" +============================= + +From time to time you may be tempted to "fix" what you think was a "bug" in the original game engine. + +Unfortunately, the definition of what is a "bug" is not so clear. Consider that your "bug" is actually a feature unless proven otherwise: + +* We have no way of knowing what the original developers really intended (short of asking them, good luck with that). +* What may seem like an illogical mechanic can actually be part of an attempt to balance the game. +* Many people will actually like these "bugs" because that is what they remember the game for. +* Exploits may be part of the fun of an open-world game - they reward knowledge with power. There are too many of them to plug them all, anyway. + +OpenMW, in its default configuration, is meant to be a faithful reimplementation of Morrowind, minus things like crash bugs, stability issues and design errors. However, we try to avoid touching anything that affects the core gameplay, the balancing of the game or introduces incompatibilities with existing mod content. + +That said, we may sometimes evaluate such issues on an individual basis. Common exceptions to the above would be: + +* Issues so glaring that they would severely limit the capabilities of the engine in the future (for example, the scripting engine not being allowed to access objects in remote cells) +* Bugs where the intent is very obvious, and that have little to no balancing impact (e.g. the bug were being tired made it easier to repair items, instead of harder) +* Bugs that were fixed in an official patch for Morrowind + +In the future, we may offer additional settings to turn each "bug" or exploit on/off, or allow modders to do so by means of scripting. From cf6f3685604cab05e552ad7e73543f1fab8cdd5a Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sat, 29 Jul 2017 11:52:13 +0200 Subject: [PATCH 025/136] rtd backport fix --- CMakeLists.txt | 2 +- docs/requirements.txt | 1 - docs/source/conf.py | 40 +-- docs/source/index.rst | 11 +- docs/source/source/index.rst | 8 - docs/source/source/opencs/index.rst | 11 - docs/source/source/opencs/model/index.rst | 358 ---------------------- docs/source/source/opencs/view/index.rst | 340 -------------------- docs/source/source/openmw/index.rst | 24 -- docs/source/source/openmw/mwbase.rst | 32 -- docs/source/source/openmw/mwclass.rst | 68 ---- docs/source/source/openmw/mwdialogue.rst | 32 -- docs/source/source/openmw/mwgui.rst | 227 -------------- docs/source/source/openmw/mwinput.rst | 5 - docs/source/source/openmw/mwmechanics.rst | 137 --------- docs/source/source/openmw/mwphysics.rst | 15 - docs/source/source/openmw/mwrender.rst | 77 ----- docs/source/source/openmw/mwscript.rst | 65 ---- docs/source/source/openmw/mwsound.rst | 29 -- docs/source/source/openmw/mwstate.rst | 11 - docs/source/source/openmw/mwworld.rst | 132 -------- 21 files changed, 3 insertions(+), 1622 deletions(-) delete mode 100644 docs/source/source/index.rst delete mode 100644 docs/source/source/opencs/index.rst delete mode 100644 docs/source/source/opencs/model/index.rst delete mode 100644 docs/source/source/opencs/view/index.rst delete mode 100644 docs/source/source/openmw/index.rst delete mode 100644 docs/source/source/openmw/mwbase.rst delete mode 100644 docs/source/source/openmw/mwclass.rst delete mode 100644 docs/source/source/openmw/mwdialogue.rst delete mode 100644 docs/source/source/openmw/mwgui.rst delete mode 100644 docs/source/source/openmw/mwinput.rst delete mode 100644 docs/source/source/openmw/mwmechanics.rst delete mode 100644 docs/source/source/openmw/mwphysics.rst delete mode 100644 docs/source/source/openmw/mwrender.rst delete mode 100644 docs/source/source/openmw/mwscript.rst delete mode 100644 docs/source/source/openmw/mwsound.rst delete mode 100644 docs/source/source/openmw/mwstate.rst delete mode 100644 docs/source/source/openmw/mwworld.rst diff --git a/CMakeLists.txt b/CMakeLists.txt index ec7e2577c..7a2ac34c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -407,7 +407,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/metainfo" COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/docs/requirements.txt b/docs/requirements.txt index 6ee8d6987..72c2aaa12 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,2 @@ -breathe parse_cmake sphinx diff --git a/docs/source/conf.py b/docs/source/conf.py index 273b2f7d5..b18b40c50 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,7 +11,6 @@ # # All configuration values have a default; values that are commented out # serve to show the default. -import glob import os import sys @@ -21,12 +20,6 @@ import sys project_root = os.path.abspath('../../') sys.path.insert(0, project_root) - -def insensitive_glob(pattern): - def either(c): - return '[%s%s]' % (c.lower(), c.upper()) if c.isalpha() else c - return glob.glob(''.join(map(either, pattern))) - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -43,37 +36,6 @@ extensions = [ 'sphinx.ext.viewcode', ] -try: - import breathe - extensions.append('breathe') -except ImportError: - print("WARNING: Unable to import breathe, code documentation won't be generated.") - -# Where breathe can find the source files -openmw_path = os.path.join(project_root, "apps", "openmw") -openmw_sub_dirs = os.walk(openmw_path).next()[1] -openmw_headers = insensitive_glob(os.path.join(openmw_path, "*.hpp")) -for dir in openmw_sub_dirs: - openmw_headers += insensitive_glob(os.path.join(openmw_path, dir, "*.hpp")) -# massage the headers to get the relative path needed -openmw_headers = [os.path.relpath(x, openmw_path) for x in openmw_headers] - -opencs_path = os.path.join(project_root, "apps", "opencs") -opencs_sub_dirs = os.walk(opencs_path).next()[1] -opencs_headers = insensitive_glob(os.path.join(opencs_path, "*.hpp")) -opencs_sub_sub_dirs = [] -for dir in opencs_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, "*.hpp")) - opencs_sub_sub_dirs += os.walk(os.path.join(opencs_path, dir)).next()[1] - for sub_dir in opencs_sub_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, sub_dir, "*.hpp")) -opencs_headers = [os.path.relpath(x, opencs_path) for x in opencs_headers] - -breathe_projects_source = { - "openmw": (openmw_path, openmw_headers), - "opencs": (opencs_path, opencs_headers), -} - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -88,7 +50,7 @@ master_doc = 'index' # General information about the project. project = u'OpenMW' -copyright = u'2016, OpenMW Team' +copyright = u'2017, OpenMW Team' # The version info for the project you're documenting, acts as replacement for diff --git a/docs/source/index.rst b/docs/source/index.rst index f51cda909..3781733cb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,16 +5,7 @@ Sections -------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 manuals/index reference/index - source/index - - -Indices and Tables -================== - -* :ref:`genindex` -* :ref:`search` - diff --git a/docs/source/source/index.rst b/docs/source/source/index.rst deleted file mode 100644 index b58bf2b37..000000000 --- a/docs/source/source/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Project Source Documentation -============================ - -.. toctree:: - :maxdepth: 2 - - openmw/index - opencs/index \ No newline at end of file diff --git a/docs/source/source/opencs/index.rst b/docs/source/source/opencs/index.rst deleted file mode 100644 index b648bc49c..000000000 --- a/docs/source/source/opencs/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -OpenMW-CS Source Documentation -############################## - -.. toctree:: - :maxdepth: 2 - - model/index - view/index - -.. autodoxygenfile:: editor.hpp - :project: opencs \ No newline at end of file diff --git a/docs/source/source/opencs/model/index.rst b/docs/source/source/opencs/model/index.rst deleted file mode 100644 index 38ca0c31c..000000000 --- a/docs/source/source/opencs/model/index.rst +++ /dev/null @@ -1,358 +0,0 @@ -./opencs/model -############## - -doc ---- - .. autodoxygenfile:: model/doc/blacklist.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/document.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/documentmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/messages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operationholder.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/runner.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/saving.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstate.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/stage.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/state.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: model/filter/andnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/booleannode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/leafnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/narynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/node.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/notnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/ornode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/parser.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/textnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/unarynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/valuenode.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: model/prefs/boolsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/category.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/coloursetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/doublesetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/enumsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/intsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/modifiersetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/setting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcuteventhandler.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcut.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/state.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: model/tools/birthsigncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/bodypartcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/classcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/factioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/gmstcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/journalcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/magiceffectcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mandatoryid.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergeoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestages.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestate.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/pathgridcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/racecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referenceablecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referencecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/regioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/reportmodel.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/scriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/search.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchstage.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/skillcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundgencheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/spellcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/startscriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/tools.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/topicinfocheck.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: model/world/cellcoordinates.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cell.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cellselection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collectionbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columns.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commanddispatcher.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commandmacro.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commands.hpp - :project: opencs - - .. autodoxygenfile:: model/world/data.hpp - :project: opencs - - .. autodoxygenfile:: model/world/defaultgmsts.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcompletionmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtablebase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtree.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/info.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infoselectwrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infotableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/land.hpp - :project: opencs - - .. autodoxygenfile:: model/world/landtexture.hpp - :project: opencs - - .. autodoxygenfile:: model/world/metadata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcoladapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcolumnadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedinfocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtablewrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: model/world/record.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/ref.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refiddata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resources.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcesmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcetable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scope.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scriptcontext.hpp - :project: opencs - - .. autodoxygenfile:: model/world/subcellcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/tablemimedata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/universalid.hpp - :project: opencs - diff --git a/docs/source/source/opencs/view/index.rst b/docs/source/source/opencs/view/index.rst deleted file mode 100644 index 54d00ccc0..000000000 --- a/docs/source/source/opencs/view/index.rst +++ /dev/null @@ -1,340 +0,0 @@ -./opencs/view -############# - -doc ---- - .. autodoxygenfile:: view/doc/adjusterwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filedialog.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/globaldebugprofilemenu.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/newgame.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operations.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/runlogsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/sizehint.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/startup.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactory.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactoryimp.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/view.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/viewmanager.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: view/filter/editwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/filterbox.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/recordfilterbox.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: view/prefs/dialogue.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/keybindingpage.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/pagebase.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/page.hpp - :project: opencs - -render ------- - .. autodoxygenfile:: view/render/cameracontroller.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellarrow.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellborder.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cell.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellmarker.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellwater.hpp - :project: opencs - - .. autodoxygenfile:: view/render/editmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemovemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instanceselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingbright.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingday.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lighting.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingnight.hpp - :project: opencs - - .. autodoxygenfile:: view/render/mask.hpp - :project: opencs - - .. autodoxygenfile:: view/render/object.hpp - :project: opencs - - .. autodoxygenfile:: view/render/orbitcameramode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/previewwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/scenewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/selectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/tagbase.hpp - :project: opencs - - .. autodoxygenfile:: view/render/terrainstorage.hpp - :project: opencs - - .. autodoxygenfile:: view/render/unpagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/worldspacewidget.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: view/tools/merge.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reportsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reporttable.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchbox.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/subviews.hpp - :project: opencs - -widget ------- - .. autodoxygenfile:: view/widget/coloreditor.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/colorpickerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/completerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/droplineedit.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/modebutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/pushbutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolbar.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetool.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolmode.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolrun.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle2.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: view/world/cellcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/colordelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/creator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/datadisplaydelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguespinbox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragdroputils.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragrecordtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/enumdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/extendedcommandconfigurator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/genericcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/globalcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idcompletiondelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idtypedelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idvalidator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/infocreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/nestedtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/pathgridcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/previewsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordbuttonbar.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordstatusdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referenceablecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referencecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmapsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scenesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptedit.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripterrortable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripthighlighter.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/startscriptcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/subviews.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablebottombox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tableeditidaction.hpp - :project: opencs - - .. autodoxygenfile:: view/world/table.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/util.hpp - :project: opencs - - .. autodoxygenfile:: view/world/vartypedelegate.hpp - :project: opencs diff --git a/docs/source/source/openmw/index.rst b/docs/source/source/openmw/index.rst deleted file mode 100644 index 5367995de..000000000 --- a/docs/source/source/openmw/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -OpenMW Source Documentation -########################### - -.. toctree:: - :maxdepth: 2 - - mwbase - mwclass - mwdialogue - mwgui - mwinput - mwmechanics - mwphysics - mwrender - mwscript - mwsound - mwstate - mwworld - -.. autodoxygenfile:: engine.hpp - :project: openmw - -.. autodoxygenfile:: doc.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwbase.rst b/docs/source/source/openmw/mwbase.rst deleted file mode 100644 index 8fd7ffc1e..000000000 --- a/docs/source/source/openmw/mwbase.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwbase -######## - -.. autodoxygenfile:: mwbase/dialoguemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/environment.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/inputmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/journal.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/mechanicsmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/scriptmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/soundmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/statemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/windowmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/world.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwclass.rst b/docs/source/source/openmw/mwclass.rst deleted file mode 100644 index 3365d2582..000000000 --- a/docs/source/source/openmw/mwclass.rst +++ /dev/null @@ -1,68 +0,0 @@ -./mwclass -######### - -.. autodoxygenfile:: mwclass/activator.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/apparatus.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/armor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/bodypart.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/book.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/classes.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/clothing.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/container.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creature.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creaturelevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/ingredient.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/itemlevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/light.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/lockpick.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/misc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/npc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/potion.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/probe.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/static.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/weapon.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwdialogue.rst b/docs/source/source/openmw/mwdialogue.rst deleted file mode 100644 index 1f3522f2c..000000000 --- a/docs/source/source/openmw/mwdialogue.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwdialogue -############ - -.. autodoxygenfile:: mwdialogue/dialoguemanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/filter.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/hypertextparser.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalentry.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/keywordsearch.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/quest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/scripttest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/selectwrapper.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/topic.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwgui.rst b/docs/source/source/openmw/mwgui.rst deleted file mode 100644 index 0e3726832..000000000 --- a/docs/source/source/openmw/mwgui.rst +++ /dev/null @@ -1,227 +0,0 @@ -./mwgui -####### - -.. autodoxygenfile:: mwgui/alchemywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/backgroundimage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/birth.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookpage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/charactercreation.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/class.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/confirmationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/console.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/container.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/containeritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/controllers.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/countdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/cursor.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/debugwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/dialogue.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/draganddrop.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/enchantingdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/exposedwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/formatting.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/hud.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventoryitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventorywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemchargeview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemselection.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemwidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/jailscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalbooks.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalviewmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/layout.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/levelupdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/loadingscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mainmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mapwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/merchantrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/messagebox.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mode.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/pickpocketitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/quickkeysmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/race.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/recharge.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/referenceinterface.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/review.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/savegamedialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/screenfader.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/scrollwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/settingswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/sortfilteritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/soulgemdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellbuyingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellcreationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellicons.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/statswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/textinput.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/timeadvancer.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tooltips.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradeitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradewindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/trainingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/travelwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/videowidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/waitdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/widgets.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowbase.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowpinnablebase.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwinput.rst b/docs/source/source/openmw/mwinput.rst deleted file mode 100644 index b24d8dfdb..000000000 --- a/docs/source/source/openmw/mwinput.rst +++ /dev/null @@ -1,5 +0,0 @@ -./mwinput -######### - -.. autodoxygenfile:: mwinput/inputmanagerimp.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwmechanics.rst b/docs/source/source/openmw/mwmechanics.rst deleted file mode 100644 index 3427b712a..000000000 --- a/docs/source/source/openmw/mwmechanics.rst +++ /dev/null @@ -1,137 +0,0 @@ -./mwmechanics -############# - -.. autodoxygenfile:: mwmechanics/activespells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actors.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actorutil.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiactivate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiavoiddoor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombataction.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiescort.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiface.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aifollow.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipackage.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipursue.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aisequence.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aistate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aitravel.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiwander.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/alchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/autocalcspell.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/character.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/combat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/coordinateconverter.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/creaturestats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/difficultyscaling.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/disease.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/drawstate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/enchanting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/levelledlist.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/magiceffects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/mechanicsmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/movement.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/npcstats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/obstacle.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathfinding.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pickpocket.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/security.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spellcasting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/stat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/steering.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/summoning.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/trading.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwphysics.rst b/docs/source/source/openmw/mwphysics.rst deleted file mode 100644 index 6eebab4d9..000000000 --- a/docs/source/source/openmw/mwphysics.rst +++ /dev/null @@ -1,15 +0,0 @@ -./mwphysics -########### - -.. autodoxygenfile:: mwphysics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/collisiontype.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/convert.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/physicssystem.hpp - :project: openmw - diff --git a/docs/source/source/openmw/mwrender.rst b/docs/source/source/openmw/mwrender.rst deleted file mode 100644 index d284f6586..000000000 --- a/docs/source/source/openmw/mwrender.rst +++ /dev/null @@ -1,77 +0,0 @@ -./mwrender -########## - -.. autodoxygenfile:: mwrender/actoranimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/animation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/bulletdebugdraw.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/camera.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/cell.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/characterpreview.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/creatureanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/effectmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/globalmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/localmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/npcanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderbin.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderinginterface.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderingmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rendermode.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/ripplesimulation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rotatecontroller.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/sky.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/terrainstorage.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/util.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/vismask.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/water.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/weaponanimation.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwscript.rst b/docs/source/source/openmw/mwscript.rst deleted file mode 100644 index 8db8f40e2..000000000 --- a/docs/source/source/openmw/mwscript.rst +++ /dev/null @@ -1,65 +0,0 @@ -./mwscript -########## - -.. autodoxygenfile:: mwscript/aiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/animationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/cellextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/compilercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/consoleextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/containerextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/controlextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/dialogueextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/extensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/globalscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/guiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/interpretercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/locals.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/miscextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/ref.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/scriptmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/skyextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/soundextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/statsextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/transformationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/userextensions.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwsound.rst b/docs/source/source/openmw/mwsound.rst deleted file mode 100644 index d4fcb0e6b..000000000 --- a/docs/source/source/openmw/mwsound.rst +++ /dev/null @@ -1,29 +0,0 @@ -./mwsound -######### - -.. autodoxygenfile:: mwsound/ffmpeg_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/loudness.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/movieaudiofactory.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/openal_output.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_buffer.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/soundmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_output.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwstate.rst b/docs/source/source/openmw/mwstate.rst deleted file mode 100644 index 2618c6ff0..000000000 --- a/docs/source/source/openmw/mwstate.rst +++ /dev/null @@ -1,11 +0,0 @@ -./mwstate -######### - -.. autodoxygenfile:: mwstate/character.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/charactermanager.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/statemanagerimp.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwworld.rst b/docs/source/source/openmw/mwworld.rst deleted file mode 100644 index 21026b3e2..000000000 --- a/docs/source/source/openmw/mwworld.rst +++ /dev/null @@ -1,132 +0,0 @@ -./mwworld -######### - -.. autodoxygenfile:: mwworld/actionalchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionapply.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiondoor.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actioneat.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionequip.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/action.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionopen.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionread.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionsoulgem.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontake.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontalk.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionteleport.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontrap.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellpreloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellreflist.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cells.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellvisitors.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/class.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/containerstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/contentloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/customdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/failedaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/globals.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/inventorystore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/livecellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/localscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/manualref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/nullaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/player.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/projectilemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/ptr.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/recordcmp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/refdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/scene.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/store.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/timestamp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/weather.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/worldimp.hpp - :project: openmw - From dae19412f239c255128c40f237e695e7898e574b Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 29 Jul 2017 20:41:12 +0900 Subject: [PATCH 026/136] Fix problem with animations not looping Fixes #3804 --- apps/openmw/mwmechanics/character.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c1eb2d056..661df35b0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2043,13 +2043,13 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int } else { - // If the given animation is a looped animation, is already playing - // and has not yet reached its Loop Stop key, make it the only animation - // in the queue, and retain the loop count from the animation that was - // already playing. This emulates observed behavior from the original - // engine and allows banners to animate correctly. + // 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->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && + mAnimation->isPlaying(groupname)) { float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); @@ -2058,8 +2058,7 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) { - mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, true); - mAnimQueue.resize(1); + mAnimQueue.resize(1); return true; } } From deaeda464e65661281219c9dcb50c3e13c2d818c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 29 Jul 2017 14:19:15 +0000 Subject: [PATCH 027/136] Update CONTRIBUTING.md --- CONTRIBUTING.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df5497885..e87ddafa7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,8 +34,8 @@ Furthermore, we advise to: * If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). * Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway. -Policy on original engine "fixes" -============================= +Guidelines for original engine "fixes" +================================= From time to time you may be tempted to "fix" what you think was a "bug" in the original game engine. @@ -52,6 +52,4 @@ That said, we may sometimes evaluate such issues on an individual basis. Common * Issues so glaring that they would severely limit the capabilities of the engine in the future (for example, the scripting engine not being allowed to access objects in remote cells) * Bugs where the intent is very obvious, and that have little to no balancing impact (e.g. the bug were being tired made it easier to repair items, instead of harder) -* Bugs that were fixed in an official patch for Morrowind - -In the future, we may offer additional settings to turn each "bug" or exploit on/off, or allow modders to do so by means of scripting. +* Bugs that were fixed in an official patch for Morrowind From 99b5f21a469fc4fdfb5cf378612189d11c5acc0a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 29 Jul 2017 19:41:46 +0400 Subject: [PATCH 028/136] Add missing journal sounds (bug #3974) --- apps/openmw/mwgui/journalwindow.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index b5653508d..bb8d5fd4e 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -292,6 +292,8 @@ namespace // If in quest mode, ensure the quest list is updated if (mQuestMode) notifyQuests(getWidget(QuestsList)); + else + notifyTopics(getWidget(TopicsList)); } void pushBook (Book book, unsigned int page) @@ -370,6 +372,8 @@ namespace setVisible (JournalBTN, true); mOptionsMode = false; + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyTopicSelected (const std::string& topic, int id) @@ -399,6 +403,8 @@ namespace setVisible (JournalBTN, true); mOptionsMode = false; + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyOptions(MyGUI::Widget* _sender) @@ -416,6 +422,8 @@ namespace { assert (mStates.size () > 1); popBook (); + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character) @@ -432,6 +440,8 @@ namespace mModel->visitTopicNamesStartingWith((char) character, add); list->adjustSize(); + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyTopics(MyGUI::Widget* _sender) @@ -443,6 +453,8 @@ namespace setVisible (QuestsList, false); setVisible (ShowAllBTN, false); setVisible (ShowActiveBTN, false); + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } struct AddNamesToList @@ -494,6 +506,8 @@ namespace SetNamesInactive setInactive(list); mModel->visitQuestNames(!mAllQuests, setInactive); } + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyShowAll(MyGUI::Widget* _sender) @@ -510,7 +524,9 @@ namespace void notifyCancel(MyGUI::Widget* _sender) { - setBookMode (); + setBookMode(); + + MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyClose(MyGUI::Widget* _sender) @@ -539,6 +555,8 @@ namespace if (page+2 < book->pageCount()) { + MWBase::Environment::get().getWindowManager()->playSound("book page"); + page += 2; updateShowingPages (); } @@ -555,6 +573,8 @@ namespace if(page >= 2) { + MWBase::Environment::get().getWindowManager()->playSound("book page"); + page -= 2; updateShowingPages (); } From fd0be7008d249b99cac842a4d9cb47323b2f7be5 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 30 Jul 2017 15:42:16 +0200 Subject: [PATCH 029/136] [macOS] Fixes accidental loading of plugins from system-wide Qt install I was too eager to remove the workaround in 014a2fc0e924b9229e8da812eddf85b883cd8a8e. Actually, config-based solution seems cleaner. Respective Qt documentation: http://doc.qt.io/qt-5/qt-conf.html. Also, moves Qt plugins from Contents/MacOS to Contents/PlugIns for consistency. --- CMakeLists.txt | 14 ++++++++------ files/mac/qt.conf | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 files/mac/qt.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index be0519882..5df3b27d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -718,17 +718,19 @@ if (WIN32) endif() # Apple bundling -if (APPLE AND DESIRED_QT_VERSION MATCHES 5) +if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5) get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE) get_filename_component(QT_COCOA_PLUGIN_DIR "${QT_COCOA_PLUGIN_PATH}" DIRECTORY) get_filename_component(QT_COCOA_PLUGIN_GROUP "${QT_COCOA_PLUGIN_DIR}" NAME) get_filename_component(QT_COCOA_PLUGIN_NAME "${QT_COCOA_PLUGIN_PATH}" NAME) - configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + configure_file("${QT_COCOA_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${APP_BUNDLE_DIR}/Contents/Resources/qt.conf" COPYONLY) if (BUILD_OPENCS) get_property(OPENCS_BUNDLE_NAME_TMP TARGET openmw-cs PROPERTY OUTPUT_NAME) set(OPENCS_BUNDLE_NAME "${OPENCS_BUNDLE_NAME_TMP}.app") - configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) + configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${OPENCS_BUNDLE_NAME}/Contents/Resources/qt.conf" COPYONLY) endif () install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime) @@ -787,8 +789,8 @@ if (APPLE AND DESIRED_QT_VERSION MATCHES 5) install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) - set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") - set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") + set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") install(CODE " function(gp_item_default_embedded_path_override item default_embedded_path_var) @@ -803,7 +805,7 @@ if (APPLE AND DESIRED_QT_VERSION MATCHES 5) fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") " COMPONENT Runtime) include(CPack) -endif (APPLE AND DESIRED_QT_VERSION MATCHES 5) +endif () # Doxygen Target -- simply run 'make doc' or 'make doc_pages' # output directory for 'make doc' is "${OpenMW_BINARY_DIR}/docs/Doxygen" diff --git a/files/mac/qt.conf b/files/mac/qt.conf new file mode 100644 index 000000000..64d729736 --- /dev/null +++ b/files/mac/qt.conf @@ -0,0 +1,2 @@ +[Paths] +Plugins = PlugIns From 49b02a1bf48ecc2486d354d07ae4b19c1844822e Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 30 Jul 2017 15:48:00 +0200 Subject: [PATCH 030/136] [macOS] remove use of deprecated CMake policy --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5df3b27d2..f274875c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -800,7 +800,6 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5) endif() endfunction() - cmake_policy(SET CMP0009 OLD) fixup_bundle(\"${INSTALLED_OPENMW_APP}\" \"${PLUGINS}\" \"\") fixup_bundle(\"${INSTALLED_OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"\") " COMPONENT Runtime) From ccae2325639bc54d0231b4a85af4b29f44b3cb0b Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 30 Jul 2017 16:34:49 +0200 Subject: [PATCH 031/136] [macOS, CI] Use most recent available Qt --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 48836b7bb..467900ff9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ env: - secure: "MegynKyJpyL7XDwdWVEbypQh7CLjqOqOi9lGF97G7Fq0HosVZTmnwjHhmIPZspTP7ES4UbxM3rs/f3ce7sp9JN2ShRJpduD6UEFc8egQXBte9J3obUBIdUxPTRdhnht7VJ+u+pksK1S/Bm1Cs6l0eEluP3vmcaXWMykVQcZsPhY=" # macOS builds FTP upload password - secure: "jQcAaWAdDy0+vlNu4POMX8322HanCOQEUTdpviWTAUjWQTjMa0UTM4+zVVgrtEaHMpBaVYYbTT3Rg5BQ9oG+2SiVLJBQQ2XoMcos/YrjPVT6inB02Gs0vFjP29LdPAQVrB8CkAcfQr6u+Z2C+RqAtwhE09LsBUMXjRDzPAtr1CM=" - - macos_qt_formula=qt@5.7 + - macos_qt_formula=qt addons: apt: sources: From bfbfbeac437c42051f09af08ec2d9f627246c268 Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 31 Jul 2017 03:45:47 +1000 Subject: [PATCH 032/136] Added networking and saving for custom spells --- apps/openmw-mp/Script/Functions/Spells.cpp | 207 ++++++++++++++++++ apps/openmw-mp/Script/Functions/Spells.hpp | 182 ++++++++++++++- apps/openmw/mwmp/LocalPlayer.cpp | 28 ++- .../Packets/Player/PacketPlayerSpellbook.cpp | 34 +++ 4 files changed, 446 insertions(+), 5 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Spells.cpp b/apps/openmw-mp/Script/Functions/Spells.cpp index 2375fe591..05fbf5011 100644 --- a/apps/openmw-mp/Script/Functions/Spells.cpp +++ b/apps/openmw-mp/Script/Functions/Spells.cpp @@ -49,6 +49,70 @@ void SpellFunctions::AddSpell(unsigned short pid, const char* spellId) noexcept player->spellbookChanges.spells.push_back(spell); } +void SpellFunctions::AddCustomSpell(unsigned short pid, const char* spellId, const char* spellName) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + ESM::Spell spell; + spell.mName = spellName; + spell.mId = spellId; + + player->spellbookChanges.spells.push_back(spell); +} + +void SpellFunctions::AddCustomSpellData(unsigned short pid, const char* spellId, int type, int cost, int flags) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + int index = -1; + for(int i = 0; i < player->spellbookChanges.spells.size(); i++) + { + if( strcmp(player->spellbookChanges.spells.at(i).mId.c_str(), spellId) == 0) + { + index = i; + } + } + + if(index == -1) + return; + + player->spellbookChanges.spells.at(index).mData.mType = type; + player->spellbookChanges.spells.at(index).mData.mCost = cost; + player->spellbookChanges.spells.at(index).mData.mFlags = flags; +} + +void SpellFunctions::AddCustomSpellEffect(unsigned short pid, const char* spellId, short effectId, signed char mSkill, signed char mAttribute, int mRange, int mArea, int mDuration, int mMagnMin, int mMagnMax) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + int index = -1; + for(int i = 0; i < player->spellbookChanges.spells.size(); i++) + { + if( strcmp(player->spellbookChanges.spells.at(i).mId.c_str(), spellId) == 0) + { + index = i; + } + } + + if(index == -1) + return; + + ESM::ENAMstruct effect; + effect.mEffectID = effectId; + effect.mSkill = mSkill; + effect.mAttribute = mAttribute; + effect.mRange = mRange; + effect.mArea = mArea; + effect.mDuration = mDuration; + effect.mMagnMin = mMagnMin; + effect.mMagnMax = mMagnMax; + + player->spellbookChanges.spells.at(index).mEffects.mList.push_back(effect); +} + const char *SpellFunctions::GetSpellId(unsigned short pid, unsigned int i) noexcept { Player *player; @@ -60,6 +124,149 @@ const char *SpellFunctions::GetSpellId(unsigned short pid, unsigned int i) noexc return player->spellbookChanges.spells.at(i).mId.c_str(); } +const char *SpellFunctions::GetSpellName(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ""); + + if (i >= player->spellbookChanges.count) + return "invalid"; + + return player->spellbookChanges.spells.at(i).mName.c_str(); +} + +int SpellFunctions::GetSpellType(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mData.mType; +} + +int SpellFunctions::GetSpellCost(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mData.mCost; +} + +int SpellFunctions::GetSpellFlags(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mData.mFlags; +} + +unsigned int SpellFunctions::GetSpellEffectCount(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.size(); +} + +short SpellFunctions::GetSpellEffectId(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mEffectID; +} + +signed char SpellFunctions::GetSpellEffectSkill(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mSkill; +} + +signed char SpellFunctions::GetSpellEffectAttribute(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mAttribute; +} + +int SpellFunctions::GetSpellEffectRange(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mRange; +} + +int SpellFunctions::GetSpellEffectArea(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mArea; +} + +int SpellFunctions::GetSpellEffectDuration(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mDuration; +} + +int SpellFunctions::GetSpellEffectMagnMin(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mMagnMin; +} + +int SpellFunctions::GetSpellEffectMagnMax(unsigned short pid, unsigned int i, unsigned int j) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->spellbookChanges.count) + return 0; + + return player->spellbookChanges.spells.at(i).mEffects.mList.at(j).mMagnMax; +} + void SpellFunctions::SendSpellbookChanges(unsigned short pid, bool toOthers) noexcept { Player *player; diff --git a/apps/openmw-mp/Script/Functions/Spells.hpp b/apps/openmw-mp/Script/Functions/Spells.hpp index bf3e1d307..6984a8455 100644 --- a/apps/openmw-mp/Script/Functions/Spells.hpp +++ b/apps/openmw-mp/Script/Functions/Spells.hpp @@ -9,8 +9,24 @@ \ {"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\ {"AddSpell", SpellFunctions::AddSpell},\ + {"AddCustomSpell", SpellFunctions::AddCustomSpell},\ + {"AddCustomSpellData", SpellFunctions::AddCustomSpellData},\ + {"AddCustomSpellEffect", SpellFunctions::AddCustomSpellEffect},\ \ {"GetSpellId", SpellFunctions::GetSpellId},\ + {"GetSpellName", SpellFunctions::GetSpellName},\ + {"GetSpellType", SpellFunctions::GetSpellType},\ + {"GetSpellCost", SpellFunctions::GetSpellCost},\ + {"GetSpellFlags", SpellFunctions::GetSpellFlags},\ + {"GetSpellEffectCount", SpellFunctions::GetSpellEffectCount},\ + {"GetSpellEffectId", SpellFunctions::GetSpellEffectId},\ + {"GetSpellEffectSkill", SpellFunctions::GetSpellEffectSkill},\ + {"GetSpellEffectAttribute", SpellFunctions::GetSpellEffectAttribute},\ + {"GetSpellEffectRange", SpellFunctions::GetSpellEffectRange},\ + {"GetSpellEffectArea", SpellFunctions::GetSpellEffectArea},\ + {"GetSpellEffectDuration", SpellFunctions::GetSpellEffectDuration},\ + {"GetSpellEffectMagnMin", SpellFunctions::GetSpellEffectMagnMin},\ + {"GetSpellEffectMagnMax", SpellFunctions::GetSpellEffectMagnMax},\ \ {"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges} @@ -57,11 +73,50 @@ public: * \brief Add a new spell to the spellbook changes for a player. * * \param pid The player ID whose spellbook changes should be used. - * \param topicId The spellId of the spell. + * \param spellId The spellId of the spell. * \return void */ static void AddSpell(unsigned short pid, const char* spellId) noexcept; + /** + * \brief Add a new custom spell to the spellbook changes for a player. + * + * \param pid The player ID whose spellbook changes should be used. + * \param spellId The spellId of the spell. + * \param spellName The name of the spell. + * \return void + */ + static void AddCustomSpell(unsigned short pid, const char* spellId, const char* spellName) noexcept; + + /** + * \brief Add custom spell data to the spellbook changes for a player. + * + * \param pid The player ID whose spellbook changes should be used. + * \param spellId The spellId of the spell. + * \param type The type of the spell. + * \param cost The cost of the spell. + * \param flags The flags of the spell. + * \return void + */ + static void AddCustomSpellData(unsigned short pid, const char* spellId, int type, int cost, int flags) noexcept; + + /** + * \brief Add custom spell effect to the spellbook changes for a player. + * + * \param pid The player ID whose spellbook changes should be used. + * \param spellId The spellId of the spell. + * \param effectId The effectId of the spell effect. + * \param mSkill The skill affected by the spell effect. + * \param mAttribute The attribute affected by the spell effect. + * \param mRange The range of the spell effect. + * \param mArea The area of the spell effect. + * \param mDuration The duration of the spell effect. + * \param mMagnMin The minimum magnitude of the spell effect. + * \param mMagnMax The maximum magnitude of the spell effect. + * \return void + */ + static void AddCustomSpellEffect(unsigned short pid, const char* spellId, short effectId, signed char mSkill, signed char mAttribute, int mRange, int mArea, int mDuration, int mMagnMin, int mMagnMax) noexcept; + /** * \brief Get the spellId at a certain index in a player's latest spellbook changes. * @@ -71,6 +126,131 @@ public: */ static const char *GetSpellId(unsigned short pid, unsigned int i) noexcept; + /** + * \brief Get the name of the spell at a certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \return The spell name. + */ + static const char *GetSpellName(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the type of the spell at a certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \return The spell type. + */ + static int GetSpellType(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the cost of the spell at a certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \return The spell cost. + */ + static int GetSpellCost(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the flags of the spell at a certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \return The spell flags. + */ + static int GetSpellFlags(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the number of effects on the spell at a certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \return The spell effect count. + */ + static unsigned int GetSpellEffectCount(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the effectId of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The effectId. + */ + static short GetSpellEffectId(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the affected skill of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The affected skill. + */ + static signed char GetSpellEffectSkill(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the affected attribute of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The affected attribute. + */ + static signed char GetSpellEffectAttribute(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the range of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The range. + */ + static int GetSpellEffectRange(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the area of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The area. + */ + static int GetSpellEffectArea(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the duration of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The duration. + */ + static int GetSpellEffectDuration(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the minimum magnitude of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The minimum magnitude. + */ + static int GetSpellEffectMagnMin(unsigned short pid, unsigned int i, unsigned int j) noexcept; + + /** + * \brief Get the maximum magnitude of the effect at a certain index in the spell at another certain index in a player's latest spellbook changes. + * + * \param pid The player ID whose spellbook changes should be used. + * \param i The index of the spell. + * \param j The index of the effect. + * \return The maximum magnitude. + */ + static int GetSpellEffectMagnMax(unsigned short pid, unsigned int i, unsigned int j) noexcept; + /** * \brief Send a PlayerSpellbook packet with a player's recorded spellbook changes. * diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index e4bc4fda7..ecd6cfdef 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -648,8 +648,16 @@ void LocalPlayer::addSpells() MWMechanics::Spells &ptrSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getSpells(); for (const auto &spell : spellbookChanges.spells) - ptrSpells.add(spell.mId); - + { + if(spell.mId.find("$dynamic") != string::npos) + { + //custom spell + MWBase::Environment::get().getWorld()->createRecord(spell); + ptrSpells.add(&spell); + }else{ + ptrSpells.add(spell.mId); + } + } } void LocalPlayer::addJournalItems() @@ -1130,12 +1138,24 @@ void LocalPlayer::sendSpellRemoval(std::string id) void LocalPlayer::sendSpellAddition(const ESM::Spell &spell) { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Not implemented."); + spellbookChanges.spells.clear(); + + spellbookChanges.spells.push_back(spell); + + spellbookChanges.action = SpellbookChanges::ADD; + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->Send(); } void LocalPlayer::sendSpellRemoval(const ESM::Spell &spell) { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Not implemented."); + spellbookChanges.spells.clear(); + + spellbookChanges.spells.push_back(spell); + + spellbookChanges.action = SpellbookChanges::REMOVE; + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->Send(); } void LocalPlayer::sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor) diff --git a/components/openmw-mp/Packets/Player/PacketPlayerSpellbook.cpp b/components/openmw-mp/Packets/Player/PacketPlayerSpellbook.cpp index 724885eb4..b9737390d 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerSpellbook.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerSpellbook.cpp @@ -31,6 +31,40 @@ void PacketPlayerSpellbook::Packet(RakNet::BitStream *bs, bool send) RW(spell.mId, send, 1); + if(spell.mId.find("$dynamic") != string::npos) + { + RW(spell.mName, send, 1); + + RW(spell.mData.mType, send, 1); + RW(spell.mData.mCost, send, 1); + RW(spell.mData.mFlags, send, 1); + + int effectCount = 0; + if (send) + effectCount = spell.mEffects.mList.size(); + + RW(effectCount, send, 1); + + for (unsigned int j = 0; j < effectCount; j++) + { + ESM::ENAMstruct effect; + if (send) + effect = spell.mEffects.mList.at(j); + + RW(effect.mEffectID, send, 1); + RW(effect.mSkill, send, 1); + RW(effect.mAttribute, send, 1); + RW(effect.mRange, send, 1); + RW(effect.mArea, send, 1); + RW(effect.mDuration, send, 1); + RW(effect.mMagnMin, send, 1); + RW(effect.mMagnMax, send, 1); + + if(!send) + spell.mEffects.mList.push_back(effect); + } + } + if (!send) player->spellbookChanges.spells.push_back(spell); } From 196eedf1b044e7bf07611fbc49847420aa182cfd Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 30 Jul 2017 23:51:07 +0200 Subject: [PATCH 033/136] Fix key focus issue with the journal hotkey --- files/mygui/openmw_journal.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 9b530b379..c53f39578 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -3,6 +3,7 @@ + From 43279c49b50a4a13218bc6c8930d958244b440a7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 30 Jul 2017 23:51:32 +0200 Subject: [PATCH 034/136] Go back to index when selecting 'cancel' on topics list --- apps/openmw/mwgui/journalwindow.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index bb8d5fd4e..105f95085 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -58,6 +58,7 @@ namespace Book mTopicIndexBook; bool mQuestMode; bool mOptionsMode; + bool mTopicsMode; bool mAllQuests; template @@ -196,6 +197,7 @@ namespace mQuestMode = false; mAllQuests = false; mOptionsMode = false; + mTopicsMode = false; } void adjustButton (char const * name) @@ -259,6 +261,7 @@ namespace void setBookMode () { mOptionsMode = false; + mTopicsMode = false; setVisible (OptionsBTN, true); setVisible (OptionsOverlay, false); @@ -269,6 +272,7 @@ namespace void setOptionsMode () { mOptionsMode = true; + mTopicsMode = false; setVisible (OptionsBTN, false); setVisible (OptionsOverlay, true); @@ -372,6 +376,7 @@ namespace setVisible (JournalBTN, true); mOptionsMode = false; + mTopicsMode = false; MWBase::Environment::get().getWindowManager()->playSound("book page"); } @@ -432,6 +437,8 @@ namespace setVisible (RightTopicIndex, false); setVisible (TopicsList, true); + mTopicsMode = true; + Gui::MWList* list = getWidget(TopicsList); list->clear(); @@ -447,6 +454,7 @@ namespace void notifyTopics(MyGUI::Widget* _sender) { mQuestMode = false; + mTopicsMode = false; setVisible (LeftTopicIndex, true); setVisible (RightTopicIndex, true); setVisible (TopicsList, false); @@ -524,9 +532,16 @@ namespace void notifyCancel(MyGUI::Widget* _sender) { - setBookMode(); + if (mTopicsMode) + { + notifyTopics(_sender); + } + else + { + setBookMode(); + MWBase::Environment::get().getWindowManager()->playSound("book page"); + } - MWBase::Environment::get().getWindowManager()->playSound("book page"); } void notifyClose(MyGUI::Widget* _sender) From b98e175161d8355eb6925a2548b3c9ab51d7f8af Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sun, 30 Jul 2017 17:40:56 -0500 Subject: [PATCH 035/136] Renaming duplicate horizontalSpacer variable --- files/ui/settingspage.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index bc2abdf2f..4607d35cb 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -53,7 +53,7 @@ - + Qt::Horizontal @@ -115,7 +115,7 @@ - + Qt::Horizontal From e7e875081622b2f90f53d0c89456055949664bd5 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 31 Jul 2017 09:41:23 +0200 Subject: [PATCH 036/136] [macOS, CI] Remove encrypted FTP credentials from repo It seems more convenient to keep them in Travis settings. --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 467900ff9..6606b0290 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,6 @@ env: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE=" - # macOS builds FTP upload login - - secure: "MegynKyJpyL7XDwdWVEbypQh7CLjqOqOi9lGF97G7Fq0HosVZTmnwjHhmIPZspTP7ES4UbxM3rs/f3ce7sp9JN2ShRJpduD6UEFc8egQXBte9J3obUBIdUxPTRdhnht7VJ+u+pksK1S/Bm1Cs6l0eEluP3vmcaXWMykVQcZsPhY=" - # macOS builds FTP upload password - - secure: "jQcAaWAdDy0+vlNu4POMX8322HanCOQEUTdpviWTAUjWQTjMa0UTM4+zVVgrtEaHMpBaVYYbTT3Rg5BQ9oG+2SiVLJBQQ2XoMcos/YrjPVT6inB02Gs0vFjP29LdPAQVrB8CkAcfQr6u+Z2C+RqAtwhE09LsBUMXjRDzPAtr1CM=" - macos_qt_formula=qt addons: apt: From 8384a8aa8a816f9cc31a8178331580f79bc040f3 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 31 Jul 2017 18:57:57 +0800 Subject: [PATCH 037/136] [General] Return sent packet number --- components/openmw-mp/Packets/BasePacket.cpp | 12 ++++++------ components/openmw-mp/Packets/BasePacket.hpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/openmw-mp/Packets/BasePacket.cpp b/components/openmw-mp/Packets/BasePacket.cpp index 2cffec9d0..65b7f5f3c 100644 --- a/components/openmw-mp/Packets/BasePacket.cpp +++ b/components/openmw-mp/Packets/BasePacket.cpp @@ -48,26 +48,26 @@ void BasePacket::SetStreams(RakNet::BitStream *inStream, RakNet::BitStream *outS bsSend = outStream; } -void BasePacket::RequestData(RakNet::RakNetGUID guid) +uint32_t BasePacket::RequestData(RakNet::RakNetGUID guid) { bsSend->ResetWritePointer(); bsSend->Write(packetID); bsSend->Write(guid); - peer->Send(bsSend, HIGH_PRIORITY, RELIABLE_ORDERED, orderChannel, guid, false); + return peer->Send(bsSend, HIGH_PRIORITY, RELIABLE_ORDERED, orderChannel, guid, false); } -void BasePacket::Send(RakNet::AddressOrGUID destination) +uint32_t BasePacket::Send(RakNet::AddressOrGUID destination) { bsSend->ResetWritePointer(); Packet(bsSend, true); - peer->Send(bsSend, priority, reliability, orderChannel, destination, false); + return peer->Send(bsSend, priority, reliability, orderChannel, destination, false); } -void BasePacket::Send(bool toOther) +uint32_t BasePacket::Send(bool toOther) { bsSend->ResetWritePointer(); Packet(bsSend, true); - peer->Send(bsSend, priority, reliability, orderChannel, guid, toOther); + return peer->Send(bsSend, priority, reliability, orderChannel, guid, toOther); } void BasePacket::Read() diff --git a/components/openmw-mp/Packets/BasePacket.hpp b/components/openmw-mp/Packets/BasePacket.hpp index e298d27b7..b51ce0695 100644 --- a/components/openmw-mp/Packets/BasePacket.hpp +++ b/components/openmw-mp/Packets/BasePacket.hpp @@ -17,8 +17,8 @@ namespace mwmp virtual ~BasePacket(); virtual void Packet(RakNet::BitStream *bs, bool send); - virtual void Send(bool toOtherPlayers = true); - virtual void Send(RakNet::AddressOrGUID destination); + virtual uint32_t Send(bool toOtherPlayers = true); + virtual uint32_t Send(RakNet::AddressOrGUID destination); virtual void Read(); void setGUID(RakNet::RakNetGUID guid); @@ -27,7 +27,7 @@ namespace mwmp void SetReadStream(RakNet::BitStream *bitStream); void SetSendStream(RakNet::BitStream *bitStream); void SetStreams(RakNet::BitStream *inStream, RakNet::BitStream *outStream); - virtual void RequestData(RakNet::RakNetGUID guid); + virtual uint32_t RequestData(RakNet::RakNetGUID guid); static size_t headerSize() { From 1aabcdd09cbca646c5dc5c0a4ab8a160bdb46774 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 31 Jul 2017 18:58:51 +0800 Subject: [PATCH 038/136] [General] Add *_WITH_ACK_RECEIPT to master server packets --- components/openmw-mp/Master/PacketMasterAnnounce.cpp | 1 + components/openmw-mp/Master/PacketMasterQuery.cpp | 1 + components/openmw-mp/Master/PacketMasterUpdate.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/components/openmw-mp/Master/PacketMasterAnnounce.cpp b/components/openmw-mp/Master/PacketMasterAnnounce.cpp index dbdc7c4f5..ac8b3cecb 100644 --- a/components/openmw-mp/Master/PacketMasterAnnounce.cpp +++ b/components/openmw-mp/Master/PacketMasterAnnounce.cpp @@ -15,6 +15,7 @@ PacketMasterAnnounce::PacketMasterAnnounce(RakNet::RakPeerInterface *peer) : Bas { packetID = ID_MASTER_ANNOUNCE; orderChannel = CHANNEL_MASTER; + reliability = RELIABLE_ORDERED_WITH_ACK_RECEIPT; } void PacketMasterAnnounce::Packet(BitStream *bs, bool send) diff --git a/components/openmw-mp/Master/PacketMasterQuery.cpp b/components/openmw-mp/Master/PacketMasterQuery.cpp index d70e6de2e..1850de6c5 100644 --- a/components/openmw-mp/Master/PacketMasterQuery.cpp +++ b/components/openmw-mp/Master/PacketMasterQuery.cpp @@ -17,6 +17,7 @@ PacketMasterQuery::PacketMasterQuery(RakNet::RakPeerInterface *peer) : BasePacke { packetID = ID_MASTER_QUERY; orderChannel = CHANNEL_MASTER; + reliability = RELIABLE_ORDERED_WITH_ACK_RECEIPT; } void PacketMasterQuery::Packet(RakNet::BitStream *bs, bool send) diff --git a/components/openmw-mp/Master/PacketMasterUpdate.cpp b/components/openmw-mp/Master/PacketMasterUpdate.cpp index 8b82a1038..54f32e266 100644 --- a/components/openmw-mp/Master/PacketMasterUpdate.cpp +++ b/components/openmw-mp/Master/PacketMasterUpdate.cpp @@ -14,6 +14,7 @@ PacketMasterUpdate::PacketMasterUpdate(RakNet::RakPeerInterface *peer) : BasePac { packetID = ID_MASTER_UPDATE; orderChannel = CHANNEL_MASTER; + reliability = RELIABLE_ORDERED_WITH_ACK_RECEIPT; } void PacketMasterUpdate::Packet(RakNet::BitStream *bs, bool send) From 918658d38362c6d6266489d86d4b88726a8993db Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 31 Jul 2017 19:07:20 +0800 Subject: [PATCH 039/136] [Master] Waiting ACK instead of immediately closing connection. --- apps/master/MasterServer.cpp | 34 +++++++++++++++++++++++++++------- apps/master/MasterServer.hpp | 1 + 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/apps/master/MasterServer.cpp b/apps/master/MasterServer.cpp index c3821d220..f52841317 100644 --- a/apps/master/MasterServer.cpp +++ b/apps/master/MasterServer.cpp @@ -16,6 +16,7 @@ using namespace RakNet; using namespace std; using namespace mwmp; +using namespace chrono; MasterServer::MasterServer(unsigned short maxConnections, unsigned short port) { @@ -55,10 +56,10 @@ void MasterServer::Thread() { Packet *packet = peer->Receive(); - auto now = chrono::steady_clock::now(); + auto now = steady_clock::now(); if (now - startTime >= 60s) { - startTime = chrono::steady_clock::now(); + startTime = steady_clock::now(); for (auto it = servers.begin(); it != servers.end();) { @@ -66,6 +67,17 @@ void MasterServer::Thread() servers.erase(it++); else ++it; } + for(auto id = pendingACKs.begin(); id != pendingACKs.end();) + { + if(now - id->second >= 30s) + { + cout << "timeout: " << peer->GetSystemAddressFromGuid(id->first).ToString() << endl; + peer->CloseConnection(id->first, true); + id = pendingACKs.erase(id); + } + else + ++id; + } } if (packet == nullptr) @@ -90,10 +102,10 @@ void MasterServer::Thread() { pmq.SetServers(reinterpret_cast *>(&servers)); pmq.Send(packet->systemAddress); + pendingACKs[packet->guid] = steady_clock::now(); cout << "Sent info about all " << servers.size() << " servers to " << packet->systemAddress.ToString() << endl; - peer->CloseConnection(packet->systemAddress, true); break; } case ID_MASTER_UPDATE: @@ -107,10 +119,10 @@ void MasterServer::Thread() pair pairPtr(it->first, static_cast(it->second)); pmu.SetServer(&pairPtr); pmu.Send(packet->systemAddress); + pendingACKs[packet->guid] = steady_clock::now(); cout << "Sent info about " << addr.ToString() << " to " << packet->systemAddress.ToString() << endl; } - peer->CloseConnection(packet->systemAddress, true); break; } case ID_MASTER_ANNOUNCE: @@ -126,6 +138,7 @@ void MasterServer::Thread() iter->second.lastUpdate = now; pma.SetFunc(PacketMasterAnnounce::FUNCTION_KEEP); pma.Send(packet->systemAddress); + pendingACKs[packet->guid] = steady_clock::now(); }; if (iter != servers.end()) @@ -135,6 +148,7 @@ void MasterServer::Thread() servers.erase(iter); cout << "Deleted"; pma.Send(packet->systemAddress); + pendingACKs[packet->guid] = steady_clock::now(); } else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_ANNOUNCE) { @@ -159,14 +173,20 @@ void MasterServer::Thread() cout << "Unknown"; pma.SetFunc(PacketMasterAnnounce::FUNCTION_DELETE); pma.Send(packet->systemAddress); + pendingACKs[packet->guid] = steady_clock::now(); } cout << " server " << packet->systemAddress.ToString() << endl; - - peer->CloseConnection(packet->systemAddress, true); break; } + case ID_SND_RECEIPT_ACKED: + uint32_t num; + memcpy(&num, packet->data+1, 4); + cout << "Packet with id " << num << " was delivered." << endl; + pendingACKs.erase(packet->guid); + peer->CloseConnection(packet->systemAddress, true); + break; default: - cout << "Wrong packet" << endl; + cout << "Wrong packet. id " << (unsigned) packet->data[0] << " packet length " << packet->length << " from " << packet->systemAddress.ToString() << endl; peer->CloseConnection(packet->systemAddress, true); } } diff --git a/apps/master/MasterServer.hpp b/apps/master/MasterServer.hpp index c06a63263..5b2379e81 100644 --- a/apps/master/MasterServer.hpp +++ b/apps/master/MasterServer.hpp @@ -48,6 +48,7 @@ private: RakNet::SocketDescriptor sockdescr; ServerMap servers; bool run; + std::map pendingACKs; }; From bca594150c1f1655afd0d79c6cf21414e8051966 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 31 Jul 2017 19:07:51 +0800 Subject: [PATCH 040/136] [Browser] Add debug info to QueryClient --- apps/browser/netutils/QueryClient.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/browser/netutils/QueryClient.cpp b/apps/browser/netutils/QueryClient.cpp index c82957473..0d0b82030 100644 --- a/apps/browser/netutils/QueryClient.cpp +++ b/apps/browser/netutils/QueryClient.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace RakNet; using namespace std; @@ -56,6 +57,9 @@ map QueryClient::Query() pmq->SetServers(&query); status = GetAnswer(); + + qDebug() <<"Answer" << (status == ID_MASTER_QUERY ? "ok." : "wrong."); + return query; } @@ -83,7 +87,7 @@ MASTER_PACKETS QueryClient::GetAnswer() RakNet::Packet *packet; bool update = true; unsigned char pid = 0; - int id; + int id = -1; while (update) { for (packet = peer->Receive(); packet; peer->DeallocatePacket(packet), packet = peer->Receive()) @@ -94,8 +98,10 @@ MASTER_PACKETS QueryClient::GetAnswer() data.Read(pid); switch(pid) { - case ID_DISCONNECTION_NOTIFICATION: case ID_CONNECTION_LOST: + qDebug() << "ID_CONNECTION_LOST"; + case ID_DISCONNECTION_NOTIFICATION: + qDebug() << "Disconnected"; update = false; break; case ID_MASTER_QUERY: @@ -125,6 +131,7 @@ MASTER_PACKETS QueryClient::GetAnswer() ConnectionState QueryClient::Connect() { + ConnectionAttemptResult car = peer->Connect(masterAddr.ToString(false), masterAddr.GetPort(), TES3MP_MASTERSERVER_PASSW, strlen(TES3MP_MASTERSERVER_PASSW), 0, 0, 5, 500); @@ -134,17 +141,20 @@ ConnectionState QueryClient::Connect() switch (state) { case IS_CONNECTED: + qDebug() << "Connected"; return IS_CONNECTED; case IS_NOT_CONNECTED: case IS_DISCONNECTED: case IS_SILENTLY_DISCONNECTING: case IS_DISCONNECTING: { + qDebug() << "Cannot connect to the master server "<< state; //LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Cannot connect to master server: %d", masterAddr.ToString()); return IS_NOT_CONNECTED; } case IS_PENDING: case IS_CONNECTING: + qDebug() << "Pending"; break; } RakSleep(500); From 1f632d8bc98605234dd84834f4da52ea174db95c Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 31 Jul 2017 19:32:27 +0800 Subject: [PATCH 041/136] [Master] Fix REST servers/info --- apps/master/RestServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/master/RestServer.cpp b/apps/master/RestServer.cpp index 9ca7eac58..b266db48d 100644 --- a/apps/master/RestServer.cpp +++ b/apps/master/RestServer.cpp @@ -164,11 +164,11 @@ void RestServer::start() httpServer.resource["/api/servers/info"]["GET"] = [this](auto response, auto /*request*/) { stringstream ss; ss << '{'; - ss << "servers: " << serverMap->size(); + ss << "\"servers\": " << serverMap->size(); unsigned int players = 0; for (auto s : *serverMap) players += s.second.GetPlayers(); - ss << ", players: " << players; + ss << ", \"players\": " << players; ss << "}"; ResponseStr(*response, ss.str(), "application/json"); From 308ddabe90fba83bd902645957ffc4c3fabdf3e0 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 31 Jul 2017 12:39:33 +0000 Subject: [PATCH 042/136] Add feature additions policy --- CONTRIBUTING.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e87ddafa7..b5a7423d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,3 +53,18 @@ That said, we may sometimes evaluate such issues on an individual basis. Common * Issues so glaring that they would severely limit the capabilities of the engine in the future (for example, the scripting engine not being allowed to access objects in remote cells) * Bugs where the intent is very obvious, and that have little to no balancing impact (e.g. the bug were being tired made it easier to repair items, instead of harder) * Bugs that were fixed in an official patch for Morrowind + +Feature additions policy +===================== + +We get it, you have waited so long for feature XYZ to be available in Morrowind and now that OpenMW is here you can not wait to implement your ingenious idea and share it with the world. + +Unfortunately, since maintaining features comes at a cost and our resources are limited, we have to be a little selective in what features we allow into the main repository. Generally: + +- Features should be as generic and non-redundant as possible. +- Any feature that is also possible with modding should be done as a mod instead. +- In the future, OpenMW plans to expand the scope of what is possible with modding, e.g. by moving certain game logic into editable scripts. +- Currently, modders can edit OpenMW's GUI skins and layout XML files, although there are still a few missing hooks (e.g. scripting support) in order to make this into a powerful way of modding. +- If a feature introduces new game UI strings, that reduces its chance of being accepted because we do not currently have any way of localizing these to the user's Morrowind installation language. + +If you are in doubt of your feature being within our scope, it is probably best to start a forum discussion first. See the [settings documentation](https://openmw.readthedocs.io/en/stable/reference/modding/settings/index.html) and [Features list](https://wiki.openmw.org/index.php?title=Features) for some examples of features that were deemed acceptable. From c9d9461d3e84b60024d0800bd23413c41f82ee73 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 31 Jul 2017 16:13:50 +0200 Subject: [PATCH 043/136] Add Spacer class derived from AutoSizedWidget Using a normal widget as a spacer with HStretch/VStretch may not work properly because for widgets not derived from AutoSizedWidget, the HBox/VBox treat the widget's current size as the requested minimum size. This leads the layout to break when resized more than once. The new class sets HStretch and VStretch to true by default to save some typing. --- components/widgets/box.cpp | 6 ++++++ components/widgets/box.hpp | 9 +++++++++ components/widgets/widgets.cpp | 1 + files/mygui/openmw_container_window.layout | 4 +--- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ac2ff7fd..0ce8ce951 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -422,4 +422,10 @@ namespace Gui align(); } + Spacer::Spacer() + { + setUserString("HStretch", "true"); + setUserString("VStretch", "true"); + } + } diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index ccdc5784b..70f73ce42 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -81,6 +81,15 @@ namespace Gui bool mAutoResize; // auto resize the box so that it exactly fits all elements }; + class Spacer : public AutoSizedWidget, public MyGUI::Widget + { + MYGUI_RTTI_DERIVED( Spacer ) + public: + Spacer(); + + virtual MyGUI::IntSize getRequestedSize() { return MyGUI::IntSize(0,0); } + }; + class HBox : public Box, public MyGUI::Widget { MYGUI_RTTI_DERIVED( HBox ) diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 3b6361cf8..92f2084df 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -16,6 +16,7 @@ namespace Gui { MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 87651b0f2..6bb585e50 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -10,9 +10,7 @@ - - - + From a03cc8216e2ce46ac15477e2ffd41dcf33ca32c0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 31 Jul 2017 18:51:44 +0400 Subject: [PATCH 044/136] Fixed count widget buttons alignment --- files/mygui/openmw_count_window.layout | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index a3234c405..520d49fa3 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -16,13 +16,15 @@ - - + + + - + + From 10eb6ec75f9eec6df9c6fee9b40f4b99732b1dd4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 31 Jul 2017 19:28:02 +0400 Subject: [PATCH 045/136] AI: Check angle between actor and door --- apps/openmw/mwbase/world.hpp | 4 --- apps/openmw/mwmechanics/obstacle.cpp | 43 ++++++++++++++++++---------- apps/openmw/mwworld/worldimp.cpp | 10 ++----- apps/openmw/mwworld/worldimp.hpp | 3 -- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ce6cf38eb..86d26d3a7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -10,7 +10,6 @@ #include "../mwworld/ptr.hpp" #include "../mwrender/rendermode.hpp" -#include "../mwphysics/physicssystem.hpp" namespace osg { @@ -300,9 +299,6 @@ namespace MWBase virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; ///< cast a Ray and return true if there is an object in the ray path. - virtual MWPhysics::PhysicsSystem::RayResult castRayTest (float x1, float y1, float z1, float x2, float y2, float z2) = 0; - ///< cast a rendering ray and return ray result. - virtual bool toggleCollisionMode() = 0; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 8e932f351..3c6f14bfd 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,11 +1,9 @@ #include "obstacle.hpp" -#include - #include +#include #include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -36,24 +34,39 @@ namespace MWMechanics MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist) { - osg::Vec3f origin = MWBase::Environment::get().getWorld()->getActorHeadTransform(actor).getTrans(); + MWWorld::CellStore *cell = actor.getCell(); - osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) - * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); + // Check all the doors in this cell + const MWWorld::CellRefList& doors = cell->getReadOnlyDoors(); + const MWWorld::CellRefList::List& refList = doors.mList; + MWWorld::CellRefList::List::const_iterator it = refList.begin(); + osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); + pos.z() = 0; - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); - osg::Vec3f dest = origin + direction * minDist; + osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0)); - osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); - MWPhysics::PhysicsSystem::RayResult result = MWBase::Environment::get().getWorld()->castRayTest(pos.x(), pos.y(), pos.z(), dest.x(), dest.y(), dest.z()); + for (; it != refList.end(); ++it) + { + const MWWorld::LiveCellRef& ref = *it; - if (!result.mHit || result.mHitObject.isEmpty()) - return MWWorld::Ptr(); // none found + osg::Vec3f doorPos(ref.mData.getPosition().asVec3()); + doorPos.z() = 0; - if (result.mHitObject.getClass().getTypeName() == typeid(ESM::Door).name() && !result.mHitObject.getCellRef().getTeleport()) - return result.mHitObject; + float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length())); + + // Allow 60 degrees angle between actor and door + if (angle < -osg::PI / 3 || angle > osg::PI / 3) + continue; + + // Door is not close enough + if ((pos - doorPos).length2() > minDist*minDist) + continue; + + // FIXME cast + return MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); // found, stop searching + } - return MWWorld::Ptr(); + return MWWorld::Ptr(); // none found } ObstacleCheck::ObstacleCheck(): diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 86943a7e7..91a3c4a8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1451,16 +1451,12 @@ namespace MWWorld } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) - { - MWPhysics::PhysicsSystem::RayResult result = castRayTest(x1, y1, z1, x2, y2, z2); - return result.mHit; - } - - MWPhysics::PhysicsSystem::RayResult World::castRayTest (float x1, float y1, float z1, float x2, float y2, float z2) { osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - return mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); + + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door); + return result.mHit; } void World::processDoors(float duration) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 951a837da..ce6e27672 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -407,9 +407,6 @@ namespace MWWorld virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); ///< cast a Ray and return true if there is an object in the ray path. - virtual MWPhysics::PhysicsSystem::RayResult castRayTest (float x1, float y1, float z1, float x2, float y2, float z2); - ///< cast a rendering ray and return ray result. - virtual bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. From d7cbfc98eb766b5f6395a7dd5d1398e70d9cfd43 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 1 Aug 2017 02:16:49 +0800 Subject: [PATCH 046/136] [Browser] Fix crashing of browser (I hope) --- apps/browser/QueryHelper.cpp | 6 +- apps/browser/netutils/QueryClient.cpp | 89 ++++++++++++++++++++------- apps/browser/netutils/QueryClient.hpp | 4 +- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/apps/browser/QueryHelper.cpp b/apps/browser/QueryHelper.cpp index 325e9df74..1307bd03b 100644 --- a/apps/browser/QueryHelper.cpp +++ b/apps/browser/QueryHelper.cpp @@ -27,9 +27,11 @@ QueryHelper::QueryHelper(QAbstractItemModel *model) void QueryHelper::refresh() { if (!queryThread->isRunning()) + { _model->removeRows(0, _model->rowCount()); - queryThread->start(); - emit started(); + queryThread->start(); + emit started(); + } } void QueryHelper::terminate() diff --git a/apps/browser/netutils/QueryClient.cpp b/apps/browser/netutils/QueryClient.cpp index 0d0b82030..73d68ccf9 100644 --- a/apps/browser/netutils/QueryClient.cpp +++ b/apps/browser/netutils/QueryClient.cpp @@ -43,21 +43,41 @@ QueryClient &QueryClient::Get() map QueryClient::Query() { - status = -1; map query; - if (Connect() == IS_NOT_CONNECTED) - return query; - BitStream bs; bs.Write((unsigned char) (ID_MASTER_QUERY)); - int code = peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false); + qDebug() << "Locking mutex in QueryClient::Query()"; + mxServers.lock(); + status = -1; + int attempts = 3; + do + { + if (Connect() == IS_NOT_CONNECTED) + { + qDebug() << "Unlocking mutex in QueryClient::Query()"; + mxServers.unlock(); + return query; + } - if (code == 0) - return query; + int code = peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false); - pmq->SetServers(&query); - status = GetAnswer(); + if (code == 0) + { + qDebug() << "Unlocking mutex in QueryClient::Query()"; + mxServers.unlock(); + return query; + } + pmq->SetServers(&query); + status = GetAnswer(ID_MASTER_QUERY); + RakSleep(100); + } + while(status != ID_MASTER_QUERY && attempts-- > 0); + if(status != ID_MASTER_QUERY) + qDebug() << "Getting query was failed"; + qDebug() << "Unlocking mutex in QueryClient::Query()"; + peer->CloseConnection(masterAddr, true); + mxServers.unlock(); qDebug() <<"Answer" << (status == ID_MASTER_QUERY ? "ok." : "wrong."); return query; @@ -65,24 +85,40 @@ map QueryClient::Query() pair QueryClient::Update(RakNet::SystemAddress addr) { + qDebug() << "Locking mutex in QueryClient::Update(RakNet::SystemAddress addr)"; pair server; - if (Connect() == IS_NOT_CONNECTED) - { - status = -1; - return server; - } - BitStream bs; bs.Write((unsigned char) (ID_MASTER_UPDATE)); bs.Write(addr); - peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false); + mxServers.lock(); + status = -1; + int attempts = 3; pmu->SetServer(&server); - status = GetAnswer(); + do + { + if (Connect() == IS_NOT_CONNECTED) + { + qDebug() << IS_NOT_CONNECTED; + qDebug() << "Unlocking mutex in QueryClient::Update(RakNet::SystemAddress addr)"; + mxServers.unlock(); + return server; + } + + peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, CHANNEL_MASTER, masterAddr, false); + status = GetAnswer(ID_MASTER_UPDATE); + RakSleep(100); + } + while(status != ID_MASTER_UPDATE && attempts-- > 0); + if(status != ID_MASTER_UPDATE) + qDebug() << "Getting update was failed"; + peer->CloseConnection(masterAddr, true); + qDebug() << "Unlocking mutex in QueryClient::Update(RakNet::SystemAddress addr)"; + mxServers.unlock(); return server; } -MASTER_PACKETS QueryClient::GetAnswer() +MASTER_PACKETS QueryClient::GetAnswer(MASTER_PACKETS waitingPacket) { RakNet::Packet *packet; bool update = true; @@ -105,20 +141,30 @@ MASTER_PACKETS QueryClient::GetAnswer() update = false; break; case ID_MASTER_QUERY: - pmq->Read(); + qDebug() << "ID_MASTER_QUERY"; + if (waitingPacket == ID_MASTER_QUERY) + pmq->Read(); + else + qDebug() << "Got wrong packet"; update = false; id = pid; break; case ID_MASTER_UPDATE: - pmu->Read(); + qDebug() << "ID_MASTER_UPDATE"; + if (waitingPacket == ID_MASTER_UPDATE) + pmu->Read(); + else + qDebug() << "Got wrong packet"; update = false; id = pid; break; case ID_MASTER_ANNOUNCE: + qDebug() << "ID_MASTER_ANNOUNCE"; update = false; id = pid; break; case ID_CONNECTION_REQUEST_ACCEPTED: + qDebug() << "ID_CONNECTION_REQUEST_ACCEPTED"; break; default: break; @@ -148,8 +194,7 @@ ConnectionState QueryClient::Connect() case IS_SILENTLY_DISCONNECTING: case IS_DISCONNECTING: { - qDebug() << "Cannot connect to the master server "<< state; - //LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Cannot connect to master server: %d", masterAddr.ToString()); + qDebug() << "Cannot connect to the master server. Code:"<< state; return IS_NOT_CONNECTED; } case IS_PENDING: diff --git a/apps/browser/netutils/QueryClient.hpp b/apps/browser/netutils/QueryClient.hpp index 4acd6f553..807cc8704 100644 --- a/apps/browser/netutils/QueryClient.hpp +++ b/apps/browser/netutils/QueryClient.hpp @@ -10,6 +10,7 @@ #include #include #include +#include class QueryClient { @@ -26,7 +27,7 @@ public: int Status(); private: RakNet::ConnectionState Connect(); - MASTER_PACKETS GetAnswer(); + MASTER_PACKETS GetAnswer(MASTER_PACKETS packet); protected: QueryClient(); ~QueryClient(); @@ -37,6 +38,7 @@ private: mwmp::PacketMasterQuery *pmq; mwmp::PacketMasterUpdate *pmu; std::pair server; + std::mutex mxServers; }; From b7cfb1aaf42312bfcd51375c0d29604b21e34bf0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 31 Jul 2017 23:05:19 +0400 Subject: [PATCH 047/136] Fixed DamageHealth and AbsorbHealth effects applying --- apps/openmw/mwmechanics/spellcasting.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 7fde66ebe..a6ae5ca65 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1131,6 +1131,9 @@ namespace MWMechanics receivedMagicDamage = true; adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); } + + break; + case ESM::MagicEffect::DamageMagicka: case ESM::MagicEffect::DamageFatigue: if (!godmode) @@ -1147,6 +1150,9 @@ namespace MWMechanics receivedMagicDamage = true; adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); } + + break; + case ESM::MagicEffect::AbsorbMagicka: case ESM::MagicEffect::AbsorbFatigue: if (!godmode) From d24286273b68c0d1d3cd3d79bbfbc0e17dceff67 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 28 Jun 2017 22:40:13 +0200 Subject: [PATCH 048/136] Prevent respawned references from being added to the scene twice in certain cases (Fixes #3864) --- apps/openmw/mwrender/objects.cpp | 16 +++++++++------- apps/openmw/mwworld/scene.cpp | 6 ++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d4cbf25fe..f0a3d2e38 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -38,6 +38,8 @@ Objects::~Objects() void Objects::insertBegin(const MWWorld::Ptr& ptr) { + assert(mObjects.find(ptr) == mObjects.end()); + osg::ref_ptr cellnode; CellMap::iterator found = mCellSceneNodes.find(ptr.getCell()); @@ -90,9 +92,8 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim = new CreatureAnimation(ptr, mesh, mResourceSystem); - ptr.getClass().getContainerStore(ptr).setContListener(static_cast(anim.get())); - - mObjects.insert(std::make_pair(ptr, anim)); + if (mObjects.insert(std::make_pair(ptr, anim)).second) + ptr.getClass().getContainerStore(ptr).setContListener(static_cast(anim.get())); } void Objects::insertNPC(const MWWorld::Ptr &ptr) @@ -102,10 +103,11 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) osg::ref_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem)); - ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr); - ptr.getClass().getInventoryStore(ptr).setContListener(anim.get()); - - mObjects.insert(std::make_pair(ptr, anim)); + if (mObjects.insert(std::make_pair(ptr, anim)).second) + { + ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr); + ptr.getClass().getInventoryStore(ptr).setContListener(anim.get()); + } } bool Objects::removeObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8da01cc4b..c83165239 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -54,6 +54,12 @@ namespace void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { + if (ptr.getRefData().getBaseNode() || physics.getActor(ptr)) + { + std::cerr << "Warning: Tried to add " << ptr.getCellRef().getRefId() << " to the scene twice" << std::endl; + return; + } + bool useAnim = ptr.getClass().useAnim(); std::string model = ptr.getClass().getModel(ptr); if (useAnim) From 604f9ee32396387677b021d0a8981fa8c09c0057 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 1 Aug 2017 09:05:35 +0400 Subject: [PATCH 049/136] Split weapons and spells rating code from combat actions --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aicombataction.cpp | 683 +-------------------- apps/openmw/mwmechanics/aicombataction.hpp | 15 - apps/openmw/mwmechanics/spellpriority.cpp | 545 ++++++++++++++++ apps/openmw/mwmechanics/spellpriority.hpp | 32 + apps/openmw/mwmechanics/weaponpriority.cpp | 146 +++++ apps/openmw/mwmechanics/weaponpriority.hpp | 14 + 7 files changed, 749 insertions(+), 688 deletions(-) create mode 100644 apps/openmw/mwmechanics/spellpriority.cpp create mode 100644 apps/openmw/mwmechanics/spellpriority.hpp create mode 100644 apps/openmw/mwmechanics/weaponpriority.cpp create mode 100644 apps/openmw/mwmechanics/weaponpriority.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1aa311fd2..89b94ce12 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -84,7 +84,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects aistate coordinateconverter trading aiface + character actors objects aistate coordinateconverter trading aiface weaponpriority spellpriority ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 3e61b7463..1bfeff074 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -16,624 +16,25 @@ #include "npcstats.hpp" #include "spellcasting.hpp" #include "combat.hpp" - -namespace -{ - -// RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects. -enum RangeTypes -{ - Self = 0x1, - Touch = 0x10, - Target = 0x100 -}; - -int getRangeTypes (const ESM::EffectList& effects) -{ - int types = 0; - for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) - { - if (it->mRange == ESM::RT_Self) - types |= Self; - else if (it->mRange == ESM::RT_Touch) - types |= Touch; - else if (it->mRange == ESM::RT_Target) - types |= Target; - } - return types; -} - -float suggestCombatRange(int rangeTypes) -{ - static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); - static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); - - // This distance is a possible distance of melee attack - static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); - - if (rangeTypes & Touch) - { - return fCombatDistance; - } - - return distance * 4; -} - -int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true) -{ - int toCure=0; - const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); - for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) - { - const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; - for (std::vector::const_iterator effectIt = params.mEffects.begin(); - effectIt != params.mEffects.end(); ++effectIt) - { - int effectId = effectIt->mEffectId; - if (effectFilter != -1 && effectId != effectFilter) - continue; - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); - - if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway - continue; - - if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - ++toCure; - - if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) - ++toCure; - } - } - return toCure; -} - -} +#include "weaponpriority.hpp" +#include "spellpriority.hpp" namespace MWMechanics { - - float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor) - { - if (item.getTypeName() != typeid(ESM::Potion).name()) - return 0.f; - - const ESM::Potion* potion = item.get()->mBase; - return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); - } - - float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, - float arrowRating, float boltRating) - { - if (item.getTypeName() != typeid(ESM::Weapon).name()) - return 0.f; - - const ESM::Weapon* weapon = item.get()->mBase; - - if (type != -1 && weapon->mData.mType != type) - return 0.f; - - float rating=0.f; - float bonus=0.f; - - if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) - { - // Range weapon is useless under water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) - return 0.f; - - if (enemy.isEmpty()) - return 0.f; - - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) - return 0.f; - - bonus+=1.5f; - } - - if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) - { - rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; - - if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown) - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); - } - else - { - for (int i=0; i<2; ++i) - { - rating += weapon->mData.mSlash[i]; - rating += weapon->mData.mThrust[i]; - rating += weapon->mData.mChop[i]; - } - rating /= 6.f; - - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); - } - - if (item.getClass().hasItemHealth(item)) - { - if (item.getClass().getItemHealth(item) == 0) - return 0.f; - rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item)); - } - - if (weapon->mData.mType == ESM::Weapon::MarksmanBow) - { - if (arrowRating <= 0.f) - rating = 0.f; - else - rating += arrowRating; - } - else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - if (boltRating <= 0.f) - rating = 0.f; - else - rating += boltRating; - } - - if (!weapon->mEnchant.empty()) - { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes - && (item.getCellRef().getEnchantmentCharge() == -1 - || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) - rating += rateEffects(enchantment->mEffects, actor, enemy); - } - - int skill = item.getClass().getEquipmentSkill(item); - if (skill != -1) - rating *= actor.getClass().getSkill(actor, skill) / 100.f; - - // There is no need to apply bonus if weapon rating == 0 - if (rating == 0.f) - return 0.f; - - return rating + bonus; - } - - float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) - { - const CreatureStats& stats = actor.getClass().getCreatureStats(actor); - - float successChance = MWMechanics::getSpellSuccessChance(spell, actor); - if (successChance == 0.f) - return 0.f; - - if (spell->mData.mType != ESM::Spell::ST_Spell) - return 0.f; - - // Don't make use of racial bonus spells, like MW. Can be made optional later - if (actor.getClass().isNpc()) - { - std::string raceid = actor.get()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); - if (race->mPowers.exists(spell->mId)) - return 0.f; - } - - if (spell->mData.mCost > stats.getMagicka().getCurrent()) - return 0.f; - - // Spells don't stack, so early out if the spell is still active on the target - int types = getRangeTypes(spell->mEffects); - if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId)) - return 0.f; - if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId)) - return 0.f; - - return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f); - } - - float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) - { - if (ptr.getClass().getEnchantment(ptr).empty()) - return 0.f; - - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); - - if (enchantment->mData.mType == ESM::Enchantment::CastOnce) - { - return rateEffects(enchantment->mEffects, actor, enemy); - } - else - { - //if (!ptr.getClass().canBeEquipped(ptr, actor)) - return 0.f; - } - } - - float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) + float suggestCombatRange(int rangeTypes) { - // NOTE: enemy may be empty - - float rating = 1; - switch (effect.mEffectID) - { - case ESM::MagicEffect::Soultrap: - case ESM::MagicEffect::AlmsiviIntervention: - case ESM::MagicEffect::DivineIntervention: - case ESM::MagicEffect::CalmHumanoid: - case ESM::MagicEffect::CalmCreature: - case ESM::MagicEffect::FrenzyHumanoid: - case ESM::MagicEffect::FrenzyCreature: - case ESM::MagicEffect::DemoralizeHumanoid: - case ESM::MagicEffect::DemoralizeCreature: - case ESM::MagicEffect::RallyHumanoid: - case ESM::MagicEffect::RallyCreature: - case ESM::MagicEffect::Charm: - case ESM::MagicEffect::DetectAnimal: - case ESM::MagicEffect::DetectEnchantment: - case ESM::MagicEffect::DetectKey: - case ESM::MagicEffect::Telekinesis: - case ESM::MagicEffect::Mark: - case ESM::MagicEffect::Recall: - case ESM::MagicEffect::Jump: - case ESM::MagicEffect::WaterBreathing: - case ESM::MagicEffect::SwiftSwim: - case ESM::MagicEffect::WaterWalking: - case ESM::MagicEffect::SlowFall: - case ESM::MagicEffect::Light: - case ESM::MagicEffect::Lock: - case ESM::MagicEffect::Open: - case ESM::MagicEffect::TurnUndead: - case ESM::MagicEffect::WeaknessToCommonDisease: - case ESM::MagicEffect::WeaknessToBlightDisease: - case ESM::MagicEffect::WeaknessToCorprusDisease: - case ESM::MagicEffect::CureCommonDisease: - case ESM::MagicEffect::CureBlightDisease: - case ESM::MagicEffect::CureCorprusDisease: - case ESM::MagicEffect::ResistBlightDisease: - case ESM::MagicEffect::ResistCommonDisease: - case ESM::MagicEffect::ResistCorprusDisease: - case ESM::MagicEffect::Invisibility: - case ESM::MagicEffect::Chameleon: - case ESM::MagicEffect::NightEye: - case ESM::MagicEffect::Vampirism: - case ESM::MagicEffect::StuntedMagicka: - case ESM::MagicEffect::ExtraSpell: - case ESM::MagicEffect::RemoveCurse: - case ESM::MagicEffect::CommandCreature: - case ESM::MagicEffect::CommandHumanoid: - return 0.f; - - case ESM::MagicEffect::Sound: - { - if (enemy.isEmpty()) - return 0.f; - - // there is no need to cast sound if enemy is not able to cast spells - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) - return 0.f; - - if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) - return 0.f; - - break; - } - - case ESM::MagicEffect::RestoreAttribute: - return 0.f; // TODO: implement based on attribute damage - case ESM::MagicEffect::RestoreSkill: - return 0.f; // TODO: implement based on skill damage - - case ESM::MagicEffect::ResistFire: - case ESM::MagicEffect::ResistFrost: - case ESM::MagicEffect::ResistMagicka: - case ESM::MagicEffect::ResistNormalWeapons: - case ESM::MagicEffect::ResistParalysis: - case ESM::MagicEffect::ResistPoison: - case ESM::MagicEffect::ResistShock: - case ESM::MagicEffect::SpellAbsorption: - case ESM::MagicEffect::Reflect: - return 0.f; // probably useless since we don't know in advance what the enemy will cast - - // don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions - case ESM::MagicEffect::FortifyAttribute: - case ESM::MagicEffect::FortifyHealth: - case ESM::MagicEffect::FortifyMagicka: - case ESM::MagicEffect::FortifyFatigue: - case ESM::MagicEffect::FortifySkill: - case ESM::MagicEffect::FortifyMaximumMagicka: - case ESM::MagicEffect::FortifyAttack: - return 0.f; - - case ESM::MagicEffect::Burden: - { - if (enemy.isEmpty()) - return 0.f; - - // Ignore enemy without inventory - if (!enemy.getClass().hasInventoryStore(enemy)) - return 0.f; - - // burden makes sense only to overburden an enemy - float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy); - if (burden > 0) - return 0.f; - - if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden) - rating *= 3; - else - return 0.f; - - break; - } - - case ESM::MagicEffect::Feather: - { - // Ignore actors without inventory - if (!actor.getClass().hasInventoryStore(actor)) - return 0.f; - - // feather makes sense only for overburden actors - float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor); - if (burden <= 0) - return 0.f; - - if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden) - rating *= 3; - else - return 0.f; - - break; - } - - case ESM::MagicEffect::Levitate: - return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway - case ESM::MagicEffect::BoundBoots: - case ESM::MagicEffect::BoundHelm: - if (actor.getClass().isNpc()) - { - // Beast races can't wear helmets or boots - std::string raceid = actor.get()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); - if (race->mData.mFlags & ESM::Race::Beast) - return 0.f; - } - // Intended fall-through - // Creatures can not wear armor - case ESM::MagicEffect::BoundCuirass: - case ESM::MagicEffect::BoundGloves: - if (!actor.getClass().isNpc()) - return 0.f; - break; - - case ESM::MagicEffect::RestoreHealth: - case ESM::MagicEffect::RestoreMagicka: - case ESM::MagicEffect::RestoreFatigue: - if (effect.mRange == ESM::RT_Self) - { - int priority = 1; - if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) - priority = 10; - const DynamicStat& current = actor.getClass().getCreatureStats(actor). - getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); - float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; - // Effect doesn't heal more than we need, *or* we are below 1/2 health - if (current.getModified() - current.getCurrent() > toHeal - || current.getCurrent() < current.getModified()*0.5) - { - return 10000.f * priority - - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion - } - else - return -10000.f * priority; // Save for later - } - break; - - case ESM::MagicEffect::Dispel: - { - int numPositive = 0; - int numNegative = 0; - int diff = 0; - - if (effect.mRange == ESM::RT_Self) - { - numPositive = numEffectsToDispel(actor, -1, false); - numNegative = numEffectsToDispel(actor); - - diff = numNegative - numPositive; - } - else - { - if (enemy.isEmpty()) - return 0.f; - - numPositive = numEffectsToDispel(enemy, -1, false); - numNegative = numEffectsToDispel(enemy); - - diff = numPositive - numNegative; - - // if rating < 0 here, the spell will be considered as negative later - rating *= -1; - } - - if (diff <= 0) - return 0.f; - - rating *= (diff) / 5.f; - - break; - } - - // Prefer Cure effects over Dispel, because Dispel also removes positive effects - case ESM::MagicEffect::CureParalyzation: - return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze); - - case ESM::MagicEffect::CurePoison: - return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison); - case ESM::MagicEffect::DisintegrateArmor: - { - if (enemy.isEmpty()) - return 0.f; - - // Ignore enemy without inventory - if (!enemy.getClass().hasInventoryStore(enemy)) - return 0.f; - - MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy); - - // According to UESP - static const int armorSlots[] = { - MWWorld::InventoryStore::Slot_CarriedLeft, - MWWorld::InventoryStore::Slot_Cuirass, - MWWorld::InventoryStore::Slot_LeftPauldron, - MWWorld::InventoryStore::Slot_RightPauldron, - MWWorld::InventoryStore::Slot_LeftGauntlet, - MWWorld::InventoryStore::Slot_RightGauntlet, - MWWorld::InventoryStore::Slot_Helmet, - MWWorld::InventoryStore::Slot_Greaves, - MWWorld::InventoryStore::Slot_Boots - }; - - bool enemyHasArmor = false; - - // Ignore enemy without armor - for (unsigned int i=0; i= 0 && effect.mAttribute < ESM::Attribute::Length) - { - const float attributePriorities[ESM::Attribute::Length] = { - 1.0f, // Strength - 0.5f, // Intelligence - 0.6f, // Willpower - 0.7f, // Agility - 0.5f, // Speed - 0.8f, // Endurance - 0.7f, // Personality - 0.3f // Luck - }; - rating *= attributePriorities[effect.mAttribute]; - } - } - break; - - case ESM::MagicEffect::DamageSkill: - case ESM::MagicEffect::DrainSkill: - if (enemy.isEmpty() || !enemy.getClass().isNpc()) - return 0.f; - if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) - return 0.f; - break; - - default: - break; - } - - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - - // Underwater casting not possible - if (effect.mRange == ESM::RT_Target) - { - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) - return 0.f; - - if (enemy.isEmpty()) - return 0.f; - - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) - return 0.f; - } - - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - { - rating *= -1.f; - - if (enemy.isEmpty()) - return 0.f; - - // Check resistance for harmful effects - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects()); + static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); + static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); - rating *= (1.f - std::min(resistance, 100.f) / 100.f); - } + // This distance is a possible distance of melee attack + static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); - // for harmful no-magnitude effects (e.g. silence) check if enemy is already has them - // for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them - if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + if (rangeTypes & RangeTypes::Touch) { - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - { - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) - return 0.f; - } - else - { - CreatureStats& stats = actor.getClass().getCreatureStats(actor); - - if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) - return 0.f; - } + return fCombatDistance; } - rating *= calcEffectCost(effect); - - // Currently treating all "on target" or "on touch" effects to target the enemy actor. - // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. - if (effect.mRange != ESM::RT_Self) - rating *= -1.f; - - return rating; - } - - float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - // NOTE: enemy may be empty - float rating = 0.f; - for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) - { - rating += rateEffect(*it, actor, enemy); - - if (it->mRange == ESM::RT_Target) - rating *= 1.5f; - } - return rating; + return distance * 4; } void ActionSpell::prepare(const MWWorld::Ptr &actor) @@ -655,7 +56,7 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(mSpellId); int types = getRangeTypes(spell->mEffects); - isRanged = (types & Target) | (types & Self); + isRanged = (types & RangeTypes::Target) | (types & RangeTypes::Self); return suggestCombatRange(types); } @@ -1106,67 +507,6 @@ namespace MWMechanics return true; } - float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - - static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); - static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); - - float mult = fAIMagicSpellMult; - - for (std::vector::const_iterator effectIt = - spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) - { - if (effectIt->mRange == ESM::RT_Target) - { - if (!MWBase::Environment::get().getWorld()->isSwimming(enemy)) - mult = fAIRangeMagicSpellMult; - else - mult = 0.0f; - break; - } - } - - return MWMechanics::getSpellSuccessChance(spell, actor) * mult; - } - - float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - - static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); - static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); - static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); - - if (weapon.isEmpty()) - return 0.f; - - float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; - float chopMult = fAIMeleeWeaponMult; - float bonusDamage = 0.f; - - const ESM::Weapon* esmWeap = weapon.get()->mBase; - - if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) - { - if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) - { - bonusDamage = ammo.get()->mBase->mData.mChop[1]; - chopMult = fAIRangeMeleeWeaponMult; - } - else - chopMult = 0.f; - } - - float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult; - float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult; - float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult; - - return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult - + std::max(std::max(chopRating, slashRating), thrustRating); - } - float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) { const CreatureStats& stats = actor.getClass().getCreatureStats(actor); @@ -1212,5 +552,4 @@ namespace MWMechanics return false; } - } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 393bd9f5d..dc6f359d6 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -10,7 +10,6 @@ namespace MWMechanics { - class Action { public: @@ -88,18 +87,6 @@ namespace MWMechanics virtual const ESM::Weapon* getWeapon() const; }; - float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor); - /// @param type Skip all weapons that are not of this type (i.e. return rating 0) - float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, - int type=-1, float arrowRating=0.f, float boltRating=0.f); - - /// @note target may be empty - float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - /// @note target may be empty - float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - std::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy); @@ -107,8 +94,6 @@ namespace MWMechanics float getMaxAttackDistance(const MWWorld::Ptr& actor); bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating); } diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp new file mode 100644 index 000000000..a73e4fd89 --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -0,0 +1,545 @@ +#include "spellpriority.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/actionequip.hpp" +#include "../mwworld/cellstore.hpp" + +#include "npcstats.hpp" +#include "spellcasting.hpp" +#include "combat.hpp" + +namespace +{ + int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true) + { + int toCure=0; + const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); + for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) + { + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; + for (std::vector::const_iterator effectIt = params.mEffects.begin(); + effectIt != params.mEffects.end(); ++effectIt) + { + int effectId = effectIt->mEffectId; + if (effectFilter != -1 && effectId != effectFilter) + continue; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); + + if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway + continue; + + if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + ++toCure; + + if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) + ++toCure; + } + } + return toCure; + } +} + +namespace MWMechanics +{ + int getRangeTypes (const ESM::EffectList& effects) + { + int types = 0; + for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) + { + if (it->mRange == ESM::RT_Self) + types |= RangeTypes::Self; + else if (it->mRange == ESM::RT_Touch) + types |= RangeTypes::Touch; + else if (it->mRange == ESM::RT_Target) + types |= RangeTypes::Target; + } + return types; + } + + float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor) + { + if (item.getTypeName() != typeid(ESM::Potion).name()) + return 0.f; + + const ESM::Potion* potion = item.get()->mBase; + return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); + } + + float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) + { + const CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + float successChance = MWMechanics::getSpellSuccessChance(spell, actor); + if (successChance == 0.f) + return 0.f; + + if (spell->mData.mType != ESM::Spell::ST_Spell) + return 0.f; + + // Don't make use of racial bonus spells, like MW. Can be made optional later + if (actor.getClass().isNpc()) + { + std::string raceid = actor.get()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); + if (race->mPowers.exists(spell->mId)) + return 0.f; + } + + if (spell->mData.mCost > stats.getMagicka().getCurrent()) + return 0.f; + + // Spells don't stack, so early out if the spell is still active on the target + int types = getRangeTypes(spell->mEffects); + if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId)) + return 0.f; + if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId)) + return 0.f; + + return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f); + } + + float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) + { + if (ptr.getClass().getEnchantment(ptr).empty()) + return 0.f; + + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); + + if (enchantment->mData.mType == ESM::Enchantment::CastOnce) + { + return rateEffects(enchantment->mEffects, actor, enemy); + } + else + { + //if (!ptr.getClass().canBeEquipped(ptr, actor)) + return 0.f; + } + } + + float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) + { + // NOTE: enemy may be empty + + float rating = 1; + switch (effect.mEffectID) + { + case ESM::MagicEffect::Soultrap: + case ESM::MagicEffect::AlmsiviIntervention: + case ESM::MagicEffect::DivineIntervention: + case ESM::MagicEffect::CalmHumanoid: + case ESM::MagicEffect::CalmCreature: + case ESM::MagicEffect::FrenzyHumanoid: + case ESM::MagicEffect::FrenzyCreature: + case ESM::MagicEffect::DemoralizeHumanoid: + case ESM::MagicEffect::DemoralizeCreature: + case ESM::MagicEffect::RallyHumanoid: + case ESM::MagicEffect::RallyCreature: + case ESM::MagicEffect::Charm: + case ESM::MagicEffect::DetectAnimal: + case ESM::MagicEffect::DetectEnchantment: + case ESM::MagicEffect::DetectKey: + case ESM::MagicEffect::Telekinesis: + case ESM::MagicEffect::Mark: + case ESM::MagicEffect::Recall: + case ESM::MagicEffect::Jump: + case ESM::MagicEffect::WaterBreathing: + case ESM::MagicEffect::SwiftSwim: + case ESM::MagicEffect::WaterWalking: + case ESM::MagicEffect::SlowFall: + case ESM::MagicEffect::Light: + case ESM::MagicEffect::Lock: + case ESM::MagicEffect::Open: + case ESM::MagicEffect::TurnUndead: + case ESM::MagicEffect::WeaknessToCommonDisease: + case ESM::MagicEffect::WeaknessToBlightDisease: + case ESM::MagicEffect::WeaknessToCorprusDisease: + case ESM::MagicEffect::CureCommonDisease: + case ESM::MagicEffect::CureBlightDisease: + case ESM::MagicEffect::CureCorprusDisease: + case ESM::MagicEffect::ResistBlightDisease: + case ESM::MagicEffect::ResistCommonDisease: + case ESM::MagicEffect::ResistCorprusDisease: + case ESM::MagicEffect::Invisibility: + case ESM::MagicEffect::Chameleon: + case ESM::MagicEffect::NightEye: + case ESM::MagicEffect::Vampirism: + case ESM::MagicEffect::StuntedMagicka: + case ESM::MagicEffect::ExtraSpell: + case ESM::MagicEffect::RemoveCurse: + case ESM::MagicEffect::CommandCreature: + case ESM::MagicEffect::CommandHumanoid: + return 0.f; + + case ESM::MagicEffect::Sound: + { + if (enemy.isEmpty()) + return 0.f; + + // there is no need to cast sound if enemy is not able to cast spells + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) + return 0.f; + + if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + return 0.f; + + break; + } + + case ESM::MagicEffect::RestoreAttribute: + return 0.f; // TODO: implement based on attribute damage + case ESM::MagicEffect::RestoreSkill: + return 0.f; // TODO: implement based on skill damage + + case ESM::MagicEffect::ResistFire: + case ESM::MagicEffect::ResistFrost: + case ESM::MagicEffect::ResistMagicka: + case ESM::MagicEffect::ResistNormalWeapons: + case ESM::MagicEffect::ResistParalysis: + case ESM::MagicEffect::ResistPoison: + case ESM::MagicEffect::ResistShock: + case ESM::MagicEffect::SpellAbsorption: + case ESM::MagicEffect::Reflect: + return 0.f; // probably useless since we don't know in advance what the enemy will cast + + // don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::FortifyHealth: + case ESM::MagicEffect::FortifyMagicka: + case ESM::MagicEffect::FortifyFatigue: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::FortifyMaximumMagicka: + case ESM::MagicEffect::FortifyAttack: + return 0.f; + + case ESM::MagicEffect::Burden: + { + if (enemy.isEmpty()) + return 0.f; + + // Ignore enemy without inventory + if (!enemy.getClass().hasInventoryStore(enemy)) + return 0.f; + + // burden makes sense only to overburden an enemy + float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy); + if (burden > 0) + return 0.f; + + if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden) + rating *= 3; + else + return 0.f; + + break; + } + + case ESM::MagicEffect::Feather: + { + // Ignore actors without inventory + if (!actor.getClass().hasInventoryStore(actor)) + return 0.f; + + // feather makes sense only for overburden actors + float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor); + if (burden <= 0) + return 0.f; + + if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden) + rating *= 3; + else + return 0.f; + + break; + } + + case ESM::MagicEffect::Levitate: + return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway + case ESM::MagicEffect::BoundBoots: + case ESM::MagicEffect::BoundHelm: + if (actor.getClass().isNpc()) + { + // Beast races can't wear helmets or boots + std::string raceid = actor.get()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); + if (race->mData.mFlags & ESM::Race::Beast) + return 0.f; + } + // Intended fall-through + // Creatures can not wear armor + case ESM::MagicEffect::BoundCuirass: + case ESM::MagicEffect::BoundGloves: + if (!actor.getClass().isNpc()) + return 0.f; + break; + + case ESM::MagicEffect::RestoreHealth: + case ESM::MagicEffect::RestoreMagicka: + case ESM::MagicEffect::RestoreFatigue: + if (effect.mRange == ESM::RT_Self) + { + int priority = 1; + if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) + priority = 10; + const DynamicStat& current = actor.getClass().getCreatureStats(actor). + getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); + float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; + // Effect doesn't heal more than we need, *or* we are below 1/2 health + if (current.getModified() - current.getCurrent() > toHeal + || current.getCurrent() < current.getModified()*0.5) + { + return 10000.f * priority + - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion + } + else + return -10000.f * priority; // Save for later + } + break; + + case ESM::MagicEffect::Dispel: + { + int numPositive = 0; + int numNegative = 0; + int diff = 0; + + if (effect.mRange == ESM::RT_Self) + { + numPositive = numEffectsToDispel(actor, -1, false); + numNegative = numEffectsToDispel(actor); + + diff = numNegative - numPositive; + } + else + { + if (enemy.isEmpty()) + return 0.f; + + numPositive = numEffectsToDispel(enemy, -1, false); + numNegative = numEffectsToDispel(enemy); + + diff = numPositive - numNegative; + + // if rating < 0 here, the spell will be considered as negative later + rating *= -1; + } + + if (diff <= 0) + return 0.f; + + rating *= (diff) / 5.f; + + break; + } + + // Prefer Cure effects over Dispel, because Dispel also removes positive effects + case ESM::MagicEffect::CureParalyzation: + return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze); + + case ESM::MagicEffect::CurePoison: + return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison); + case ESM::MagicEffect::DisintegrateArmor: + { + if (enemy.isEmpty()) + return 0.f; + + // Ignore enemy without inventory + if (!enemy.getClass().hasInventoryStore(enemy)) + return 0.f; + + MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy); + + // According to UESP + static const int armorSlots[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + bool enemyHasArmor = false; + + // Ignore enemy without armor + for (unsigned int i=0; i= 0 && effect.mAttribute < ESM::Attribute::Length) + { + const float attributePriorities[ESM::Attribute::Length] = { + 1.0f, // Strength + 0.5f, // Intelligence + 0.6f, // Willpower + 0.7f, // Agility + 0.5f, // Speed + 0.8f, // Endurance + 0.7f, // Personality + 0.3f // Luck + }; + rating *= attributePriorities[effect.mAttribute]; + } + } + break; + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::DrainSkill: + if (enemy.isEmpty() || !enemy.getClass().isNpc()) + return 0.f; + if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) + return 0.f; + break; + + default: + break; + } + + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + + // Underwater casting not possible + if (effect.mRange == ESM::RT_Target) + { + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) + return 0.f; + + if (enemy.isEmpty()) + return 0.f; + + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) + return 0.f; + } + + if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + { + rating *= -1.f; + + if (enemy.isEmpty()) + return 0.f; + + // Check resistance for harmful effects + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects()); + + rating *= (1.f - std::min(resistance, 100.f) / 100.f); + } + + // for harmful no-magnitude effects (e.g. silence) check if enemy is already has them + // for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them + if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + { + if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + { + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) + return 0.f; + } + else + { + CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) + return 0.f; + } + } + + rating *= calcEffectCost(effect); + + // Currently treating all "on target" or "on touch" effects to target the enemy actor. + // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. + if (effect.mRange != ESM::RT_Self) + rating *= -1.f; + + return rating; + } + + float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + // NOTE: enemy may be empty + float rating = 0.f; + for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) + { + rating += rateEffect(*it, actor, enemy); + + if (it->mRange == ESM::RT_Target) + rating *= 1.5f; + } + return rating; + } + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); + + float mult = fAIMagicSpellMult; + + for (std::vector::const_iterator effectIt = + spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mRange == ESM::RT_Target) + { + if (!MWBase::Environment::get().getWorld()->isSwimming(enemy)) + mult = fAIRangeMagicSpellMult; + else + mult = 0.0f; + break; + } + } + + return MWMechanics::getSpellSuccessChance(spell, actor) * mult; + } +} diff --git a/apps/openmw/mwmechanics/spellpriority.hpp b/apps/openmw/mwmechanics/spellpriority.hpp new file mode 100644 index 000000000..4e5ff5c71 --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_SPELL_PRIORITY_H +#define OPENMW_SPELL_PRIORITY_H + +#include + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + // RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects. + enum RangeTypes + { + Self = 0x1, + Touch = 0x10, + Target = 0x100 + }; + + int getRangeTypes (const ESM::EffectList& effects); + + float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor); + + /// @note target may be empty + float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + /// @note target may be empty + float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); +} + +#endif diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp new file mode 100644 index 000000000..07cf6ff5f --- /dev/null +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -0,0 +1,146 @@ +#include "weaponpriority.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" + +#include "npcstats.hpp" +#include "combat.hpp" +#include "aicombataction.hpp" +#include "spellpriority.hpp" + +namespace MWMechanics +{ + float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, + float arrowRating, float boltRating) + { + if (item.getTypeName() != typeid(ESM::Weapon).name()) + return 0.f; + + const ESM::Weapon* weapon = item.get()->mBase; + + if (type != -1 && weapon->mData.mType != type) + return 0.f; + + float rating=0.f; + float bonus=0.f; + + if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) + { + // Range weapon is useless under water + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) + return 0.f; + + if (enemy.isEmpty()) + return 0.f; + + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) + return 0.f; + + bonus+=1.5f; + } + + if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) + { + rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; + + if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown) + MWMechanics::resistNormalWeapon(enemy, actor, item, rating); + } + else + { + for (int i=0; i<2; ++i) + { + rating += weapon->mData.mSlash[i]; + rating += weapon->mData.mThrust[i]; + rating += weapon->mData.mChop[i]; + } + rating /= 6.f; + + MWMechanics::resistNormalWeapon(enemy, actor, item, rating); + } + + if (item.getClass().hasItemHealth(item)) + { + if (item.getClass().getItemHealth(item) == 0) + return 0.f; + rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item)); + } + + if (weapon->mData.mType == ESM::Weapon::MarksmanBow) + { + if (arrowRating <= 0.f) + rating = 0.f; + else + rating += arrowRating; + } + else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + if (boltRating <= 0.f) + rating = 0.f; + else + rating += boltRating; + } + + if (!weapon->mEnchant.empty()) + { + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); + if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes + && (item.getCellRef().getEnchantmentCharge() == -1 + || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) + rating += rateEffects(enchantment->mEffects, actor, enemy); + } + + int skill = item.getClass().getEquipmentSkill(item); + if (skill != -1) + rating *= actor.getClass().getSkill(actor, skill) / 100.f; + + // There is no need to apply bonus if weapon rating == 0 + if (rating == 0.f) + return 0.f; + + return rating + bonus; + } + + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); + static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); + static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); + + if (weapon.isEmpty()) + return 0.f; + + float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; + float chopMult = fAIMeleeWeaponMult; + float bonusDamage = 0.f; + + const ESM::Weapon* esmWeap = weapon.get()->mBase; + + if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) + { + if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) + { + bonusDamage = ammo.get()->mBase->mData.mChop[1]; + chopMult = fAIRangeMeleeWeaponMult; + } + else + chopMult = 0.f; + } + + float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult; + float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult; + float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult; + + return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult + + std::max(std::max(chopRating, slashRating), thrustRating); + } + +} diff --git a/apps/openmw/mwmechanics/weaponpriority.hpp b/apps/openmw/mwmechanics/weaponpriority.hpp new file mode 100644 index 000000000..90a767c4a --- /dev/null +++ b/apps/openmw/mwmechanics/weaponpriority.hpp @@ -0,0 +1,14 @@ +#ifndef OPENMW_WEAPON_PRIORITY_H +#define OPENMW_WEAPON_PRIORITY_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, + int type=-1, float arrowRating=0.f, float boltRating=0.f); + + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); +} + +#endif From ffcdedced346871a444830ac9234a0ec8db83c37 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 1 Aug 2017 20:35:10 +0200 Subject: [PATCH 050/136] [macOS, CI] Use FTP URL from environment This URL is also subject to change, moving to Travis settings. --- CI/deploy.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/deploy.osx.sh b/CI/deploy.osx.sh index 1ff6f89c3..53bfa18b5 100755 --- a/CI/deploy.osx.sh +++ b/CI/deploy.osx.sh @@ -6,4 +6,4 @@ DATE=`date +'%d%m%Y'` SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}` TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg" -curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "ftp://s3.mydevil.net:21/nightly/${TARGET_FILENAME}" +curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}" From 748f5225a914907db2e918ef9a07153b002a0207 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 2 Aug 2017 02:20:27 +0300 Subject: [PATCH 051/136] Copy PathFinder::mPath back value when pass to MWMechanics::AiPackage::pathTo as dest May become dangling reference because method may remove all elements from mPath. --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index baf4efc03..b44b187ad 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -489,7 +489,7 @@ namespace MWMechanics float duration, AiWanderStorage& storage, ESM::Position& pos) { // Is there no destination or are we there yet? - if ((!mPathFinder.isPathConstructed()) || pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE)) + if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE)) { stopWalking(actor, storage); storage.setState(Wander_ChooseAction); From cb32f1d60ada705ce25151ea1a36538a4ccfc34c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 2 Aug 2017 16:05:05 +0000 Subject: [PATCH 052/136] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 6125ed36d..8aaa6cf73 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -50,6 +50,7 @@ Programmers Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 + elsid Emanuel Guével (potatoesmaster) eroen escondida From 3cfd9af94591bf00386c70c32fdafe2d31fa2d06 Mon Sep 17 00:00:00 2001 From: Julian Date: Wed, 2 Aug 2017 18:54:16 +0200 Subject: [PATCH 053/136] merge redundant input events --- components/sdlutil/sdlinputwrapper.cpp | 33 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index ac172b84b..56411ca88 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,17 +49,42 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v SDL_PumpEvents(); - SDL_Event evt; + SDL_Event event; if (windowEventsOnly) { // During loading, just handle window events, and keep others for later - while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) - handleWindowEvent(evt); + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) + handleWindowEvent(event); return; } - while(SDL_PollEvent(&evt)) + // Merge redundant events to avoid unnecessary listener calls + std::vector events; + while(SDL_PollEvent(&event)) { + if (events.empty() || events.back().type != event.type) + { + events.emplace_back(event); + continue; + } + + SDL_Event& previousEvent = events.back(); + + switch (event.type) + { + case SDL_MOUSEMOTION: + previousEvent.motion.x = event.motion.x; + previousEvent.motion.y = event.motion.y; + previousEvent.motion.xrel += event.motion.xrel; + previousEvent.motion.yrel += event.motion.yrel; + break; + default: + events.emplace_back(event); + } + } + + + for (const SDL_Event& evt : events) { switch(evt.type) { From 2fdffb1995ae920c0dfa800b270fce1417ac83ce Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 2 Aug 2017 18:05:33 -0500 Subject: [PATCH 054/136] Adding myself to Authors.md I've had a few pull requests merged, so I assume I'm ready to be added. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8aaa6cf73..95c741eab 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -146,6 +146,7 @@ Programmers t6 terrorfisch Thomas Luppi (Digmaster) + Will Herrmann (Thunderforge) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) viadanna From 487e72fd23f527cd3288a18bb60a6a4f17647147 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 18:39:59 +0400 Subject: [PATCH 055/136] Play Up sounds instead of Down ones in trade window (bug #3982) --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c6b8a4bd7..8b0f895d1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -320,7 +320,7 @@ namespace MWGui { ensureSelectedItemUnequipped(count); const ItemStack& item = mTradeModel->getItem(mSelectedItem); - std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); + std::string sound = item.mBase.getClass().getUpSoundId(item.mBase); MWBase::Environment::get().getWindowManager()->playSound(sound); if (item.mType == ItemStack::Type_Barter) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 5f4433a47..e05848ef8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -209,7 +209,7 @@ namespace MWGui void TradeWindow::sellItem(MyGUI::Widget* sender, int count) { const ItemStack& item = mTradeModel->getItem(mItemToSell); - std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); + std::string sound = item.mBase.getClass().getUpSoundId(item.mBase); MWBase::Environment::get().getWindowManager()->playSound(sound); TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel(); From 35beede0658c3993def9bc2099af529b0019fc07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 18:41:13 +0400 Subject: [PATCH 056/136] Restock items after trade deal instead of trade window opening --- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e05848ef8..f82d2f68d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -122,8 +122,6 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; - restock(); - std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); @@ -357,6 +355,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + + restock(); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) From d1489f5b42a59c8d0d8fb9112b481409bb6a36d8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 19:12:21 +0400 Subject: [PATCH 057/136] Take in account a temporary disposition in isAggressive check (bug #3987) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62ac9bd40..751f8d164 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1490,7 +1490,7 @@ namespace MWMechanics { int disposition = 50; if (ptr.getClass().isNpc()) - disposition = getDerivedDisposition(ptr, false); + disposition = getDerivedDisposition(ptr, true); int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast(disposition)))); From 56a30d7aeccefe15a6172089d47f648bc75995bb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 20:27:14 +0400 Subject: [PATCH 058/136] Journalbook layout fixes --- apps/openmw/mwgui/journalbooks.cpp | 10 +++++----- apps/openmw/mwgui/journalwindow.cpp | 8 ++++---- files/mygui/openmw_journal.layout | 16 ++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 5634eb080..a1d74fab6 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -82,7 +82,7 @@ namespace AddEntry::operator () (entry); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (30); } }; @@ -107,7 +107,7 @@ namespace mTypesetter->selectContent (mContentId); mTypesetter->write (mBodyStyle, 2, 3);// end quote - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (30); } }; @@ -121,7 +121,7 @@ namespace void operator () (MWGui::JournalViewModel::Utf8Span topicName) { mTypesetter->write (mBodyStyle, topicName); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (); } }; @@ -135,7 +135,7 @@ namespace void operator () (MWGui::JournalViewModel::Utf8Span topicName) { mTypesetter->write (mBodyStyle, topicName); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (); } }; } @@ -250,7 +250,7 @@ book JournalBooks::createTopicIndexBook () BookTypesetter::Ptr JournalBooks::createTypesetter () { //TODO: determine page size from layout... - return BookTypesetter::create (240, 300); + return BookTypesetter::create (240, 320); } } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 105f95085..e96cc8b70 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -187,12 +187,12 @@ namespace } adjustButton(TopicsBTN); - int width = getWidget(TopicsBTN)->getSize().width + getWidget(QuestsBTN)->getSize().width; int topicsWidth = getWidget(TopicsBTN)->getSize().width; - int pageWidth = getWidget(RightBookPage)->getSize().width; + int cancelLeft = getWidget(CancelBTN)->getPosition().left; + int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(TopicsBTN)->setPosition((pageWidth - width)/2, getWidget(TopicsBTN)->getPosition().top); - getWidget(QuestsBTN)->setPosition((pageWidth - width)/2 + topicsWidth, getWidget(QuestsBTN)->getPosition().top); + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); mQuestMode = false; mAllQuests = false; diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index c53f39578..1131b1bbc 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -49,33 +49,33 @@ - - + + - + - + - + - + - + @@ -88,7 +88,7 @@ - + From c920d083e421f947a33c04203dbb49556ef88aaf Mon Sep 17 00:00:00 2001 From: Siimacore Date: Thu, 3 Aug 2017 23:15:26 +0200 Subject: [PATCH 059/136] Correcting https://bugs.openmw.org/issues/3906. --- apps/launcher/maindialog.cpp | 10 +++++++++- apps/launcher/maindialog.hpp | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 94e186db8..31da90d2f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -172,7 +172,10 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() } } - return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; + if (!setup() || !setupGameData()) { + return FirstRunDialogResultFailure; + } + return FirstRunDialogResultContinue; } void Launcher::MainDialog::setVersionLabel() @@ -344,6 +347,11 @@ bool Launcher::MainDialog::setupGameSettings() file.close(); } + return true; +} + +bool Launcher::MainDialog::setupGameData() +{ QStringList dataDirs; // Check if the paths actually contain data files diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 96b5c0b97..8d0d61b8f 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -72,6 +72,7 @@ namespace Launcher bool setupLauncherSettings(); bool setupGameSettings(); bool setupGraphicsSettings(); + bool setupGameData(); void setVersionLabel(); From 23bda7613beb1257a01690d4462d0d7375b0f63a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 Aug 2017 07:31:41 +0400 Subject: [PATCH 060/136] Do not allow to use journal in a main menu (bug #3991) --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7b2a1560d..a823ae0fd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1022,6 +1022,7 @@ namespace MWInput return; if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getWindowManager()->playSound ("book open"); From fbec0d9443497d4124fdb1825b53cb0a24c83a85 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 4 Aug 2017 21:43:01 +0300 Subject: [PATCH 061/136] [Client] Remove inertia from players who are teleported via a packet --- apps/openmw/mwbase/world.hpp | 10 ++++++++++ apps/openmw/mwmp/LocalPlayer.cpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ apps/openmw/mwworld/worldimp.hpp | 10 ++++++++++ 4 files changed, 35 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4070d76da..9a92f427e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -297,6 +297,16 @@ namespace MWBase ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + /* + Start of tes3mp addition + + Make it possible to set the inertial force of a Ptr directly + */ + virtual void setInertialForce(const MWWorld::Ptr& ptr, const osg::Vec3f &force) = 0; + /* + End of tes3mp addition + */ + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; ///< cast a Ray and return true if there is an object in the ray path. diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index ecd6cfdef..d09575267 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -801,8 +801,10 @@ void LocalPlayer::setPosition() else { world->getPlayer().setTeleported(true); + world->moveObject(ptrPlayer, position.pos[0], position.pos[1], position.pos[2]); world->rotateObject(ptrPlayer, position.rot[0], position.rot[1], position.rot[2]); + world->setInertialForce(ptrPlayer, osg::Vec3f(0.f, 0.f, 0.f)); } updatePosition(true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ea887aa2..2e97e3ab7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1512,6 +1512,19 @@ namespace MWWorld mPhysics->queueObjectMovement(ptr, velocity); } + /* + Start of tes3mp addition + + Make it possible to set the inertial force of a Ptr directly + */ + void World::setInertialForce(const Ptr& ptr, const osg::Vec3f &force) + { + mPhysics->getActor(ptr)->setInertialForce(force); + } + /* + End of tes3mp addition + */ + void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8dfa6b906..8fbcb88c2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -398,6 +398,16 @@ namespace MWWorld ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + /* + Start of tes3mp addition + + Make it possible to set the inertial force of a Ptr directly + */ + void setInertialForce(const Ptr& ptr, const osg::Vec3f &force); + /* + End of tes3mp addition + */ + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); ///< cast a Ray and return true if there is an object in the ray path. From 0e2038f045135310271dd1b3cb2d6ccc91328e49 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 4 Aug 2017 21:45:52 +0300 Subject: [PATCH 062/136] [General] Record and get player positions before their last cell change --- apps/openmw-mp/Script/Functions/Positions.cpp | 24 ++++++++++++++++ apps/openmw-mp/Script/Functions/Positions.hpp | 28 +++++++++++++++++++ apps/openmw/mwmp/LocalPlayer.cpp | 1 + components/openmw-mp/Base/BasePlayer.hpp | 1 + .../Packets/Player/PacketPlayerCellChange.cpp | 2 ++ 5 files changed, 56 insertions(+) diff --git a/apps/openmw-mp/Script/Functions/Positions.cpp b/apps/openmw-mp/Script/Functions/Positions.cpp index cd2f26f5a..11c5d4f40 100644 --- a/apps/openmw-mp/Script/Functions/Positions.cpp +++ b/apps/openmw-mp/Script/Functions/Positions.cpp @@ -45,6 +45,30 @@ double PositionFunctions::GetPosZ(unsigned short pid) noexcept return player->position.pos[2]; } +double PositionFunctions::GetPreviousCellPosX(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0.0f); + + return player->previousCellPosition.pos[0]; +} + +double PositionFunctions::GetPreviousCellPosY(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0.0f); + + return player->previousCellPosition.pos[1]; +} + +double PositionFunctions::GetPreviousCellPosZ(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0.0f); + + return player->previousCellPosition.pos[2]; +} + void PositionFunctions::GetRot(unsigned short pid, float *x, float *y, float *z) noexcept { *x = 0.00; diff --git a/apps/openmw-mp/Script/Functions/Positions.hpp b/apps/openmw-mp/Script/Functions/Positions.hpp index 1924525e1..ae8b8a768 100644 --- a/apps/openmw-mp/Script/Functions/Positions.hpp +++ b/apps/openmw-mp/Script/Functions/Positions.hpp @@ -9,6 +9,10 @@ {"GetPosY", PositionFunctions::GetPosY},\ {"GetPosZ", PositionFunctions::GetPosZ},\ \ + {"GetPreviousCellPosX", PositionFunctions::GetPreviousCellPosX},\ + {"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\ + {"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\ + \ {"GetRot", PositionFunctions::GetRot},\ {"GetRotX", PositionFunctions::GetRotX},\ {"GetRotZ", PositionFunctions::GetRotZ},\ @@ -59,6 +63,30 @@ public: */ static double GetPosZ(unsigned short pid) noexcept; + /** + * \brief Get the X position of a player from before their latest cell change. + * + * \param pid The player ID. + * \return The X position. + */ + static double GetPreviousCellPosX(unsigned short pid) noexcept; + + /** + * \brief Get the Y position of a player from before their latest cell change. + * + * \param pid The player ID. + * \return The Y position. + */ + static double GetPreviousCellPosY(unsigned short pid) noexcept; + + /** + * \brief Get the Z position of a player from before their latest cell change. + * + * \param pid The player ID. + * \return The Z position. + */ + static double GetPreviousCellPosZ(unsigned short pid) noexcept; + /** * \brief Assign the player's rotational coordinate values to the variables passed as * parameters. diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index d09575267..f3c1ec6c6 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -375,6 +375,7 @@ void LocalPlayer::updateCell(bool forceUpdate) } cell = *ptrCell; + previousCellPosition = position; // Make sure the position is updated before a cell packet is sent, or else // cell change events in server scripts will have the wrong player position diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 4f4bdbd4b..1f971d285 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -235,6 +235,7 @@ namespace mwmp ESM::Position position; ESM::Position direction; + ESM::Position previousCellPosition; ESM::Cell cell; ESM::NPC npc; ESM::NpcStats npcStats; diff --git a/components/openmw-mp/Packets/Player/PacketPlayerCellChange.cpp b/components/openmw-mp/Packets/Player/PacketPlayerCellChange.cpp index acc5415df..4bb05b1a8 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerCellChange.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerCellChange.cpp @@ -20,6 +20,8 @@ void mwmp::PacketPlayerCellChange::Packet(RakNet::BitStream *bs, bool send) RW(player->cell.mData, send, 1); RW(player->cell.mName, send, 1); + RW(player->previousCellPosition.pos, send, 1); + RW(player->isChangingRegion, send); if (player->isChangingRegion) From 63343b6241de45a6db433d33aa2788ac78eb6aea Mon Sep 17 00:00:00 2001 From: Jake Westrip Date: Sat, 5 Aug 2017 06:15:15 +1000 Subject: [PATCH 063/136] Ensure jail does not decrease a skill past zero --- apps/openmw/mwgui/jailscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 211e0c5f9..8ac133d76 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -93,7 +93,7 @@ namespace MWGui if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) value.setBase(std::min(100, value.getBase()+1)); else - value.setBase(value.getBase()-1); + value.setBase(std::max(0, value.getBase()-1)); } const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); From bf70b97f899730db4bba06b270cbf52f9ab48a98 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 4 Aug 2017 21:44:20 +0000 Subject: [PATCH 064/136] Update AUTHORS.md --- AUTHORS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 95c741eab..2a10cbc2b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -62,8 +62,8 @@ Programmers Hallfaer Tuilinn hristoast Internecine - Jacob Essex (Yacoby) - Jannik Heller (scrawl) + Jacob Essex (Yacoby) + Jake Westrip (16bitint) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) @@ -132,6 +132,7 @@ Programmers Roman Proskuryakov (kpp) Sandy Carter (bwrsandman) Scott Howard + scrawl Sebastian Wick (swick) Sergey Shambir ShadowRadiance From cf7a6232d021050d327b905ea16c2ef8995c488e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 1 Aug 2017 21:42:49 +0400 Subject: [PATCH 065/136] Combat AI: use WhenUsed enchantments --- apps/openmw/mwmechanics/aicombataction.cpp | 2 + apps/openmw/mwmechanics/aicombataction.hpp | 4 +- apps/openmw/mwmechanics/spellpriority.cpp | 50 ++++++++++++++++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 1bfeff074..d44498966 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -71,6 +71,8 @@ namespace MWMechanics { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(mItem->getClass().getEnchantment(*mItem)); int types = getRangeTypes(enchantment->mEffects); + + isRanged = (types & RangeTypes::Target) | (types & RangeTypes::Self); return suggestCombatRange(types); } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index dc6f359d6..466ae2dc4 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -54,7 +54,7 @@ namespace MWMechanics virtual float getCombatRange (bool& isRanged) const; /// Since this action has no animation, apply a small cool down for using it - virtual float getActionCooldown() { return 1.f; } + virtual float getActionCooldown() { return 0.75f; } }; class ActionPotion : public Action @@ -68,7 +68,7 @@ namespace MWMechanics virtual bool isAttackingOrSpell() const { return false; } /// Since this action has no animation, apply a small cool down for using it - virtual float getActionCooldown() { return 1.f; } + virtual float getActionCooldown() { return 0.75f; } }; class ActionWeapon : public Action diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index a73e4fd89..a56f430c6 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -46,6 +46,26 @@ namespace } return toCure; } + + float getSpellDuration (const MWWorld::Ptr& actor, const std::string& spellId) + { + float duration = 0; + const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); + for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) + { + if (it->first != spellId) + continue; + + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; + for (std::vector::const_iterator effectIt = params.mEffects.begin(); + effectIt != params.mEffects.end(); ++effectIt) + { + if (effectIt->mDuration > duration) + duration = effectIt->mDuration; + } + } + return duration; + } } namespace MWMechanics @@ -114,15 +134,39 @@ namespace MWMechanics const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); + // Spells don't stack, so early out if the spell is still active on the target + int types = getRangeTypes(enchantment->mEffects); + if ((types & Self) && actor.getClass().getCreatureStats(actor).getActiveSpells().isSpellActive(ptr.getCellRef().getRefId())) + return 0.f; + + if (types & (Touch|Target) && getSpellDuration(enemy, ptr.getCellRef().getRefId()) > 3) + return 0.f; + if (enchantment->mData.mType == ESM::Enchantment::CastOnce) { return rateEffects(enchantment->mEffects, actor, enemy); } - else + else if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - //if (!ptr.getClass().canBeEquipped(ptr, actor)) - return 0.f; + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + + // Creatures can not wear armor/clothing, so allow creatures to use non-equipped items, + if (actor.getClass().isNpc() && !store.isEquipped(ptr)) + return 0.f; + + int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), actor); + + if (ptr.getCellRef().getEnchantmentCharge() != -1 + && ptr.getCellRef().getEnchantmentCharge() < castCost) + return 0.f; + + float rating = rateEffects(enchantment->mEffects, actor, enemy); + + rating *= 2; // prefer rechargable magic items over spells + return rating; } + + return 0.f; } float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) From 72ce118d02ee3691be45eab187d85b16311136f3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 5 Aug 2017 12:38:26 +0400 Subject: [PATCH 066/136] Disable AiPursue package for player's followers --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62ac9bd40..2f217ab12 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1152,7 +1152,19 @@ namespace MWMechanics it->getClass().getNpcStats(*it).setCrimeId(id); if (!it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) + { + // Player's followers should not try to arrest player + if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) + { + std::set playerFollowers; + getActorsSidingWith(player, playerFollowers); + + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + } + it->getClass().getCreatureStats(*it).getAiSequence().stack(AiPursue(player), *it); + } } else { From 77ce05b7d6fa73b49aa8b2a4bc8c83c0461d87f9 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 6 Aug 2017 00:11:54 +0300 Subject: [PATCH 067/136] [Client] Fix spell casting probability synchronization --- apps/openmw/mwmechanics/spellcasting.cpp | 20 ++------------------ apps/openmw/mwmp/LocalActor.cpp | 4 +++- apps/openmw/mwmp/LocalPlayer.cpp | 4 +++- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index bf93ccd8b..d93290302 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -917,14 +917,8 @@ namespace MWMechanics /* Start of tes3mp change (major) - Instead of checking whether the caster is a player or an NPC, - first check whether it's the LocalPlayer or a DedicatedPlayer and calculate - calculate the success chance in clients' LocalPlayer::prepareAttack() - - TODO: Make this make sense for NPCs too - - TODO: See if LocalPlayer being the target and having godmode on - can be accounted for like it is in OpenMW's corresponding code + Make spell casting fail based on the attack success rated determined + in LocalPlayer and LocalActor's updateAttack() */ mwmp::Attack *localAttack = NULL; mwmp::Attack *dedicatedAttack = MechanicsHelper::getDedicatedAttack(mCaster); @@ -944,19 +938,9 @@ namespace MWMechanics } fail = true; } - else if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())) /* End of tes3mp change (major) */ - { - float successChance = getSpellSuccessChance(spell, mCaster); - if (Misc::Rng::roll0to99() >= successChance) - { - if (mCaster == getPlayer()) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); - fail = true; - } - } if (fail) { diff --git a/apps/openmw/mwmp/LocalActor.cpp b/apps/openmw/mwmp/LocalActor.cpp index e2bc97150..7c4143517 100644 --- a/apps/openmw/mwmp/LocalActor.cpp +++ b/apps/openmw/mwmp/LocalActor.cpp @@ -241,7 +241,9 @@ void LocalActor::updateAttack() { MWMechanics::CreatureStats &attackerStats = ptr.getClass().getCreatureStats(ptr); attack.spellId = attackerStats.getSpells().getSelectedSpell(); - attack.success = MechanicsHelper::getSpellSuccess(attack.spellId, ptr); + + if (attack.pressed) + attack.success = MechanicsHelper::getSpellSuccess(attack.spellId, ptr); } mwmp::Main::get().getNetworking()->getActorList()->addAttackActor(*this); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index f3c1ec6c6..06fcc18b1 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -525,7 +525,9 @@ void LocalPlayer::updateAttack() if (attack.type == Attack::MAGIC) { attack.spellId = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); - attack.success = MechanicsHelper::getSpellSuccess(attack.spellId, getPlayerPtr()); + + if (attack.pressed) + attack.success = MechanicsHelper::getSpellSuccess(attack.spellId, getPlayerPtr()); } getNetworking()->getPlayerPacket(ID_PLAYER_ATTACK)->setPlayer(this); From 393f4ab75834e41a1f1c0652ba21031cbb1d2d82 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 6 Aug 2017 13:02:22 +0200 Subject: [PATCH 068/136] Add missing include for isatty function (Fixes #4002) --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index a7e522acd..9e44f237e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -20,6 +20,9 @@ #include #endif +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#include +#endif #if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 From 60a7d3d6e0af503f81e3e5ec9b1b0c007f2cf000 Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Sun, 6 Aug 2017 20:10:56 +0200 Subject: [PATCH 069/136] Fade out music before change occurs --- apps/openmw/mwsound/soundmanagerimp.cpp | 40 +++++++++++++++++++++++-- apps/openmw/mwsound/soundmanagerimp.hpp | 6 ++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 53c0643f6..97030643f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -34,7 +34,7 @@ namespace MWSound { - SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) , mFallback(fallbackMap) , mOutput(new DEFAULT_OUTPUT(*this)) @@ -328,9 +328,23 @@ namespace MWSound } } + void SoundManager::advanceMusic(const std::string& filename) + { + if (!isMusicPlaying()) + { + streamMusicFull(filename); + return; + } + + mMusicFader = 0.5f; + mNextMusic = filename; + + mMusic->setFadeout(mMusicFader); + } + void SoundManager::streamMusic(const std::string& filename) { - streamMusicFull("Music/"+filename); + advanceMusic("Music/"+filename); } void SoundManager::startRandomTitle() @@ -370,7 +384,7 @@ namespace MWSound i = (i+1) % filelist.size(); } - streamMusicFull(filelist[i]); + advanceMusic(filelist[i]); } bool SoundManager::isMusicPlaying() @@ -1029,6 +1043,25 @@ namespace MWSound } + void SoundManager::updateMusic(float duration) + { + if (!mNextMusic.empty()) + { + mMusic->updateFade(duration); + + mOutput->startUpdate(); + mOutput->updateStream(mMusic); + mOutput->finishUpdate(); + + if (mMusic->getRealVolume() <= 0.f) + { + streamMusicFull(mNextMusic); + mNextMusic.clear(); + } + } + } + + void SoundManager::update(float duration) { if(!mOutput->isInitialized()) @@ -1040,6 +1073,7 @@ namespace MWSound updateSounds(duration); updateRegionSound(duration); updateWaterSound(duration); + updateMusic(duration); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index bf628b102..1c5348e65 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -114,9 +114,15 @@ namespace MWSound MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); + void advanceMusic(const std::string& filename); + void updateSounds(float duration); void updateRegionSound(float duration); void updateWaterSound(float duration); + void updateMusic(float duration); + + float mMusicFader; + std::string mNextMusic; float volumeFromType(PlayType type) const; From 632d39ca767978620100d83052a6dedd9067157c Mon Sep 17 00:00:00 2001 From: spycrab Date: Sun, 6 Aug 2017 15:03:48 +0200 Subject: [PATCH 070/136] Allow starting at an (unnamed) exterior cell using --start (Feature #3941) --- apps/openmw/engine.cpp | 3 +-- apps/openmw/engine.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 426300149..c921e17d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -278,8 +278,7 @@ void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) mResDir = parResDir; } -// Set start cell name (only interiors for now) - +// Set start cell name void OMW::Engine::setCell (const std::string& cellName) { mCellName = cellName; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 29419a4c2..bf144bfed 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -148,7 +148,7 @@ namespace OMW /// Set resource dir void setResourceDir(const boost::filesystem::path& parResDir); - /// Set start cell name (only interiors for now) + /// Set start cell name void setCell(const std::string& cellName); /** diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f8d44292e..a9506385d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2582,7 +2582,25 @@ namespace MWWorld { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - if (const ESM::Cell *ext = getExterior(name)) { + const ESM::Cell *ext = getExterior(name); + + if (!ext && name.find(',') != std::string::npos) { + try { + int x = std::stoi(name.substr(0, name.find(','))); + int y = std::stoi(name.substr(name.find(',')+1)); + ext = getExterior(x, y)->getCell(); + } + catch (std::invalid_argument) + { + // This exception can be ignored, as this means that name probably refers to a interior cell instead of comma separated coordinates + } + catch (std::out_of_range) + { + throw std::runtime_error("Cell coordinates out of range."); + } + } + + if (ext) { int x = ext->getGridX(); int y = ext->getGridY(); indexToPosition(x, y, pos.pos[0], pos.pos[1], true); @@ -2592,6 +2610,7 @@ namespace MWWorld return true; } + return false; } From cef415509f9db64c7eea93bf1ba6f799215f2a9f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 6 Aug 2017 20:54:20 +0000 Subject: [PATCH 071/136] Revert "Merge redundant input events" --- components/sdlutil/sdlinputwrapper.cpp | 33 ++++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 56411ca88..ac172b84b 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,42 +49,17 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v SDL_PumpEvents(); - SDL_Event event; + SDL_Event evt; if (windowEventsOnly) { // During loading, just handle window events, and keep others for later - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) - handleWindowEvent(event); + while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) + handleWindowEvent(evt); return; } - // Merge redundant events to avoid unnecessary listener calls - std::vector events; - while(SDL_PollEvent(&event)) { - if (events.empty() || events.back().type != event.type) - { - events.emplace_back(event); - continue; - } - - SDL_Event& previousEvent = events.back(); - - switch (event.type) - { - case SDL_MOUSEMOTION: - previousEvent.motion.x = event.motion.x; - previousEvent.motion.y = event.motion.y; - previousEvent.motion.xrel += event.motion.xrel; - previousEvent.motion.yrel += event.motion.yrel; - break; - default: - events.emplace_back(event); - } - } - - - for (const SDL_Event& evt : events) + while(SDL_PollEvent(&evt)) { switch(evt.type) { From bf8d10587ec8e3954b61764773162dba6d9ac76f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 6 Aug 2017 21:09:29 +0000 Subject: [PATCH 072/136] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2a10cbc2b..c48647f4e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -139,6 +139,7 @@ Programmers Siimacore sir_herrbatka smbas + spycrab Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) stil-t From dd919b9f2cb2e1e546e0e0ef899f051782cfebb3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 26 Jul 2017 14:42:01 +0400 Subject: [PATCH 073/136] Do not allow to loot fighting actors during death animation (bug #3528) --- apps/openmw/mwclass/creature.cpp | 30 +++++++++++++--- apps/openmw/mwclass/npc.cpp | 36 +++++++++++++------ .../reference/modding/settings/game.rst | 18 +++++++++- files/settings-default.cfg | 3 ++ 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ce03af7a1..65f8c80d8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" @@ -448,10 +449,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); - if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) + const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + + if(stats.isDead()) + { + bool canLoot = Settings::Manager::getBool ("can loot during death animation", "Game"); + + // by default user can loot friendly actors during death animation + if (canLoot && !stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing + return std::shared_ptr (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } @@ -558,7 +576,11 @@ namespace MWClass return true; const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); - return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); + + if (customData.mCreatureStats.isDead() && customData.mCreatureStats.isDeathAnimationFinished()) + return true; + + return !customData.mCreatureStats.getAiSequence().isInCombat(); } MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f8ff3da19..ed1f12b31 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -863,16 +864,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); - if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::FailedAction("#{sActorInCombat}")); - if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) - || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing - // Can't talk to werewolfs - if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf()) + const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + + if(stats.isDead()) + { + bool canLoot = Settings::Manager::getBool ("can loot during death animation", "Game"); + + // by default user can loot friendly actors during death animation + if (canLoot && !stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } @@ -1019,7 +1031,11 @@ namespace MWClass return true; const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); - return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); + + if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished()) + return true; + + return !customData.mNpcStats.getAiSequence().isInCombat(); } MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 62fe5a70e..e1d5d75f6 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -65,6 +65,22 @@ the type of attack is determined by the direction that the character is moving a The default value is false. This setting can be toggled with the Always Use Best Attack button in the Prefs panel of the Options menu. +can loot during death animation +------------------------------- + +:Type: boolean +:Range: True/False +:Default: True + +If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. +However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. +This is how original Morrowind behaves. + +If this setting is false, player has to wait until end of death animation in all cases. +This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. + +The default value is true. This setting can only be configured by editing the settings configuration file. + difficulty ---------- @@ -110,4 +126,4 @@ followers attack on sight :Default: False Makes player followers and escorters start combat with enemies who have started combat with them or the player. -Otherwise they wait for the enemies or the player to do an attack first. \ No newline at end of file +Otherwise they wait for the enemies or the player to do an attack first. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 40c1ed099..a0460326b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -180,6 +180,9 @@ prevent merchant equipping = false # or the player. Otherwise they wait for the enemies or the player to do an attack first. followers attack on sight = false +# Can loot non-fighting actors during death animation +can loot during death animation = true + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). From ab391f17dbcd06ecfbe7829503e96d37b4cd0069 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 7 Aug 2017 12:12:57 +0400 Subject: [PATCH 074/136] Fixes regression in spell school detection (bug #4007) --- apps/openmw/mwmechanics/spellcasting.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a6ae5ca65..ecd4ba48a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -121,6 +121,11 @@ namespace MWMechanics CreatureStats& stats = actor.getClass().getCreatureStats(actor); + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); + + float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; + castChance *= stats.getFatigueTerm(); + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) return 0; @@ -138,11 +143,6 @@ namespace MWMechanics return 100; } - float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); - - float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; - castChance *= stats.getFatigueTerm(); - if (!cap) return std::max(0.f, castChance); else From 7b8278ae45941226a555a5c9dd4840d9fc57eca1 Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Tue, 8 Aug 2017 03:17:40 +0200 Subject: [PATCH 075/136] remove redundant mMusicFader variable --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +-- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 97030643f..88ee42b01 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -336,10 +336,9 @@ namespace MWSound return; } - mMusicFader = 0.5f; mNextMusic = filename; - mMusic->setFadeout(mMusicFader); + mMusic->setFadeout(0.5f); } void SoundManager::streamMusic(const std::string& filename) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 1c5348e65..5d911d4be 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -121,7 +121,6 @@ namespace MWSound void updateWaterSound(float duration); void updateMusic(float duration); - float mMusicFader; std::string mNextMusic; float volumeFromType(PlayType type) const; From 546352dbe311a11cbd1e2da9335ef38b9197d59f Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Tue, 8 Aug 2017 03:31:01 +0200 Subject: [PATCH 076/136] avoid starting sound updates more than necessary --- apps/openmw/mwsound/soundmanagerimp.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 88ee42b01..c6f663059 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -938,6 +938,8 @@ namespace MWSound env ); + updateMusic(duration); + // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -1048,9 +1050,7 @@ namespace MWSound { mMusic->updateFade(duration); - mOutput->startUpdate(); mOutput->updateStream(mMusic); - mOutput->finishUpdate(); if (mMusic->getRealVolume() <= 0.f) { @@ -1072,7 +1072,6 @@ namespace MWSound updateSounds(duration); updateRegionSound(duration); updateWaterSound(duration); - updateMusic(duration); } } From 6cb3c832488acbcf43b8fecdc1f98da064b29c84 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:36:50 +0400 Subject: [PATCH 077/136] Add transparency for interactive messageboxes in game mode --- apps/openmw/mwgui/messagebox.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + ...openmw_interactive_messagebox_notransp.layout | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 files/mygui/openmw_interactive_messagebox_notransp.layout diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f8ddeba3e..ab43df0f1 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -196,7 +196,7 @@ namespace MWGui InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout") + : WindowModal(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "openmw_interactive_messagebox_notransp.layout" : "openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 6592de56e..ed673c5d6 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -38,6 +38,7 @@ set(MYGUI_FILES openmw_hud.layout openmw_infobox.layout openmw_interactive_messagebox.layout + openmw_interactive_messagebox_notransp.layout openmw_inventory_window.layout openmw_journal.layout openmw_journal.skin.xml diff --git a/files/mygui/openmw_interactive_messagebox_notransp.layout b/files/mygui/openmw_interactive_messagebox_notransp.layout new file mode 100644 index 000000000..6b79b9417 --- /dev/null +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From 4cc8afd25da2aca12995c4801a3d034381903972 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:38:15 +0400 Subject: [PATCH 078/136] Add transparency for tooltips in game mode --- apps/openmw/mwgui/tooltips.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1e770a60b..798eb1d6a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -378,17 +378,11 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - if(mShowOwned == 1 || mShowOwned == 3) - { - if(isFocusObject && checkOwned()) - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); - } - else - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); - } - } + // TODO: apply alpha to "owned" background + if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); + else + mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); std::string caption = info.caption; std::string image = info.icon; From 8c1c80ab9143900e8c527678c92bfe0b62e50481 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:39:25 +0400 Subject: [PATCH 079/136] Disable transparency for persuation dialogue menu --- files/mygui/openmw_persuasion_dialog.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout index d9a673ec2..c66f9d0ad 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,7 +1,7 @@ - + From 56f5a5dee385eb2d1c3c97439d81447ba0885a07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 22:57:39 +0400 Subject: [PATCH 080/136] Added transparency to 'owned' tooltip --- apps/openmw/mwgui/tooltips.cpp | 3 +-- files/mygui/openmw_hud_box.skin.xml | 12 ++++++++++++ files/mygui/openmw_windows.skin.xml | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 798eb1d6a..81a3d864c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -378,9 +378,8 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - // TODO: apply alpha to "owned" background if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); + mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp_Owned" : "HUD_Box_Owned"); else mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 33199d6ae..e53493bb1 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -36,6 +36,18 @@ + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 00e6f9148..a272ae84a 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -158,13 +158,20 @@ - + + + + + + + + From f41a4bb93794de0e76665486ec13a06a589785f7 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 00:20:49 -0500 Subject: [PATCH 081/136] Changing "New Installation" to "Retail CD/DVD" for clarity --- apps/wizard/componentselectionpage.cpp | 7 +++---- apps/wizard/conclusionpage.cpp | 6 +++--- apps/wizard/installationpage.cpp | 7 +++---- apps/wizard/languageselectionpage.cpp | 2 +- apps/wizard/mainwizard.cpp | 5 ++--- apps/wizard/methodselectionpage.cpp | 7 +++---- files/ui/wizard/methodselectionpage.ui | 18 +++++++++--------- 7 files changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 161e51515..d99884966 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include "mainwizard.hpp" @@ -26,7 +25,7 @@ Wizard::ComponentSelectionPage::ComponentSelectionPage(QWidget *parent) : void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem*) { - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) return; // Morrowind is always checked here bool unchecked = true; @@ -60,7 +59,7 @@ void Wizard::ComponentSelectionPage::initializePage() QListWidgetItem *tribunalItem = new QListWidgetItem(QLatin1String("Tribunal")); QListWidgetItem *bloodmoonItem = new QListWidgetItem(QLatin1String("Bloodmoon")); - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { morrowindItem->setFlags((morrowindItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Checked); @@ -117,7 +116,7 @@ bool Wizard::ComponentSelectionPage::validatePage() // qDebug() << components << path << mWizard->mInstallations[path]; - if (field(QLatin1String("installation.new")).toBool() == false) { + if (field(QLatin1String("installation.retailDisc")).toBool() == false) { if (components.contains(QLatin1String("Tribunal")) && !components.contains(QLatin1String("Bloodmoon"))) { if (mWizard->mInstallations[path].hasBloodmoon) diff --git a/apps/wizard/conclusionpage.cpp b/apps/wizard/conclusionpage.cpp index 87154732a..f6a6015b8 100644 --- a/apps/wizard/conclusionpage.cpp +++ b/apps/wizard/conclusionpage.cpp @@ -16,14 +16,14 @@ Wizard::ConclusionPage::ConclusionPage(QWidget *parent) : void Wizard::ConclusionPage::initializePage() { // Write the path to openmw.cfg - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { QString path(field(QLatin1String("installation.path")).toString()); mWizard->addInstallation(path); } if (!mWizard->mError) { - if ((field(QLatin1String("installation.new")).toBool() == true) + if ((field(QLatin1String("installation.retailDisc")).toBool() == true) || (field(QLatin1String("installation.import-settings")).toBool() == true)) { qDebug() << "IMPORT SETTINGS"; @@ -33,7 +33,7 @@ void Wizard::ConclusionPage::initializePage() if (!mWizard->mError) { - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { textLabel->setText(tr("

The OpenMW Wizard successfully installed Morrowind on your computer.

\

Click Finish to close the Wizard.

")); diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index 2f0af88c9..7a4dcbf10 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -7,7 +7,6 @@ #include #include "mainwizard.hpp" -#include "inisettings.hpp" Wizard::InstallationPage::InstallationPage(QWidget *parent) : QWizardPage(parent) @@ -76,7 +75,7 @@ void Wizard::InstallationPage::initializePage() // That way installing all three components would yield 300% // When one component is done the bar will be filled by 33% - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { installProgressBar->setMaximum((components.count() * 100)); } else { if (components.contains(QLatin1String("Tribunal")) @@ -96,7 +95,7 @@ void Wizard::InstallationPage::startInstallation() QStringList components(field(QLatin1String("installation.components")).toStringList()); QString path(field(QLatin1String("installation.path")).toString()); - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { // Always install Morrowind mUnshield->setInstallComponent(Wizard::Component_Morrowind, true); @@ -227,7 +226,7 @@ bool Wizard::InstallationPage::isComplete() const int Wizard::InstallationPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_Conclusion; } else { if (!mWizard->mError) { diff --git a/apps/wizard/languageselectionpage.cpp b/apps/wizard/languageselectionpage.cpp index 0d5132f5b..4c10bf38c 100644 --- a/apps/wizard/languageselectionpage.cpp +++ b/apps/wizard/languageselectionpage.cpp @@ -30,7 +30,7 @@ void Wizard::LanguageSelectionPage::initializePage() int Wizard::LanguageSelectionPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_ComponentSelection; } else { QString path(field(QLatin1String("installation.path")).toString()); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 7ef8761dd..b99f151aa 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -258,7 +257,7 @@ void Wizard::MainWizard::runSettingsImporter() QStringList arguments; // Import plugin selection? - if (field(QLatin1String("installation.new")).toBool() == true + if (field(QLatin1String("installation.retailDisc")).toBool() == true || field(QLatin1String("installation.import-addons")).toBool() == true) arguments.append(QLatin1String("--game-files")); @@ -278,7 +277,7 @@ void Wizard::MainWizard::runSettingsImporter() // Now the paths arguments.append(QLatin1String("--ini")); - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { arguments.append(path + QDir::separator() + QLatin1String("Morrowind.ini")); } else { arguments.append(mInstallations[path].iniPath); diff --git a/apps/wizard/methodselectionpage.cpp b/apps/wizard/methodselectionpage.cpp index 5f3917bd5..e00344af9 100644 --- a/apps/wizard/methodselectionpage.cpp +++ b/apps/wizard/methodselectionpage.cpp @@ -1,5 +1,4 @@ #include "methodselectionpage.hpp" -#include #include "mainwizard.hpp" Wizard::MethodSelectionPage::MethodSelectionPage(QWidget *parent) : @@ -10,16 +9,16 @@ Wizard::MethodSelectionPage::MethodSelectionPage(QWidget *parent) : setupUi(this); #ifndef OPENMW_USE_UNSHIELD - newLocationRadioButton->setEnabled(false); + retailDiscRadioButton->setEnabled(false); existingLocationRadioButton->setChecked(true); #endif - registerField(QLatin1String("installation.new"), newLocationRadioButton); + registerField(QLatin1String("installation.retailDisc"), retailDiscRadioButton); } int Wizard::MethodSelectionPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_InstallationTarget; } else { return MainWizard::Page_ExistingInstallation; diff --git a/files/ui/wizard/methodselectionpage.ui b/files/ui/wizard/methodselectionpage.ui index 531d093af..4d4d66bad 100644 --- a/files/ui/wizard/methodselectionpage.ui +++ b/files/ui/wizard/methodselectionpage.ui @@ -17,16 +17,16 @@ Select Installation Method
- Select how OpenMW should get the required Morrowind installation files. + <html><head/><body><p>Select how you would like to install <i>The Elder Scrolls III: Morrowind</i>.</p></body></html> - + font-weight:bold; - Install Morrowind to a new location + Retail CD/DVD true @@ -34,7 +34,7 @@ - + @@ -72,14 +72,14 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - newLocationRadioButton + retailDiscRadioButton
- + - Install Morrowind from a retail disk to a new location for OpenMW to use. + Install from a retail disc to a new location. true @@ -94,7 +94,7 @@ font-weight:bold - Select an existing Morrowind installation + Existing Installation @@ -138,7 +138,7 @@ - Select an existing Morrowind installation for OpenMW to use. + Select an existing installation. true From 464c64a306bb79ca76fc0bdc3de0324e6982c37a Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 20:03:27 -0500 Subject: [PATCH 082/136] Swap the OIS Ctrl and Meta keys on macOS to match Qt --- components/sdlutil/sdlinputwrapper.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index ac172b84b..f622f2166 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -1,7 +1,6 @@ #include "sdlinputwrapper.hpp" #include -#include #include @@ -423,7 +422,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) ); mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) ); mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) ); - mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) ); mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) ); mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) ); @@ -499,9 +497,19 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) ); mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) ); mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) ); - mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); + +//Qt switches the Ctrl and Meta keys on macOS. See http://doc.qt.io/qt-5/qkeysequence.html +#if defined(__APPLE__) + mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LWIN)); + mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RWIN) ); +#else mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LWIN) ); mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RWIN) ); - mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); + mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) ); +#endif } } From 54fe6457031080a806985c6d41d5bc5a9ac0bda7 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 23:12:43 -0500 Subject: [PATCH 083/136] Removing erroneous comment since Qt is not relevant here --- components/sdlutil/sdlinputwrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f622f2166..a76de00d1 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -499,7 +499,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) ); mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); -//Qt switches the Ctrl and Meta keys on macOS. See http://doc.qt.io/qt-5/qkeysequence.html +//The function of the Ctrl and Meta keys are switched on macOS compared to other platforms. +//For instance, Cmd+C versus Ctrl+C to copy from the system clipboard #if defined(__APPLE__) mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) ); mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) ); From e4df17ccafbdfe897bcd9ef912a9467594ca8b93 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 11 Aug 2017 09:02:50 +0400 Subject: [PATCH 084/136] Make inventory avatar to fit within border (bug #4003) --- files/mygui/openmw_inventory_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 09e5ed9c7..bb707fa0d 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -12,7 +12,7 @@ - + From c542ae6875c8e913f8824cdc4fca303d0e893b45 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 09:06:31 +0400 Subject: [PATCH 085/136] Create autosave when waiting (bug #1452) --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8685475a4..ba58a9c69 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -134,7 +134,7 @@ namespace MWGui void WaitDialog::startWaiting(int hoursToWait) { - if(Settings::Manager::getBool("autosave","Saves") && mSleeping) //autosaves when enabled and sleeping + if(Settings::Manager::getBool("autosave","Saves")) //autosaves when enabled MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); From b3b7d6aa9f48fb4924737b8b682219e26db5957b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 09:36:09 +0400 Subject: [PATCH 086/136] Do not make target reference unavailable on cell change (bug #3898) --- apps/openmw/mwgui/referenceinterface.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 76bb4f53f..9aaa98f19 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -20,9 +20,8 @@ namespace MWGui { MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); - // check if player has changed cell, or count of the reference has become 0 - if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) + // check if count of the reference has become 0 + if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { if (!mPtr.isEmpty()) { From 3f159960b7f430b6e8ecc6e0ac2da4d1a348ecac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 21:18:05 +0400 Subject: [PATCH 087/136] Restored pickpocket and werewolf check --- apps/openmw/mwclass/npc.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ed1f12b31..ca6c85aba 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -885,6 +885,14 @@ namespace MWClass if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing + + // Can't talk to werewolfs + if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf()) + return std::shared_ptr (new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } From 249c1ae95a6c70acd2f2b13af9a5bb863e6044f1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 13 Aug 2017 19:26:32 -0400 Subject: [PATCH 088/136] Fix orbit camera jumping back to old position --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 82eebf127..3a801ffc3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -393,6 +393,7 @@ void SceneWidget::selectNavigationMode (const std::string& mode) mCurrentCamControl->setCamera(NULL); mCurrentCamControl = mOrbitCamControl; mOrbitCamControl->setCamera(getCamera()); + mOrbitCamControl->reset(); } } From f84eb68b3d1e173b84c41618ebe21e0dbe474f9d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 10:41:37 +0400 Subject: [PATCH 089/136] Confiscate an item when you try to sell it to its owner (bug #3944) --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 6 +-- .../mwmechanics/mechanicsmanagerimp.cpp | 37 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index bd0d2ea4a..9cb004107 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -241,6 +241,8 @@ namespace MWBase virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; + + virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f82d2f68d..ca0bb48e8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -311,9 +311,9 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, - it->mBase.getClass().getValue(it->mBase) - * it->mCount, true); + + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); + onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8460a1473..b174e87cd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -907,6 +907,43 @@ namespace MWMechanics return ownerFound != owners.end(); } + void MechanicsManager::confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) + { + if (player != getPlayer()) + return; + + const std::string itemId = Misc::StringUtils::lowerCase(item.getCellRef().getRefId()); + + StolenItemsMap::iterator stolenIt = mStolenItems.find(itemId); + if (stolenIt == mStolenItems.end()) + return; + + Owner owner; + owner.first = victim.getCellRef().getRefId(); + owner.second = false; + + Misc::StringUtils::lowerCaseInPlace(owner.first); + + // decrease count of stolen items + int toRemove = std::min(count, mStolenItems[itemId][owner]); + mStolenItems[itemId][owner] -= toRemove; + if (mStolenItems[itemId][owner] == 0) + { + // erase owner from stolen items owners + OwnerMap& owners = stolenIt->second; + OwnerMap::iterator ownersIt = owners.find(owner); + if (ownersIt != owners.end()) + owners.erase(ownersIt); + } + + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + + // move items from player to owner and report about theft + victim.getClass().getContainerStore(victim).add(item, toRemove, victim); + store.remove(item, toRemove, player); + commitCrime(player, victim, OT_Theft, item.getClass().getValue(item) * toRemove); + } + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) { MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ed06f58c5..a5598252f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -206,6 +206,8 @@ namespace MWMechanics virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId); + virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); From 7a5645b35d8ae2ff3ecf15efc0eddcccfaf271aa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 18:42:19 +0400 Subject: [PATCH 090/136] Prevent followers from attacking player if crime was reported --- .../mwmechanics/mechanicsmanagerimp.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8460a1473..e5f1d73dc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1030,11 +1030,6 @@ namespace MWMechanics if (playerFollowers.find(*it) != playerFollowers.end()) continue; - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) - MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); - crimeSeen = true; } } @@ -1136,10 +1131,25 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Player's followers should not attack player, or try to arrest him + if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) + { + std::set playerFollowers; + getActorsSidingWith(player, playerFollowers); + + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + } + // Will the witness report the crime? if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) { reported = true; + + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); } if (it->getClass().isClass(*it, "guard")) @@ -1153,16 +1163,6 @@ namespace MWMechanics if (!it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) { - // Player's followers should not try to arrest player - if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) - { - std::set playerFollowers; - getActorsSidingWith(player, playerFollowers); - - if (playerFollowers.find(*it) != playerFollowers.end()) - continue; - } - it->getClass().getCreatureStats(*it).getAiSequence().stack(AiPursue(player), *it); } } From ec640341608b0b68c1fe47a1900ae4b125449d6e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 19:29:34 +0400 Subject: [PATCH 091/136] Confiscate stolen item/gem when enchanting --- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 643b69532..c7d2ef7de 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -360,8 +360,9 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, - item.getClass().getValue(item), true); + + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; From 1e983604db7c5e6ec2f1a129cf0281044b763cb5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 20:39:04 +0400 Subject: [PATCH 092/136] Dispel only effects from spells (bug #3995) --- apps/openmw/mwmechanics/activespells.cpp | 15 ++++++++++++++- apps/openmw/mwmechanics/activespells.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwmechanics/spellpriority.cpp | 8 ++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 52c05fdfa..90d29f686 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -222,10 +222,23 @@ namespace MWMechanics } } - void ActiveSpells::purgeAll(float chance) + void ActiveSpells::purgeAll(float chance, bool spellOnly) { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { + const std::string spellId = it->first; + + // if spellOnly is true, dispell only spells. Leave potions, enchanted items etc. + if (spellOnly) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(spellId); + if (!spell || spell->mData.mType != ESM::Spell::ST_Spell) + { + ++it; + continue; + } + } + if (Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 0f1f803b7..a19c8a51d 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -89,7 +89,7 @@ namespace MWMechanics void purgeEffect (short effectId, const std::string& sourceId); /// Remove all active effects, if roll succeeds (for each effect) - void purgeAll (float chance); + void purgeAll(float chance, bool spellOnly = false); /// Remove all effects with CASTER_LINKED flag that were cast by \a casterActorId void purge (int casterActorId); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ecd4ba48a..f7ee15bf4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -673,7 +673,7 @@ namespace MWMechanics } else if (target.getClass().isActor() && effectId == ESM::MagicEffect::Dispel) { - target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); + target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude, true); return true; } else if (target.getClass().isActor() && target == getPlayer()) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index a73e4fd89..0b86b9494 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -25,6 +25,14 @@ namespace const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) { + // if the effect filter is not specified, take in account only spells effects. Leave potions, enchanted items etc. + if (effectFilter == -1) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell || spell->mData.mType != ESM::Spell::ST_Spell) + continue; + } + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; for (std::vector::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt) From 67d59bead51ce4948c0e0256ee014bdab3bc8b5f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 Aug 2017 15:03:04 +0400 Subject: [PATCH 093/136] Get only text from input fields (bug #4025) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/class.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++-- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++-- apps/openmw/mwgui/textinput.cpp | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 7379f3613..95dc8cc4d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,7 +64,7 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getOnlyText()); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); switch (result) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e1f5a165e..ac61041c3 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -483,7 +483,7 @@ namespace MWGui std::string CreateClassDialog::getName() const { - return mEditName->getCaption(); + return mEditName->getOnlyText(); } std::string CreateClassDialog::getDescription() const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c7d2ef7de..5dc1f3454 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -312,7 +313,7 @@ namespace MWGui return; } - if (mName->getCaption ().empty()) + if (mName->getOnlyText().empty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -336,7 +337,7 @@ namespace MWGui return; } - mEnchanting.setNewItemName(mName->getCaption()); + mEnchanting.setNewItemName(mName->getOnlyText()); mEnchanting.setEffect(mEffectList); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index cb7c6c0d0..6391f8597 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -58,7 +58,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::TextBox* mName; + MyGUI::EditBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 84d4ca959..4d1a490aa 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -248,7 +248,7 @@ namespace MWGui dialog->eventCancelClicked.clear(); return; } - if (mSaveNameEdit->getCaption().empty()) + if (mSaveNameEdit->getOnlyText().empty()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; @@ -275,7 +275,7 @@ namespace MWGui if (mSaving) { - MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getOnlyText(), mCurrentSlot); } else { diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 354253fa4..cd2d2cd1d 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -373,7 +373,7 @@ namespace MWGui return; } - if (mNameEdit->getCaption () == "") + if (mNameEdit->getOnlyText() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -394,7 +394,7 @@ namespace MWGui return; } - mSpell.mName = mNameEdit->getCaption(); + mSpell.mName = mNameEdit->getOnlyText(); int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 958b52dc0..9ddfac612 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -53,7 +53,7 @@ namespace MWGui void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { - if (mTextEdit->getCaption() == "") + if (mTextEdit->getOnlyText() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); @@ -69,7 +69,7 @@ namespace MWGui std::string TextInputDialog::getTextInput() const { - return mTextEdit->getCaption(); + return mTextEdit->getOnlyText(); } void TextInputDialog::setTextInput(const std::string &text) From bc7353f100f1bdfbce0630da949bf25906771cde Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 Aug 2017 20:30:47 +0400 Subject: [PATCH 094/136] Check animation state for GetPCRunning and GetPCSneaking --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 ++++- apps/openmw/mwmechanics/actors.cpp | 20 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 16 +++++++++++++-- apps/openmw/mwmechanics/character.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 10 ++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwscript/controlextensions.cpp | 16 ++++++++++++--- 8 files changed, 68 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 9cb004107..2daaf9711 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -230,7 +230,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. @@ -243,6 +243,9 @@ namespace MWBase virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; + + virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; + virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00f8899de..9a23526f7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -802,6 +802,26 @@ namespace MWMechanics } } + bool Actors::isRunning(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isRunning(); + } + + bool Actors::isSneaking(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isSneaking(); + } + void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) { PtrActorMap::iterator it = mActors.find(ptr); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 362c2f126..cd949696b 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -107,6 +107,9 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + bool isRunning(const MWWorld::Ptr& ptr); + bool isSneaking(const MWWorld::Ptr& ptr); + void forceStateUpdate(const MWWorld::Ptr &ptr); bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 661df35b0..25d04d176 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1650,7 +1650,7 @@ void CharacterController::update(float duration) mSecondsOfSwimming -= 1; } } - else if(isrunning) + else if(isrunning && !sneak) { mSecondsOfRunning += duration; while(mSecondsOfRunning > 1) @@ -1688,7 +1688,7 @@ void CharacterController::update(float duration) else fatigueLoss = fFatigueSwimRunBase + encumbrance * fFatigueSwimRunMult; } - if (isrunning) + else if (isrunning) fatigueLoss = fFatigueRunBase + encumbrance * fFatigueRunMult; } } @@ -2237,6 +2237,18 @@ bool CharacterController::isSneaking() const mMovementState == CharState_SneakRight; } +bool CharacterController::isRunning() const +{ + return mMovementState == CharState_RunForward || + mMovementState == CharState_RunBack || + mMovementState == CharState_RunLeft || + mMovementState == CharState_RunRight || + mMovementState == CharState_SwimRunForward || + mMovementState == CharState_SwimRunBack || + mMovementState == CharState_SwimRunLeft || + mMovementState == CharState_SwimRunRight; +} + void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index a3cdf097d..66039bf5d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -266,6 +266,7 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; bool isSneaking() const; + bool isRunning() const; void setAttackingOrSpell(bool attackingOrSpell); void setAIAttackType(const std::string& attackType); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f4b4cec91..d182e40d7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -422,6 +422,16 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr) + { + return mActors.isRunning(ptr); + } + + bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr) + { + return mActors.isSneaking(ptr); + } + void MechanicsManager::rest(bool sleep) { mActors.rest(sleep); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index a5598252f..af0377a33 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -197,7 +197,7 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); - + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); @@ -208,6 +208,8 @@ namespace MWMechanics virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + virtual bool isRunning(const MWWorld::Ptr& ptr); + virtual bool isSneaking(const MWWorld::Ptr& ptr); private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 626fafb5a..21b3b5587 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -9,12 +9,14 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/movement.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -167,7 +169,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); + const MWWorld::Class &cls = ptr.getClass(); + + bool isRunning = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); + + runtime.push (isRunning && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); } }; @@ -177,8 +183,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Class &cls = ptr.getClass(); + + bool isSneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); + + runtime.push (isSneaking && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); } }; From d8d47f081bda51d254b25df98e126677a054f950 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 13 Aug 2017 18:05:35 +0400 Subject: [PATCH 095/136] AiFollow: add a threshold when turning to target --- apps/openmw/mwmechanics/aifollow.cpp | 48 ++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index fe94246c4..fd5f9c7fe 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -22,8 +22,15 @@ struct AiFollowStorage : AiTemporaryBase { float mTimer; bool mMoving; - - AiFollowStorage() : mTimer(0.f), mMoving(false) {} + float mTargetAngleRadians; + bool mTurnActorToTarget; + + AiFollowStorage() : + mTimer(0.f), + mMoving(false), + mTargetAngleRadians(0.f), + mTurnActorToTarget(false) + {} }; int AiFollow::mFollowIndexCounter = 0; @@ -73,6 +80,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte AiFollowStorage& storage = state.get(); + bool& rotate = storage.mTurnActorToTarget; + if (rotate) + { + if (zTurn(actor, storage.mTargetAngleRadians)) + rotate = false; + + return false; + } + // AiFollow requires the target to be in range and within sight for the initial activation if (!mActive) { @@ -144,13 +160,33 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target destination from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; - if (!storage.mMoving) - { - const short threshold = 10; // to avoid constant switching between moving/stopping + short baseFollowDistance = followDistance; + short threshold = 30; // to avoid constant switching between moving/stopping + if (storage.mMoving) + followDistance -= threshold; + else followDistance += threshold; + + osg::Vec3f targetPos(target.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + + osg::Vec3f dir = targetPos - actorPos; + float targetDistSqr = dir.length2(); + + if (targetDistSqr <= followDistance * followDistance) + { + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + + if (!zTurn(actor, faceAngleRadians, osg::DegreesToRadians(45.f))) + { + storage.mTargetAngleRadians = faceAngleRadians; + storage.mTurnActorToTarget = true; + } + + return false; } - storage.mMoving = !pathTo(actor, dest, duration, followDistance); // Go to the destination + storage.mMoving = !pathTo(actor, dest, duration, baseFollowDistance); // Go to the destination if (storage.mMoving) { From 6c8c883dc07bd98df19fdbb6e6d5369b5631600f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 18 Aug 2017 00:47:28 +0300 Subject: [PATCH 096/136] Making knownEffect aware that there can be more than 4 potion effects --- apps/openmw/mwmechanics/alchemy.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index e6e3b4c4e..124468641 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -457,7 +457,9 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW static const float fWortChanceValue = MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) - || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2); + || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2) + || (potionEffectIndex <= 5 && alchemySkill >= fWortChanceValue*3) + || (potionEffectIndex <= 7 && alchemySkill >= fWortChanceValue*4); } MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) From 641a6cd842d0d39b597ecb1d5a5770e2cd0f0904 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 11:58:28 +0400 Subject: [PATCH 097/136] Added a delay before summoned creature corpse despawning --- apps/openmw/mwmechanics/actors.cpp | 8 +++- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/summoning.cpp | 53 ++++++++++++++------------- apps/openmw/mwmechanics/summoning.hpp | 2 +- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 431ad09b3..e701336fe 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -781,7 +781,7 @@ namespace MWMechanics creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures); if (ptr.getClass().hasInventoryStore(ptr)) ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures); - updateSummonedCreatures.process(); + updateSummonedCreatures.process(mTimerDisposeSummonsCorpses == 0.f); } } @@ -1009,7 +1009,9 @@ namespace MWMechanics } } - Actors::Actors() {} + Actors::Actors() { + mTimerDisposeSummonsCorpses = 0.2f; // We should add a delay between summoned creature death and its corpse despawning + } Actors::~Actors() { @@ -1078,6 +1080,7 @@ namespace MWMechanics // target lists get updated once every 1.0 sec if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0; + if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0; if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0; MWWorld::Ptr player = getPlayer(); @@ -1182,6 +1185,7 @@ namespace MWMechanics timerUpdateAITargets += duration; timerUpdateHeadTrack += duration; timerUpdateEquippedLight += duration; + mTimerDisposeSummonsCorpses += duration; // Looping magic VFX update // Note: we need to do this before any of the animations are updated. diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 362c2f126..8228284a7 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -150,6 +150,7 @@ namespace MWMechanics private: PtrActorMap mActors; + float mTimerDisposeSummonsCorpses; }; } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index e4a825efc..fad7bc96d 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -38,26 +38,10 @@ namespace MWMechanics } } - void UpdateSummonedCreatures::process() + void UpdateSummonedCreatures::process(bool cleanup) { - - MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); - - // Update summon effects std::map& creatureMap = creatureStats.getSummonedCreatureMap(); - for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) - { - bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); - if (!found) - { - // Effect has ended - MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); - creatureMap.erase(it++); - continue; - } - ++it; - } for (std::set >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) { @@ -101,21 +85,18 @@ namespace MWMechanics } } + // Update summon effects for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); - if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()) + bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); + if (!found) { - // Purge the magic effect so a new creature can be summoned if desired - creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); - if (mActor.getClass().hasInventoryStore(ptr)) - mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); - + // Effect has ended MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); creatureMap.erase(it++); + continue; } - else - ++it; + ++it; } std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); @@ -137,6 +118,26 @@ namespace MWMechanics else ++it; } + + if (!cleanup) + return; + + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); + if (ptr.isEmpty() || (ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished())) + { + // Purge the magic effect so a new creature can be summoned if desired + creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); + if (mActor.getClass().hasInventoryStore(mActor)) + mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); + + MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); + creatureMap.erase(it++); + } + else + ++it; + } } } diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b2a3c60ea..9329dcb83 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -22,7 +22,7 @@ namespace MWMechanics float magnitude, float remainingTime = -1, float totalTime = -1); /// To call after all effect sources have been visited - void process(); + void process(bool cleanup); private: MWWorld::Ptr mActor; From 7c80ddc9de385996c9e331aaffe433c330a56f62 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 17:06:47 +0400 Subject: [PATCH 098/136] Owned crosshair improvements (bug #2789) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++- apps/openmw/mwclass/activator.cpp | 5 +++++ apps/openmw/mwclass/activator.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 5 +++++ apps/openmw/mwclass/door.hpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 3 +-- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++++++++++++---- .../openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/class.hpp | 8 ++++++++ 9 files changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2daaf9711..f5013a8f3 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -7,6 +7,8 @@ #include #include +#include "../mwworld/ptr.hpp" + namespace osg { class Vec3f; @@ -231,7 +233,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 4910ab932..8df262f24 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -51,6 +51,11 @@ namespace MWClass return ""; } + bool Activator::isActivator() const + { + return true; + } + bool Activator::useAnim() const { return true; diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 21afa7b8e..3f333f4cb 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -42,6 +42,8 @@ namespace MWClass virtual bool useAnim() const; ///< Whether or not to use animated variant of model (default false) + + virtual bool isActivator() const; }; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3801cd261..07e6cc9db 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -76,6 +76,11 @@ namespace MWClass } } + bool Door::isDoor() const + { + return true; + } + bool Door::useAnim() const { return true; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index a2d129522..57e475382 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -20,6 +20,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + virtual bool isDoor() const; + virtual bool useAnim() const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 81a3d864c..9b89c3957 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -359,12 +359,11 @@ namespace MWGui { if(!mFocusObject.isEmpty()) { - const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWWorld::Ptr victim; MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); + bool allowed = mm->isAllowedToUse(ptr, mFocusObject, victim); return !allowed; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d182e40d7..68115301f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/ptr.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -829,8 +830,17 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) { + const MWWorld::CellRef& cellref = item.getCellRef(); + // there is no harm to use unlocked doors + if (item.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) + return true; + + // TODO: implement a better check to check if item is owned bed + if (item.getClass().isActivator() && item.getClass().getScript(item).compare(0, 3, "Bed") != 0) + return true; + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; @@ -872,7 +882,7 @@ namespace MWMechanics } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed.getCellRef(), victim)) + if (isAllowedToUse(ptr, bed, victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -887,7 +897,7 @@ namespace MWMechanics void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item.getCellRef(), victim)) + if (isAllowedToUse(ptr, item, victim)) return; commitCrime(ptr, victim, OT_Trespassing); } @@ -1007,7 +1017,7 @@ namespace MWMechanics } } - if (isAllowedToUse(ptr, *ownerCellRef, victim)) + if (isAllowedToUse(ptr, item, victim)) return; Owner owner; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af0377a33..bba2c55d6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -199,7 +199,7 @@ namespace MWMechanics virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim); virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 42d57ffab..097ec0faa 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -301,6 +301,10 @@ namespace MWWorld virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const; + virtual bool isActivator() const { + return false; + } + virtual bool isActor() const { return false; } @@ -309,6 +313,10 @@ namespace MWWorld return false; } + virtual bool isDoor() const { + return false; + } + virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; From d31ed83b54383fbb669297e094c3fc66a740305f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 03:43:31 -0400 Subject: [PATCH 099/136] Preliminary asset reloading --- apps/opencs/model/doc/document.cpp | 4 +-- apps/opencs/model/doc/document.hpp | 6 ++-- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 4 +-- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/data.cpp | 33 +++++++++++++++++++- apps/opencs/model/world/data.hpp | 6 ++-- apps/opencs/model/world/resources.cpp | 8 +++++ apps/opencs/model/world/resources.hpp | 2 ++ apps/opencs/model/world/resourcesmanager.cpp | 19 +++++++++-- apps/opencs/model/world/resourcesmanager.hpp | 8 +++-- apps/opencs/model/world/resourcetable.cpp | 10 ++++++ apps/opencs/model/world/resourcetable.hpp | 7 ++++- apps/opencs/view/doc/view.cpp | 8 +++++ components/vfs/archive.hpp | 3 ++ components/vfs/filesystemarchive.cpp | 6 ++++ components/vfs/filesystemarchive.hpp | 2 ++ components/vfs/manager.cpp | 8 +++++ components/vfs/manager.hpp | 3 ++ 19 files changed, 123 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index ef984c0ca..a7809f3e3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -269,11 +269,11 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, +CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, + ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir), mTools (*this, encoding), diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 030a0174e..ad0201407 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -59,7 +59,7 @@ namespace CSMDoc private: - const VFS::Manager* mVFS; + VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -102,11 +102,11 @@ namespace CSMDoc public: - Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, + Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, + ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts); ~Document(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 098d7bad5..11378cab4 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -127,7 +127,7 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: removeDocument (document); } -void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs) +void CSMDoc::DocumentManager::setVFS(VFS::Manager *vfs) { mResourcesManager.setVFS(vfs); mVFS = vfs; diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index ed8e327d7..771afe8e5 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -41,7 +41,7 @@ namespace CSMDoc ToUTF8::FromType mEncoding; CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - const VFS::Manager* mVFS; + VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -74,7 +74,7 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - void setVFS(const VFS::Manager* vfs); + void setVFS(VFS::Manager* vfs); bool isEmpty(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c87e283a8..5c0b2e282 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -259,6 +259,7 @@ void CSMPrefs::State::declare() declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence()); declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence()); declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence()); + declareShortcut ("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5)); declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence()); declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence()); declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence()); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ee9e4329c..8c25faaa5 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "idtable.hpp" #include "idtree.hpp" @@ -61,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), mResourcesManager (resourcesManager), mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) @@ -1215,6 +1216,36 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const return ids; } +void CSMWorld::Data::assetsChanged() +{ + VFS::Manager* vfs = mResourcesManager.getVFS(); + vfs->rebuildIndex(); + + ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); + ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); + ResourceTable* musicTable = static_cast(getTableModel(UniversalId::Type_Musics)); + ResourceTable* soundResTable = static_cast(getTableModel(UniversalId::Type_SoundsRes)); + ResourceTable* texTable = static_cast(getTableModel(UniversalId::Type_Textures)); + ResourceTable* vidTable = static_cast(getTableModel(UniversalId::Type_Videos)); + + meshTable->beginReset(); + iconTable->beginReset(); + musicTable->beginReset(); + soundResTable->beginReset(); + texTable->beginReset(); + vidTable->beginReset(); + + // Trigger recreation + mResourcesManager.recreateResources(); + + meshTable->endReset(); + iconTable->endReset(); + musicTable->endReset(); + soundResTable->endReset(); + texTable->endReset(); + vidTable->endReset(); +} + void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (topLeft.column()<=0) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index f96003e44..8bc1c4271 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,7 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; - const ResourcesManager& mResourcesManager; + ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; @@ -140,7 +140,7 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); virtual ~Data(); @@ -306,6 +306,8 @@ namespace CSMWorld private slots: + void assetsChanged(); + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void rowsChanged (const QModelIndex& parent, int start, int end); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 5fe9194d7..5bf0267bb 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -12,6 +12,14 @@ CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& base const char * const *extensions) : mBaseDirectory (baseDirectory), mType (type) { + recreate(vfs, extensions); +} + +void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *extensions) +{ + mFiles.clear(); + mIndex.clear(); + int baseSize = mBaseDirectory.size(); const std::map& index = vfs->getIndex(); diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index d6998da9f..5e9872ea8 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -27,6 +27,8 @@ namespace CSMWorld Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions = 0); + void recreate(const VFS::Manager* vfs, const char * const *extensions = 0); + int getSize() const; std::string getId (int index) const; diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 016799be3..6b271c276 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -14,7 +14,7 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) +void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) { mVFS = vfs; mResources.clear(); @@ -31,11 +31,26 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } -const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +VFS::Manager* CSMWorld::ResourcesManager::getVFS() const { return mVFS; } +void CSMWorld::ResourcesManager::recreateResources() +{ + // TODO make this shared with setVFS function + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + + std::map::iterator it = mResources.begin(); + for ( ; it != mResources.end(); ++it) + { + if (it->first == UniversalId::Type_Mesh) + it->second.recreate(mVFS, sMeshTypes); + else + it->second.recreate(mVFS); + } +} + const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const { std::map::const_iterator iter = mResources.find (type); diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 1ce06f2d3..969666856 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,7 +16,7 @@ namespace CSMWorld class ResourcesManager { std::map mResources; - const VFS::Manager* mVFS; + VFS::Manager* mVFS; private: @@ -26,9 +26,11 @@ namespace CSMWorld ResourcesManager(); - const VFS::Manager* getVFS() const; + VFS::Manager* getVFS() const; - void setVFS(const VFS::Manager* vfs); + void setVFS(VFS::Manager* vfs); + + void recreateResources(); const Resources& get (UniversalId::Type type) const; }; diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 5227ec3e6..f55f87873 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -154,3 +154,13 @@ int CSMWorld::ResourceTable::getColumnId (int column) const return -1; } + +void CSMWorld::ResourceTable::beginReset() +{ + beginResetModel(); +} + +void CSMWorld::ResourceTable::endReset() +{ + endResetModel(); +} diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp index 88dcc24b0..7d538df53 100644 --- a/apps/opencs/model/world/resourcetable.hpp +++ b/apps/opencs/model/world/resourcetable.hpp @@ -52,7 +52,12 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; - virtual int getColumnId (int column) const; + virtual int getColumnId (int column) const; + + /// Signal Qt that the data is about to change. + void beginReset(); + /// Signal Qt that the data has been changed. + void endReset(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ff49a90fd..92ed07daf 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -284,6 +284,13 @@ void CSVDoc::View::setupAssetsMenu() { QMenu *assets = menuBar()->addMenu (tr ("Assets")); + QAction *reload = new QAction (tr ("Reload"), this); + connect (reload, SIGNAL (triggered()), &mDocument->getData(), SLOT (assetsChanged())); + setupShortcut("document-assets-reload", reload); + assets->addAction (reload); + + assets->addSeparator(); + QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); setupShortcut("document-assets-sounds", sounds); @@ -889,6 +896,7 @@ void CSVDoc::View::addMetaDataSubView() addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); } + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index b36c7117b..9bdf12c23 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,6 +21,9 @@ namespace VFS public: virtual ~Archive() {} + /// Clears cached data for archives that may change. + virtual void resetIfNotStatic(){}; + /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index ad5150a44..9240909ad 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,6 +12,12 @@ namespace VFS } + void FileSystemArchive::resetIfNotStatic() + { + mIndex.clear(); + mBuiltIndex = false; + } + void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 6c8e1b82b..16c2d65ea 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,6 +23,8 @@ namespace VFS public: FileSystemArchive(const std::string& path); + virtual void resetIfNotStatic(); + virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 457947d40..037fef325 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -57,6 +57,14 @@ namespace VFS (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); } + void Manager::rebuildIndex() + { + for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) + (*it)->resetIfNotStatic(); + + buildIndex(); + } + Files::IStreamPtr Manager::get(const std::string &name) const { std::string normalized = name; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 6592a65a8..2ad7cf643 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -33,6 +33,9 @@ namespace VFS /// Build the file index. Should be called when all archives have been registered. void buildIndex(); + /// Rebuild the file index. New/deleted files (actual files, not bsa's) will be reflected. + void rebuildIndex(); + /// Does a file with this name exist? /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; From e0bb9c089bcc7459de77609a9d2c2df0245a0b39 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 19 Aug 2017 14:31:25 +0400 Subject: [PATCH 100/136] Revert commit 67d59bead51ce4948c0e0256ee014bdab3bc8b5f (a better implementation found) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/class.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 ++--- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++-- apps/openmw/mwgui/textinput.cpp | 4 ++-- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 95dc8cc4d..7379f3613 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,7 +64,7 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getOnlyText()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); switch (result) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index ac61041c3..e1f5a165e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -483,7 +483,7 @@ namespace MWGui std::string CreateClassDialog::getName() const { - return mEditName->getOnlyText(); + return mEditName->getCaption(); } std::string CreateClassDialog::getDescription() const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5dc1f3454..c7d2ef7de 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -313,7 +312,7 @@ namespace MWGui return; } - if (mName->getOnlyText().empty()) + if (mName->getCaption ().empty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -337,7 +336,7 @@ namespace MWGui return; } - mEnchanting.setNewItemName(mName->getOnlyText()); + mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 6391f8597..cb7c6c0d0 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -58,7 +58,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::EditBox* mName; + MyGUI::TextBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4d1a490aa..84d4ca959 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -248,7 +248,7 @@ namespace MWGui dialog->eventCancelClicked.clear(); return; } - if (mSaveNameEdit->getOnlyText().empty()) + if (mSaveNameEdit->getCaption().empty()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; @@ -275,7 +275,7 @@ namespace MWGui if (mSaving) { - MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getOnlyText(), mCurrentSlot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); } else { diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index cd2d2cd1d..354253fa4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -373,7 +373,7 @@ namespace MWGui return; } - if (mNameEdit->getOnlyText() == "") + if (mNameEdit->getCaption () == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -394,7 +394,7 @@ namespace MWGui return; } - mSpell.mName = mNameEdit->getOnlyText(); + mSpell.mName = mNameEdit->getCaption(); int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 9ddfac612..958b52dc0 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -53,7 +53,7 @@ namespace MWGui void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { - if (mTextEdit->getOnlyText() == "") + if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); @@ -69,7 +69,7 @@ namespace MWGui std::string TextInputDialog::getTextInput() const { - return mTextEdit->getOnlyText(); + return mTextEdit->getCaption(); } void TextInputDialog::setTextInput(const std::string &text) From 65d05ee1cd5abe81456537fa75b6b326c1de9370 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 19 Aug 2017 14:30:04 +0400 Subject: [PATCH 101/136] Get only text from clipboard (bug #4025) --- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..e4f6eafde 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1983,12 +1983,8 @@ namespace MWGui char* text=0; text = SDL_GetClipboardText(); if (text) - { - // MyGUI's clipboard might still have color information, to retain that information, only set the new text - // if it actually changed (clipboard inserted by an external application) - if (MyGUI::TextIterator::getOnlyText(_data) != text) - _data = text; - } + _data = MyGUI::TextIterator::toTagsString(text); + SDL_free(text); } From f3361ed085ba47d4e33f10dffe1c9674998a7263 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 19 Aug 2017 18:28:40 +0100 Subject: [PATCH 102/136] Add an EditorConfig file --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..25cc3fffc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*.cpp] +indent_style = space +indent_size = 4 +insert_final_newline = true + +[*.hpp] +indent_style = space +indent_size = 4 +insert_final_newline = true \ No newline at end of file From 91597af051d012df6897c9afaf7170e4f70366b2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 19 Aug 2017 18:48:29 +0100 Subject: [PATCH 103/136] Add VS2017 aps files to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ca2c6502e..9fbb82dba 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ Doxygen .settings .directory .idea +files/windows/*.aps ## qt-creator CMakeLists.txt.user* From 2a85c5f011ad4381460d8ded00cdec6052b4f99b Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 19 Aug 2017 14:48:00 -0400 Subject: [PATCH 104/136] Implement a Fisher-Yates shuffle on background music This fixes sometimes getting repetitive background music --- apps/openmw/mwsound/soundmanagerimp.cpp | 26 ++++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c6f663059..1cba2e13a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -271,7 +271,6 @@ namespace MWSound return sound; } - // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -298,7 +297,6 @@ namespace MWSound return volume; } - void SoundManager::stopMusic() { if(mMusic) @@ -367,7 +365,9 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - + mMusicToPlay.reserve(mMusicToPlay.size() + filelist.size()); + for(int it = 0; it < filelist.size(); it++) + mMusicToPlay.push_back(it); } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,15 +375,23 @@ namespace MWSound if(filelist.empty()) return; - int i = Misc::Rng::rollDice(filelist.size()); - - // Don't play the same music track twice in a row - if (filelist[i] == mLastPlayedMusic) + // Do a Fisher-Yates shuffle + if(mMusicFiles.size() == 0) { - i = (i+1) % filelist.size(); + mMusicToPlay.reserve(filelist.size()); + for (int it = 0; it < filelist.size(); it++) + mMusicToPlay.push_back(it); } - advanceMusic(filelist[i]); + int i = Misc::Rng::rollDice(mMusicToPlay.size()); + + // Fix last played music being the same after another shuffle + if(filelist[mMusicToPlay[i]] == mLastPlayedMusic) + i = (i+1) % mMusicToPlay.size(); + + advanceMusic(filelist[mMusicToPlay[i]]); + mMusicToPlay[i] = mMusicToPlay.back(); + mMusicToPlay.pop_back(); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d911d4be..46a03818b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,6 +49,7 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; + std::vector mMusicToPlay; // The list of music files not played yet std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From 742bd00ec6e7b1802f8bf8a78d76a400885f0b25 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 15:26:46 -0400 Subject: [PATCH 105/136] Clear cached resources --- apps/opencs/model/world/data.cpp | 3 +++ components/resource/resourcemanager.cpp | 5 +++++ components/resource/resourcemanager.hpp | 3 +++ components/resource/resourcesystem.cpp | 10 ++++++++++ components/resource/resourcesystem.hpp | 3 +++ 5 files changed, 24 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8c25faaa5..633b1ae20 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1244,6 +1244,9 @@ void CSMWorld::Data::assetsChanged() soundResTable->endReset(); texTable->endReset(); vidTable->endReset(); + + // Get rid of potentially old cached assets + mResourceSystem->clearCache(); } void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index d19d9cf80..4e48d9745 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -23,6 +23,11 @@ namespace Resource mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); } + void ResourceManager::clearCache() + { + mCache->clear(); + } + void ResourceManager::setExpiryDelay(double expiryDelay) { mExpiryDelay = expiryDelay; diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 61599cd5e..58200993b 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -28,6 +28,9 @@ namespace Resource /// Clear cache entries that have not been referenced for longer than expiryDelay. virtual void updateCache(double referenceTime); + /// Clear all cache entries. + virtual void clearCache(); + /// How long to keep objects in cache after no longer being referenced. void setExpiryDelay (double expiryDelay); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 8d05a1b4e..a9686e5db 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,6 +2,8 @@ #include +#include + #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" @@ -68,6 +70,14 @@ namespace Resource (*it)->updateCache(referenceTime); } + void ResourceSystem::clearCache() + { + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->clearCache(); + + osgDB::Registry::instance()->clearObjectCache(); + } + void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) { mResourceManagers.push_back(resourceMgr); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index dc608b875..ef9ac9647 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -41,6 +41,9 @@ namespace Resource /// @note May be called from any thread if you do not add or remove resource managers at that point. void updateCache(double referenceTime); + /// Indicates to each resource manager to clear the entire cache. + void clearCache(); + /// Add this ResourceManager to be handled by the ResourceSystem. /// @note Does not transfer ownership. void addResourceManager(ResourceManager* resourceMgr); From 5950b26912893b40333586c32e49c737a232d148 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 19:36:45 -0400 Subject: [PATCH 106/136] Update scene assets --- apps/opencs/model/world/data.cpp | 2 ++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/view/render/cell.cpp | 9 +++++++++ apps/opencs/view/render/cell.hpp | 2 ++ apps/opencs/view/render/object.cpp | 6 ++++++ apps/opencs/view/render/object.hpp | 3 +++ apps/opencs/view/render/pagedworldspacewidget.cpp | 14 +++++++++++++- apps/opencs/view/render/pagedworldspacewidget.hpp | 4 +++- apps/opencs/view/render/previewwidget.cpp | 8 ++++++++ apps/opencs/view/render/previewwidget.hpp | 2 ++ .../opencs/view/render/unpagedworldspacewidget.cpp | 9 +++++++++ .../opencs/view/render/unpagedworldspacewidget.hpp | 2 ++ components/resource/resourcesystem.cpp | 2 -- 13 files changed, 61 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 633b1ae20..61db4ff77 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1247,6 +1247,8 @@ void CSMWorld::Data::assetsChanged() // Get rid of potentially old cached assets mResourceSystem->clearCache(); + + emit assetTablesChanged(); } void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8bc1c4271..8fe5eeff9 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -304,6 +304,8 @@ namespace CSMWorld void idListChanged(); + void assetTablesChanged(); + private slots: void assetsChanged(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 48156359f..4b06432d6 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -283,6 +283,15 @@ void CSVRender::Cell::pathgridRemoved() mPathgrid->removeGeometry(); } +void CSVRender::Cell::reloadAssets() +{ + for (std::map::const_iterator iter (mObjects.begin()); + iter != mObjects.end(); ++iter) + { + iter->second->reloadAssets(); + } +} + void CSVRender::Cell::setSelection (int elementMask, Selection mode) { if (elementMask & Mask_Reference) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index ca82dd580..f53f61973 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -118,6 +118,8 @@ namespace CSVRender void pathgridRemoved(); + void reloadAssets(); + void setSelection (int elementMask, Selection mode); // Select everything that references the same ID as at least one of the elements diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index eb90e9db3..522057097 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -532,6 +532,12 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, return false; } +void CSVRender::Object::reloadAssets() +{ + update(); + updateMarker(); +} + std::string CSVRender::Object::getReferenceId() const { return mReferenceId; diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e28e2562c..e14697e62 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -151,6 +151,9 @@ namespace CSVRender /// this object? bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + /// Reloads the underlying asset + void reloadAssets(); + /// Returns an empty string if this is a refereceable-type object. std::string getReferenceId() const; diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b5497558a..b1077139c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -472,6 +472,9 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); + connect (&document.getData(), SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + // Shortcuts CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); @@ -520,7 +523,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) // Loop through all the coordinates to add them to selection while (stream >> ignore1 >> ignore2 >> x >> y) selection.add (CSMWorld::CellCoordinates (x, y)); - + // Mark that camera needs setup mCamPositionSet=false; } @@ -763,6 +766,15 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int flagAsModified(); } +void CSVRender::PagedWorldspaceWidget::assetTablesChanged() +{ + std::map::iterator iter = mCells.begin(); + for ( ; iter != mCells.end(); ++iter) + { + iter->second->reloadAssets(); + } +} + void CSVRender::PagedWorldspaceWidget::loadCameraCell() { addCellToSceneFromCamera(0, 0); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 0663d3424..8c41df51e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -84,7 +84,7 @@ namespace CSVRender /// hint system. virtual ~PagedWorldspaceWidget(); - + /// Decodes the the hint string to set of cell that are rendered. void useViewHint (const std::string& hint); @@ -155,6 +155,8 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + void assetTablesChanged (); + void loadCameraCell(); void loadEastCell(); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 2f3510317..972fb556d 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -17,6 +17,9 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int))); + connect (&mData, SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + if (!referenceable) { QAbstractItemModel *references = @@ -119,3 +122,8 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); } + +void CSVRender::PreviewWidget::assetTablesChanged () +{ + mObject.reloadAssets(); +} diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 73f7dc810..630ccf293 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -47,6 +47,8 @@ namespace CSVRender void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void assetTablesChanged (); }; } diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index b82aa45b2..3201f7303 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -47,6 +47,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int))); + connect (&document.getData(), SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + update(); mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); @@ -82,6 +85,12 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI emit closeRequest(); } +void CSVRender::UnpagedWorldspaceWidget::assetTablesChanged() +{ + if (mCell) + mCell->reloadAssets(); +} + bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector& universalIdData, DropType type) { if (WorldspaceWidget::handleDrop (universalIdData, type)) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 5283b3a97..527463990 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -108,6 +108,8 @@ namespace CSVRender void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + void assetTablesChanged (); + signals: void cellChanged(const CSMWorld::UniversalId& id); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index a9686e5db..b1061adcd 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -74,8 +74,6 @@ namespace Resource { for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->clearCache(); - - osgDB::Registry::instance()->clearObjectCache(); } void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) From 765f982123c3e13c027345c354c9e95dce907c34 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 20 Aug 2017 20:48:14 +0400 Subject: [PATCH 107/136] Removed cursor from Favorite Attributes label --- files/mygui/openmw_chargen_class.layout | 1 + files/mygui/openmw_chargen_create_class.layout | 1 + 2 files changed, 2 insertions(+) diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index 35dd57ca3..d875fae22 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -34,6 +34,7 @@ + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index 9ca6c6a31..e2920c742 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -33,6 +33,7 @@ + From 6ef5d1408f7dbec911b14c8d6f13838ae80e19b9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 20 Aug 2017 21:25:36 +0400 Subject: [PATCH 108/136] Disabled transparency for description edit fields --- files/mygui/openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_edit_note.layout | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 3d341eee5..43b0518fd 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index eb2a2789d..7039c719e 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -1,7 +1,7 @@ - + From f0dea8b8e6797bb8f4ee4cbfe2c03c988522bfa5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 20 Aug 2017 20:20:27 +0000 Subject: [PATCH 109/136] Revert "Implement a Fisher-Yates shuffle on background music" --- apps/openmw/mwsound/soundmanagerimp.cpp | 26 +++++++++---------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1cba2e13a..c6f663059 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -271,6 +271,7 @@ namespace MWSound return sound; } + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -297,6 +298,7 @@ namespace MWSound return volume; } + void SoundManager::stopMusic() { if(mMusic) @@ -365,9 +367,7 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - mMusicToPlay.reserve(mMusicToPlay.size() + filelist.size()); - for(int it = 0; it < filelist.size(); it++) - mMusicToPlay.push_back(it); + } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,23 +375,15 @@ namespace MWSound if(filelist.empty()) return; - // Do a Fisher-Yates shuffle - if(mMusicFiles.size() == 0) + int i = Misc::Rng::rollDice(filelist.size()); + + // Don't play the same music track twice in a row + if (filelist[i] == mLastPlayedMusic) { - mMusicToPlay.reserve(filelist.size()); - for (int it = 0; it < filelist.size(); it++) - mMusicToPlay.push_back(it); + i = (i+1) % filelist.size(); } - int i = Misc::Rng::rollDice(mMusicToPlay.size()); - - // Fix last played music being the same after another shuffle - if(filelist[mMusicToPlay[i]] == mLastPlayedMusic) - i = (i+1) % mMusicToPlay.size(); - - advanceMusic(filelist[mMusicToPlay[i]]); - mMusicToPlay[i] = mMusicToPlay.back(); - mMusicToPlay.pop_back(); + advanceMusic(filelist[i]); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 46a03818b..5d911d4be 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,7 +49,6 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; - std::vector mMusicToPlay; // The list of music files not played yet std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From d7744e8b16a1f4887abbc036b755d3356eada244 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:07:23 -0400 Subject: [PATCH 110/136] A bit of cleanup --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/data.cpp | 9 ++++---- apps/opencs/model/world/data.hpp | 3 ++- apps/opencs/model/world/resourcesmanager.cpp | 22 ++++++++++---------- apps/opencs/model/world/resourcesmanager.hpp | 8 ++++--- components/resource/resourcesystem.cpp | 2 -- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a7809f3e3..d9f86cdde 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -275,7 +275,7 @@ CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager const Fallback::Map* fallback, ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir), +: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, vfs, resourcesManager, fallback, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 61db4ff77..d7f42d027 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -62,9 +62,9 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mFallbackMap(fallback), + mVFS(vfs), mResourcesManager (resourcesManager), mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string()); @@ -1218,8 +1218,7 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const void CSMWorld::Data::assetsChanged() { - VFS::Manager* vfs = mResourcesManager.getVFS(); - vfs->rebuildIndex(); + mVFS->rebuildIndex(); ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); @@ -1264,7 +1263,7 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) const VFS::Manager* CSMWorld::Data::getVFS() const { - return mResourcesManager.getVFS(); + return mVFS; } const Fallback::Map* CSMWorld::Data::getFallbackMap() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8fe5eeff9..771a706b3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,6 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; + VFS::Manager* mVFS; ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; @@ -140,7 +141,7 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); virtual ~Data(); diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 6b271c276..c50b86682 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -14,16 +14,19 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) +const char * const * CSMWorld::ResourcesManager::getMeshExtensions() { - mVFS = vfs; - mResources.clear(); - // maybe we could go over the osgDB::Registry to list all supported node formats - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + return sMeshTypes; +} - addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); +void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) +{ + mVFS = vfs; + mResources.clear(); + + addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, getMeshExtensions())); addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); addResources (Resources (vfs, "music", UniversalId::Type_Music)); addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); @@ -31,21 +34,18 @@ void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } -VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const { return mVFS; } void CSMWorld::ResourcesManager::recreateResources() { - // TODO make this shared with setVFS function - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; - std::map::iterator it = mResources.begin(); for ( ; it != mResources.end(); ++it) { if (it->first == UniversalId::Type_Mesh) - it->second.recreate(mVFS, sMeshTypes); + it->second.recreate(mVFS, getMeshExtensions()); else it->second.recreate(mVFS); } diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 969666856..0e8385300 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,19 +16,21 @@ namespace CSMWorld class ResourcesManager { std::map mResources; - VFS::Manager* mVFS; + const VFS::Manager* mVFS; private: void addResources (const Resources& resources); + const char * const * getMeshExtensions(); + public: ResourcesManager(); - VFS::Manager* getVFS() const; + const VFS::Manager* getVFS() const; - void setVFS(VFS::Manager* vfs); + void setVFS(const VFS::Manager* vfs); void recreateResources(); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index b1061adcd..d7a6771c4 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,8 +2,6 @@ #include -#include - #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" From 7914fd5c9c42ea4c678a925253d495429c049248 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:36:21 -0400 Subject: [PATCH 111/136] Re-index BSAs --- components/vfs/archive.hpp | 4 ++-- components/vfs/bsaarchive.cpp | 24 ++++++++++++++++++------ components/vfs/bsaarchive.hpp | 5 +++++ components/vfs/filesystemarchive.cpp | 2 +- components/vfs/filesystemarchive.hpp | 2 +- components/vfs/manager.cpp | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index 9bdf12c23..f2082f750 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,8 +21,8 @@ namespace VFS public: virtual ~Archive() {} - /// Clears cached data for archives that may change. - virtual void resetIfNotStatic(){}; + /// Clears cached data. + virtual void reset() = 0; /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index a527a6ad9..88e6bf2c7 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -5,14 +5,15 @@ namespace VFS BsaArchive::BsaArchive(const std::string &filename) + : mFileName(filename) { - mFile.open(filename); + load(); +} - const Bsa::BSAFile::FileList &filelist = mFile.getList(); - for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) - { - mResources.push_back(BsaArchiveFile(&*it, &mFile)); - } +void BsaArchive::reset() +{ + mResources.clear(); + load(); } void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) @@ -26,6 +27,17 @@ void BsaArchive::listResources(std::map &out, char (*normal } } +void BsaArchive::load() +{ + mFile.open(mFileName); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } +} + // ------------------------------------------------------------------------------ BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index a6e274037..92204f90c 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -24,9 +24,14 @@ namespace VFS public: BsaArchive(const std::string& filename); + virtual void reset(); + virtual void listResources(std::map& out, char (*normalize_function) (char)); private: + void load(); + + std::string mFileName; Bsa::BSAFile mFile; std::vector mResources; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 9240909ad..8fb992e76 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,7 +12,7 @@ namespace VFS } - void FileSystemArchive::resetIfNotStatic() + void FileSystemArchive::reset() { mIndex.clear(); mBuiltIndex = false; diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 16c2d65ea..5843bf871 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,7 +23,7 @@ namespace VFS public: FileSystemArchive(const std::string& path); - virtual void resetIfNotStatic(); + virtual void reset(); virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 037fef325..9b1798e8f 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -60,7 +60,7 @@ namespace VFS void Manager::rebuildIndex() { for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) - (*it)->resetIfNotStatic(); + (*it)->reset(); buildIndex(); } From b62cb0e2a47d5252d686ee2770ddc6fb6711a194 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:55:16 -0400 Subject: [PATCH 112/136] Clear out GPU texture/stateset cache --- components/resource/scenemanager.cpp | 16 ++++++++++++++++ components/resource/scenemanager.hpp | 2 ++ 2 files changed, 18 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 226933760..2f04aa7c2 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -122,6 +122,13 @@ namespace Resource { return _sharedStateSetList.size(); } + + void clearCache() + { + OpenThreads::ScopedLock lock(_listMutex); + _sharedTextureList.clear(); + _sharedStateSetList.clear(); + } }; /// Set texture filtering settings on textures contained in a FlipController. @@ -710,6 +717,15 @@ namespace Resource mSharedStateMutex.unlock(); } + void SceneManager::clearCache() + { + ResourceManager::clearCache(); + + mSharedStateMutex.lock(); + mSharedStateManager->clearCache(); + mSharedStateMutex.unlock(); + } + void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { { diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index c6ff02acf..14032df77 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -143,6 +143,8 @@ namespace Resource /// @see ResourceManager::updateCache virtual void updateCache(double referenceTime); + virtual void clearCache(); + virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; private: From d4a722067db0aeeac725ea654ab70f36a8eee968 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 20:55:56 -0400 Subject: [PATCH 113/136] Reload water --- apps/opencs/view/render/cell.cpp | 2 ++ apps/opencs/view/render/cellwater.cpp | 5 +++++ apps/opencs/view/render/cellwater.hpp | 2 ++ 3 files changed, 9 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 4b06432d6..ebc383ff2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -290,6 +290,8 @@ void CSVRender::Cell::reloadAssets() { iter->second->reloadAssets(); } + + mCellWater->reloadAssets(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 15ea15cc4..d7e8669ef 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -92,6 +92,11 @@ namespace CSVRender } } + void CellWater::reloadAssets() + { + recreate(); + } + void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { const CSMWorld::Collection& cells = mData.getCells(); diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index d2ed9b458..47e586707 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -42,6 +42,8 @@ namespace CSVRender void updateCellData(const CSMWorld::Record& cellRecord); + void reloadAssets(); + private slots: void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); From 3b9326d238f0dd2da0afd47e0a96dda8aa401e0b Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 22:34:41 -0400 Subject: [PATCH 114/136] Clear terrain cache and reload terrain --- apps/opencs/view/render/cell.cpp | 7 +++++++ components/terrain/buffercache.cpp | 12 ++++++++++++ components/terrain/buffercache.hpp | 2 ++ components/terrain/chunkmanager.cpp | 7 +++++++ components/terrain/chunkmanager.hpp | 2 ++ components/terrain/world.cpp | 6 ++++++ components/terrain/world.hpp | 3 +++ 7 files changed, 39 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ebc383ff2..5aa534232 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -291,6 +291,13 @@ void CSVRender::Cell::reloadAssets() iter->second->reloadAssets(); } + if (mTerrain) + { + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + mTerrain->clearCache(); + mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); + } + mCellWater->reloadAssets(); } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 470655539..361dd6c04 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -231,4 +231,16 @@ namespace Terrain return buffer; } + void BufferCache::clearCache() + { + { + OpenThreads::ScopedLock lock(mIndexBufferMutex); + mIndexBufferMap.clear(); + } + { + OpenThreads::ScopedLock lock(mUvBufferMutex); + mUvBufferMap.clear(); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index e8963354b..bfdf558bc 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -22,6 +22,8 @@ namespace Terrain /// @note Thread safe. osg::ref_ptr getUVBuffer(unsigned int numVerts); + void clearCache(); + // TODO: add releaseGLObjects() for our vertex/element buffer objects private: diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index e4a7c2d68..ea71c726f 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -55,6 +55,13 @@ void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) cons stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize()); } +void ChunkManager::clearCache() +{ + ResourceManager::clearCache(); + + mBufferCache.clearCache(); +} + void ChunkManager::setCullingActive(bool active) { mCullingActive = active; diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 553e06d97..2f92fa836 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -34,6 +34,8 @@ namespace Terrain virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + virtual void clearCache(); + void setCullingActive(bool active); private: diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index b7cc0ae01..9bbb585a8 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -70,6 +70,12 @@ float World::getHeightAt(const osg::Vec3f &worldPos) return mStorage->getHeightAt(worldPos); } +void World::clearCache() +{ + mTextureManager->clearCache(); + mChunkManager->clearCache(); +} + void World::updateTextureFiltering() { mTextureManager->updateTextureFiltering(); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index d0576fbd3..2fb669494 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -67,6 +67,9 @@ namespace Terrain /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} + /// Clears cached texture and chunk data. + virtual void clearCache(); + /// Load the cell into the scene graph. /// @note Not thread safe. /// @note May be ignored by derived implementations that don't organize the terrain into cells. From 679a2847355e722bd1bd600a246985828c36f79d Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 13:33:11 -0400 Subject: [PATCH 115/136] Use scoped lock instead of directly locking/unlocking mutex --- components/resource/scenemanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 2f04aa7c2..aba1d454e 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -721,9 +721,8 @@ namespace Resource { ResourceManager::clearCache(); - mSharedStateMutex.lock(); + OpenThreads::ScopedLock lock(mSharedStateMutex); mSharedStateManager->clearCache(); - mSharedStateMutex.unlock(); } void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const From 979b0d7211ab0a8db8dd27bb7a69db3c70bf2ad3 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 18:58:38 -0400 Subject: [PATCH 116/136] Code cleanup and more cache clearing --- apps/opencs/model/world/data.cpp | 40 ++++++++++++---------- apps/opencs/view/doc/view.cpp | 1 - apps/opencs/view/render/cell.cpp | 1 - components/resource/bulletshapemanager.cpp | 7 ++++ components/resource/bulletshapemanager.hpp | 2 ++ components/resource/multiobjectcache.cpp | 6 ++++ components/resource/multiobjectcache.hpp | 3 ++ components/resource/resourcesystem.hpp | 1 + components/resource/scenemanager.cpp | 1 + components/terrain/world.cpp | 6 ---- components/terrain/world.hpp | 3 -- 11 files changed, 41 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d7f42d027..39c0291fc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1220,29 +1220,31 @@ void CSMWorld::Data::assetsChanged() { mVFS->rebuildIndex(); - ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); - ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); - ResourceTable* musicTable = static_cast(getTableModel(UniversalId::Type_Musics)); - ResourceTable* soundResTable = static_cast(getTableModel(UniversalId::Type_SoundsRes)); - ResourceTable* texTable = static_cast(getTableModel(UniversalId::Type_Textures)); - ResourceTable* vidTable = static_cast(getTableModel(UniversalId::Type_Videos)); - - meshTable->beginReset(); - iconTable->beginReset(); - musicTable->beginReset(); - soundResTable->beginReset(); - texTable->beginReset(); - vidTable->beginReset(); + const UniversalId assetTableIds[] = { + UniversalId::Type_Meshes, + UniversalId::Type_Icons, + UniversalId::Type_Musics, + UniversalId::Type_SoundsRes, + UniversalId::Type_Textures, + UniversalId::Type_Videos + }; + + size_t numAssetTables = sizeof(assetTableIds) / sizeof(UniversalId); + + for (size_t i = 0; i < numAssetTables; ++i) + { + ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); + table->beginReset(); + } // Trigger recreation mResourcesManager.recreateResources(); - meshTable->endReset(); - iconTable->endReset(); - musicTable->endReset(); - soundResTable->endReset(); - texTable->endReset(); - vidTable->endReset(); + for (size_t i = 0; i < numAssetTables; ++i) + { + ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); + table->endReset(); + } // Get rid of potentially old cached assets mResourceSystem->clearCache(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 92ed07daf..dfbeea031 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -896,7 +896,6 @@ void CSVDoc::View::addMetaDataSubView() addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); } - void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 5aa534232..a10e38397 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -294,7 +294,6 @@ void CSVRender::Cell::reloadAssets() if (mTerrain) { mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); - mTerrain->clearCache(); mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); } diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 010917572..c1a7eb8f3 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -190,6 +190,13 @@ void BulletShapeManager::updateCache(double referenceTime) mInstanceCache->removeUnreferencedObjectsInCache(); } +void BulletShapeManager::clearCache() +{ + ResourceManager::clearCache(); + + mInstanceCache->clear(); +} + void BulletShapeManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { stats->setAttribute(frameNumber, "Shape", mCache->getCacheSize()); diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index fec7251ac..8ae2b531f 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -42,6 +42,8 @@ namespace Resource /// @see ResourceManager::updateCache virtual void updateCache(double referenceTime); + virtual void clearCache(); + void reportStats(unsigned int frameNumber, osg::Stats *stats) const; private: diff --git a/components/resource/multiobjectcache.cpp b/components/resource/multiobjectcache.cpp index fcda455cc..266139f3c 100644 --- a/components/resource/multiobjectcache.cpp +++ b/components/resource/multiobjectcache.cpp @@ -43,6 +43,12 @@ namespace Resource objectsToRemove.clear(); } + void MultiObjectCache::clear() + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); + } + void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) { OpenThreads::ScopedLock lock(_objectCacheMutex); diff --git a/components/resource/multiobjectcache.hpp b/components/resource/multiobjectcache.hpp index a314a9e4b..527247bf9 100644 --- a/components/resource/multiobjectcache.hpp +++ b/components/resource/multiobjectcache.hpp @@ -25,6 +25,9 @@ namespace Resource void removeUnreferencedObjectsInCache(); + /** Remove all objects from the cache. */ + void clear(); + void addEntryToObjectCache(const std::string& filename, osg::Object* object); /** Take an Object from cache. Return NULL if no object found. */ diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index ef9ac9647..efce50b97 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -42,6 +42,7 @@ namespace Resource void updateCache(double referenceTime); /// Indicates to each resource manager to clear the entire cache. + /// @note May be called from any thread if you do not add or remove resource managers at that point. void clearCache(); /// Add this ResourceManager to be handled by the ResourceSystem. diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index aba1d454e..69a54bf17 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -723,6 +723,7 @@ namespace Resource OpenThreads::ScopedLock lock(mSharedStateMutex); mSharedStateManager->clearCache(); + mInstanceCache->clear(); } void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 9bbb585a8..b7cc0ae01 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -70,12 +70,6 @@ float World::getHeightAt(const osg::Vec3f &worldPos) return mStorage->getHeightAt(worldPos); } -void World::clearCache() -{ - mTextureManager->clearCache(); - mChunkManager->clearCache(); -} - void World::updateTextureFiltering() { mTextureManager->updateTextureFiltering(); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 2fb669494..d0576fbd3 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -67,9 +67,6 @@ namespace Terrain /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} - /// Clears cached texture and chunk data. - virtual void clearCache(); - /// Load the cell into the scene graph. /// @note Not thread safe. /// @note May be ignored by derived implementations that don't organize the terrain into cells. From 8c4b12a6035588e1e9dfdcc2d4475ac6babd57e8 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 22:31:19 -0400 Subject: [PATCH 117/136] VFS changes, one VFS and resource system per document. Added ability to reset a VFS::Manager. Removed ability to rebuild the index for a VFS::Manager. Moved VFS creation to CSM::Data. --- apps/opencs/editor.cpp | 9 +-------- apps/opencs/editor.hpp | 10 ---------- apps/opencs/model/doc/document.cpp | 16 ++++++---------- apps/opencs/model/doc/document.hpp | 12 +++++------- apps/opencs/model/doc/documentmanager.cpp | 11 ++++++----- apps/opencs/model/doc/documentmanager.hpp | 20 ++++++++++---------- apps/opencs/model/world/data.cpp | 19 ++++++++++++++----- apps/opencs/model/world/data.hpp | 13 ++++++++++--- components/vfs/archive.hpp | 3 --- components/vfs/bsaarchive.cpp | 6 ------ components/vfs/bsaarchive.hpp | 2 -- components/vfs/filesystemarchive.cpp | 6 ------ components/vfs/filesystemarchive.hpp | 2 -- components/vfs/manager.cpp | 14 ++++++-------- components/vfs/manager.hpp | 6 +++--- 15 files changed, 61 insertions(+), 88 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 54e323956..86c87962d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -5,9 +5,6 @@ #include #include -#include -#include - #include #include @@ -33,11 +30,7 @@ CS::Editor::Editor () NifOsg::Loader::setShowMarkers(true); - mVFS.reset(new VFS::Manager(mFsStrict)); - - VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true); - - mDocumentManager.setVFS(mVFS.get()); + mDocumentManager.setFileData(mFsStrict, config.first, config.second); mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index ff670ba1b..b60f5c6a8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,8 +1,6 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H -#include - #include #include @@ -30,11 +28,6 @@ #include "view/tools/merge.hpp" -namespace VFS -{ - class Manager; -} - namespace CSMDoc { class Document; @@ -46,9 +39,6 @@ namespace CS { Q_OBJECT - // FIXME: should be moved to document, so we can have different resources for each opened project - std::unique_ptr mVFS; - Files::ConfigurationManager mCfgMgr; CSMPrefs::State mSettingsState; CSMDoc::DocumentManager mDocumentManager; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d9f86cdde..7257b2fe3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -269,13 +269,14 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, - const std::vector< boost::filesystem::path >& files, bool new_, +CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, + const std::vector< boost::filesystem::path >& files,bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, - const std::vector& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, vfs, resourcesManager, fallback, resDir), + ToUTF8::FromType encoding, + const std::vector& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives) +: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, fallback, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), @@ -337,11 +338,6 @@ CSMDoc::Document::~Document() { } -const VFS::Manager *CSMDoc::Document::getVFS() const -{ - return mVFS; -} - QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index ad0201407..d31fd5aca 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include "../world/data.hpp" @@ -59,7 +60,6 @@ namespace CSMDoc private: - VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -102,17 +102,15 @@ namespace CSMDoc public: - Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, + Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, - const Fallback::Map* fallback, - ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, - const std::vector& blacklistedScripts); + const Fallback::Map* fallback, ToUTF8::FromType encoding, + const std::vector& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives); ~Document(); - const VFS::Manager* getVFS() const; - QUndoStack& getUndoStack(); int getState() const; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 11378cab4..531cfd267 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -9,7 +9,7 @@ #include "document.hpp" CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) -: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL) +: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) { boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; @@ -62,7 +62,7 @@ CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_) { - return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mResourcesManager, mBlacklistedScripts); + return new Document (mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mBlacklistedScripts, mFsStrict, mDataPaths, mArchives); } void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) @@ -127,8 +127,9 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: removeDocument (document); } -void CSMDoc::DocumentManager::setVFS(VFS::Manager *vfs) +void CSMDoc::DocumentManager::setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector& archives) { - mResourcesManager.setVFS(vfs); - mVFS = vfs; + mFsStrict = strict; + mDataPaths = dataPaths; + mArchives = archives; } diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 771afe8e5..ae6d9481a 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -11,8 +11,7 @@ #include #include - -#include "../world/resourcesmanager.hpp" +#include #include "loader.hpp" @@ -39,9 +38,14 @@ namespace CSMDoc QThread mLoaderThread; Loader mLoader; ToUTF8::FromType mEncoding; - CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - VFS::Manager* mVFS; + + boost::filesystem::path mResDir; + Fallback::Map mFallbackMap; + + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector mArchives; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -74,15 +78,11 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - void setVFS(VFS::Manager* vfs); + /// Sets the file data that gets passed to newly created documents. + void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector& archives); bool isEmpty(); - private: - - boost::filesystem::path mResDir; - Fallback::Map mFallbackMap; - private slots: void documentLoaded (Document *document); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 39c0291fc..007190e4a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "idtable.hpp" #include "idtree.hpp" @@ -62,11 +63,18 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& archives, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mVFS(vfs), mResourcesManager (resourcesManager), mFallbackMap(fallback), - mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) + mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), + mFsStrict(fsStrict), mDataPaths(dataPaths), mArchives(archives) { + mVFS.reset(new VFS::Manager(mFsStrict)); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); + + mResourcesManager.setVFS(mVFS.get()); + mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); + mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string()); int index = 0; @@ -1218,7 +1226,8 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const void CSMWorld::Data::assetsChanged() { - mVFS->rebuildIndex(); + mVFS.get()->reset(); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, @@ -1265,7 +1274,7 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) const VFS::Manager* CSMWorld::Data::getVFS() const { - return mVFS; + return mVFS.get(); } const Fallback::Map* CSMWorld::Data::getFallbackMap() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 771a706b3..8a3667ea1 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -31,6 +31,7 @@ #include +#include #include #include "../doc/stage.hpp" @@ -46,6 +47,7 @@ #include "infocollection.hpp" #include "nestedinfocollection.hpp" #include "pathgrid.hpp" +#include "resourcesmanager.hpp" #include "metadata.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" @@ -108,8 +110,6 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; - VFS::Manager* mVFS; - ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; @@ -120,6 +120,11 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector mArchives; + std::unique_ptr mVFS; + ResourcesManager mResourcesManager; std::shared_ptr mResourceSystem; std::vector > mReaders; @@ -141,7 +146,9 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& archives, const Fallback::Map* fallback, + const boost::filesystem::path& resDir); virtual ~Data(); diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index f2082f750..b36c7117b 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,9 +21,6 @@ namespace VFS public: virtual ~Archive() {} - /// Clears cached data. - virtual void reset() = 0; - /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index 88e6bf2c7..9b686049f 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -10,12 +10,6 @@ BsaArchive::BsaArchive(const std::string &filename) load(); } -void BsaArchive::reset() -{ - mResources.clear(); - load(); -} - void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) { for (std::vector::iterator it = mResources.begin(); it != mResources.end(); ++it) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 92204f90c..217594abd 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -24,8 +24,6 @@ namespace VFS public: BsaArchive(const std::string& filename); - virtual void reset(); - virtual void listResources(std::map& out, char (*normalize_function) (char)); private: diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 8fb992e76..ad5150a44 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,12 +12,6 @@ namespace VFS } - void FileSystemArchive::reset() - { - mIndex.clear(); - mBuiltIndex = false; - } - void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 5843bf871..6c8e1b82b 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,8 +23,6 @@ namespace VFS public: FileSystemArchive(const std::string& path); - virtual void reset(); - virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 9b1798e8f..4f3994bac 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -39,6 +39,12 @@ namespace VFS Manager::~Manager() { + reset(); + } + + void Manager::reset() + { + mIndex.clear(); for (std::vector::iterator it = mArchives.begin(); it != mArchives.end(); ++it) delete *it; mArchives.clear(); @@ -57,14 +63,6 @@ namespace VFS (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); } - void Manager::rebuildIndex() - { - for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) - (*it)->reset(); - - buildIndex(); - } - Files::IStreamPtr Manager::get(const std::string &name) const { std::string normalized = name; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 2ad7cf643..c5f0a8fec 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -26,6 +26,9 @@ namespace VFS ~Manager(); + // Empty the file index and unregister archives. + void reset(); + /// Register the given archive. All files contained in it will be added to the index on the next buildIndex() call. /// @note Takes ownership of the given pointer. void addArchive(Archive* archive); @@ -33,9 +36,6 @@ namespace VFS /// Build the file index. Should be called when all archives have been registered. void buildIndex(); - /// Rebuild the file index. New/deleted files (actual files, not bsa's) will be reflected. - void rebuildIndex(); - /// Does a file with this name exist? /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; From e799cbdb51c2a3d0a74df24951eb59405a3a9740 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 22 Aug 2017 09:18:49 +0400 Subject: [PATCH 118/136] Combat AI: allow only one summoned creature at time --- apps/openmw/mwmechanics/spellpriority.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 9c57a2a7f..3a730fbeb 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -496,6 +496,15 @@ namespace MWMechanics break; } + // Allow only one summoned creature at time + if (isSummoningEffect(effect.mEffectID)) + { + MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); + + if (!creatureStats.getSummonedCreatureMap().empty()) + return 0.f; + } + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); // Underwater casting not possible From d3d04171f9f1c80cfce59ed99a3e66da8fa57770 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 22 Aug 2017 15:06:56 -0400 Subject: [PATCH 119/136] Fix seg fault, undo changes BsaArchive --- apps/opencs/view/render/cell.cpp | 3 ++- components/vfs/bsaarchive.cpp | 20 +++++++------------- components/vfs/bsaarchive.hpp | 3 --- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a10e38397..153de773c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -297,7 +297,8 @@ void CSVRender::Cell::reloadAssets() mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); } - mCellWater->reloadAssets(); + if (mCellWater) + mCellWater->reloadAssets(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index 9b686049f..a527a6ad9 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -5,9 +5,14 @@ namespace VFS BsaArchive::BsaArchive(const std::string &filename) - : mFileName(filename) { - load(); + mFile.open(filename); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } } void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) @@ -21,17 +26,6 @@ void BsaArchive::listResources(std::map &out, char (*normal } } -void BsaArchive::load() -{ - mFile.open(mFileName); - - const Bsa::BSAFile::FileList &filelist = mFile.getList(); - for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) - { - mResources.push_back(BsaArchiveFile(&*it, &mFile)); - } -} - // ------------------------------------------------------------------------------ BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 217594abd..a6e274037 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -27,9 +27,6 @@ namespace VFS virtual void listResources(std::map& out, char (*normalize_function) (char)); private: - void load(); - - std::string mFileName; Bsa::BSAFile mFile; std::vector mResources; From 0177fe6602f5550538be170ce18a09fd8bb90eae Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 22 Aug 2017 23:08:06 +0400 Subject: [PATCH 120/136] Display large entries in journal correctly --- apps/openmw/mwgui/bookpage.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 20d3448b5..137594076 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -435,9 +435,15 @@ struct TypesetBookImpl::Typesetter : BookTypesetter } else { + // The section won't completely fit on the current page. Finish the current page and start a new one. + mBook->mPages.push_back (Page (curPageStart, curPageStop)); + + curPageStart = i->mRect.top; + curPageStop = i->mRect.bottom; + //split section int sectionHeightLeft = sectionHeight; - while (sectionHeightLeft > mPageHeight) + while (sectionHeightLeft >= mPageHeight) { // Adjust to the top of the first line that does not fit on the current page anymore int splitPos = curPageStop; From 157ecb166ce406bed76698a1fc55b4a86506d9c6 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 23 Aug 2017 00:02:02 -0400 Subject: [PATCH 121/136] Fix wrong folder name --- apps/opencs/model/world/resourcesmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index c50b86682..62dfe53a9 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -31,7 +31,7 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "music", UniversalId::Type_Music)); addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); addResources (Resources (vfs, "textures", UniversalId::Type_Texture)); - addResources (Resources (vfs, "videos", UniversalId::Type_Video)); + addResources (Resources (vfs, "video", UniversalId::Type_Video)); } const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const From 42b948dffe39cbf80f926b144f00a587275f346f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 23 Aug 2017 11:35:26 -0400 Subject: [PATCH 122/136] Fix pathgrid segfault --- apps/opencs/view/render/cell.cpp | 12 +++++++----- apps/opencs/view/render/pathgridmode.cpp | 15 +++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 153de773c..765c5b316 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -275,12 +275,14 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int void CSVRender::Cell::pathgridModified() { - mPathgrid->recreateGeometry(); + if (mPathgrid) + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRemoved() { - mPathgrid->removeGeometry(); + if (mPathgrid) + mPathgrid->removeGeometry(); } void CSVRender::Cell::reloadAssets() @@ -320,7 +322,7 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) iter->second->setSelected (selected); } } - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) { // Only one pathgrid may be selected, so some operations will only have an effect // if the pathgrid is already focused @@ -420,7 +422,7 @@ std::vector > CSVRender::Cell::getSelection (un iter!=mObjects.end(); ++iter) if (iter->second->getSelected()) result.push_back (iter->second->getTag()); - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid->isSelected()) result.push_back(mPathgrid->getTag()); @@ -457,6 +459,6 @@ void CSVRender::Cell::reset (unsigned int elementMask) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) iter->second->reset(); - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) mPathgrid->resetIndicators(); } diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index 228b2b5e7..a9cce0200 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -72,12 +72,15 @@ namespace CSVRender } else if (Cell* cell = getWorldspaceWidget().getCell (hitResult.worldPos)) { - // Add node - QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); - QString description = "Add node"; + if (cell->getPathgrid()) + { + // Add node + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Add node"; - CSMWorld::CommandMacro macro(undoStack, description); - cell->getPathgrid()->applyPoint(macro, hitResult.worldPos); + CSMWorld::CommandMacro macro(undoStack, description); + cell->getPathgrid()->applyPoint(macro, hitResult.worldPos); + } } } @@ -205,7 +208,7 @@ namespace CSVRender WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); Cell* cell = getWorldspaceWidget().getCell(hit.worldPos); - if (cell) + if (cell && cell->getPathgrid()) { PathgridTag* tag = 0; if (hit.tag && (tag = dynamic_cast(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId) From a8576d78ad4ed809a336ea8a89e40eec0ad3585f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 24 Aug 2017 13:51:53 -0400 Subject: [PATCH 123/136] Change default topic info values --- apps/opencs/view/world/infocreator.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index f68c69094..2f1615c87 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -32,13 +32,19 @@ std::string CSVWorld::InfoCreator::getId() const void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const { - int index = - dynamic_cast (*getData().getTableModel (getCollectionId())). - findColumnIndex ( - getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ? - CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal); + CSMWorld::IdTable& table = dynamic_cast (*getData().getTableModel (getCollectionId())); - command.addValue (index, mTopic->text()); + if (getCollectionId() == CSMWorld::UniversalId::Type_TopicInfos) + { + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Topic), mTopic->text()); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Rank), -1); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Gender), -1); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_PcRank), -1); + } + else + { + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Journal), mTopic->text()); + } } CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, From 663f3088d19432278d8cad805267d948c0030b98 Mon Sep 17 00:00:00 2001 From: "Hristos N. Triantafillou" Date: Thu, 24 Aug 2017 19:50:53 -0500 Subject: [PATCH 124/136] Use "Remove Branch" instead of "Remove" in normals tutorial * Pherim over at nexusmods advised me that using "Remove" leaves stranded references at the end of the file, and that the proper way to fully remove the unwanted `NiTextureEffect` block is to use "Remove Branch". This commit clarifies that in the normal map conversion tutorial. --- docs/source/reference/modding/convert_bump_mapped_mods.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/modding/convert_bump_mapped_mods.rst b/docs/source/reference/modding/convert_bump_mapped_mods.rst index 791e77353..71ac29468 100644 --- a/docs/source/reference/modding/convert_bump_mapped_mods.rst +++ b/docs/source/reference/modding/convert_bump_mapped_mods.rst @@ -176,7 +176,7 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Open up each of the models in NifSkope and look for these certain blocks_: - NiTextureEffect - NiSourceTexture with the value that appears to be a normal map file, in this mod, they have the suffix *_nm.dds*. -#. Remove all these tags by selecting them one at a time and press right click>Block>Remove. +#. Remove all these tags by selecting them one at a time and press right click>Block>Remove Branch. (Ctrl-Del) #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. #. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. From 1578fcbec7ed6c4b7347613b01a426de2fe9cd83 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 25 Aug 2017 11:05:56 +0100 Subject: [PATCH 125/136] Escape content file names before sending them to the GUI --- apps/openmw/mwworld/contentloader.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp index 46bd7d3f9..0f2d807aa 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "components/loadinglistener/loadinglistener.hpp" @@ -24,7 +25,7 @@ struct ContentLoader virtual void load(const boost::filesystem::path& filepath, int& index) { std::cout << "Loading content file " << filepath.string() << std::endl; - mListener.setLabel(filepath.string()); + mListener.setLabel(MyGUI::TextIterator::toTagsString(filepath.string())); } protected: From 86ae2ae3953f72a8d96c7359b7bf9fd2614b2cad Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 25 Aug 2017 16:08:49 -0400 Subject: [PATCH 126/136] Improved shuffle (#1412) --- AUTHORS.md | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 25 +++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index c48647f4e..bb773c4ef 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -60,6 +60,7 @@ Programmers Gašper Sedej gugus/gus Hallfaer Tuilinn + Haoda Wang (h313) hristoast Internecine Jacob Essex (Yacoby) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c6f663059..811797369 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -271,7 +272,6 @@ namespace MWSound return sound; } - // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -298,7 +298,6 @@ namespace MWSound return volume; } - void SoundManager::stopMusic() { if(mMusic) @@ -349,6 +348,7 @@ namespace MWSound void SoundManager::startRandomTitle() { std::vector filelist; + auto &tracklist = mMusicToPlay[mCurrentPlaylist]; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { const std::map& index = mVFS->getIndex(); @@ -367,7 +367,6 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,15 +374,25 @@ namespace MWSound if(filelist.empty()) return; - int i = Misc::Rng::rollDice(filelist.size()); + // Do a Fisher-Yates shuffle - // Don't play the same music track twice in a row - if (filelist[i] == mLastPlayedMusic) + // Repopulate if playlist is empty + if(tracklist.empty()) { - i = (i+1) % filelist.size(); + tracklist.resize(filelist.size()); + std::iota(tracklist.begin(), tracklist.end(), 0); } - advanceMusic(filelist[i]); + int i = Misc::Rng::rollDice(tracklist.size()); + + // Reshuffle if last played music is the same after a repopulation + if(filelist[tracklist[i]] == mLastPlayedMusic) + i = (i+1) % tracklist.size(); + + // Remove music from list after advancing music + advanceMusic(filelist[tracklist[i]]); + tracklist[i] = tracklist.back(); + tracklist.pop_back(); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d911d4be..691e52932 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -49,6 +50,7 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; + std::unordered_map> mMusicToPlay; // A list with music files not yet played std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From 4fba157d3bd073cf5800487575077b0256162bd0 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 26 Aug 2017 19:28:23 +0000 Subject: [PATCH 127/136] Implement releaseGLObjects for cached resources --- apps/opencs/view/render/scenewidget.cpp | 4 ++-- apps/openmw/mwgui/loadingscreen.hpp | 2 -- components/resource/resourcemanager.cpp | 5 +++++ components/resource/resourcemanager.hpp | 3 +++ components/resource/resourcesystem.cpp | 6 ++++++ components/resource/resourcesystem.hpp | 4 ++++ components/resource/scenemanager.cpp | 5 +++++ components/resource/scenemanager.hpp | 2 +- components/shader/shadermanager.cpp | 9 +++++++++ components/shader/shadermanager.hpp | 1 + components/terrain/buffercache.cpp | 14 ++++++++++++++ components/terrain/buffercache.hpp | 2 +- components/terrain/chunkmanager.cpp | 6 ++++++ components/terrain/chunkmanager.hpp | 2 ++ 14 files changed, 59 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3a801ffc3..11c7f5926 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -221,8 +221,8 @@ SceneWidget::SceneWidget(std::shared_ptr resourceSyste SceneWidget::~SceneWidget() { - // Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects - mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); + // Since we're holding on to the resources past the existence of this graphics context, we'll need to manually release the created objects + mResourceSystem->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } void SceneWidget::setLighting(Lighting *lighting) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 100c17e11..1a53495a9 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -73,8 +73,6 @@ namespace MWGui std::vector mSplashScreens; - // TODO: add releaseGLObjects() for mTexture - osg::ref_ptr mTexture; std::unique_ptr mGuiTexture; diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 4e48d9745..c0e99674e 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -38,4 +38,9 @@ namespace Resource return mVFS; } + void ResourceManager::releaseGLObjects(osg::State *state) + { + mCache->releaseGLObjects(state); + } + } diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 58200993b..6031ecc01 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -11,6 +11,7 @@ namespace VFS namespace osg { class Stats; + class State; } namespace Resource @@ -38,6 +39,8 @@ namespace Resource virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const {} + virtual void releaseGLObjects(osg::State* state); + protected: const VFS::Manager* mVFS; osg::ref_ptr mCache; diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index d7a6771c4..4d61dce69 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -97,4 +97,10 @@ namespace Resource (*it)->reportStats(frameNumber, stats); } + void ResourceSystem::releaseGLObjects(osg::State *state) + { + for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->releaseGLObjects(state); + } + } diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index efce50b97..396bdb8fa 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -12,6 +12,7 @@ namespace VFS namespace osg { class Stats; + class State; } namespace Resource @@ -60,6 +61,9 @@ namespace Resource void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + /// Call releaseGLObjects for each resource manager. + void releaseGLObjects(osg::State* state); + private: std::unique_ptr mSceneManager; std::unique_ptr mImageManager; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 69a54bf17..ab801ab82 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -628,6 +628,11 @@ namespace Resource { mCache->releaseGLObjects(state); mInstanceCache->releaseGLObjects(state); + + mShaderManager->releaseGLObjects(state); + + OpenThreads::ScopedLock lock(mSharedStateMutex); + mSharedStateManager->releaseGLObjects(state); } void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 14032df77..65524f76e 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -116,7 +116,7 @@ namespace Resource /// Manually release created OpenGL objects for the given graphics context. This may be required /// in cases where multiple contexts are used over the lifetime of the application. - void releaseGLObjects(osg::State* state); + void releaseGLObjects(osg::State* state) override; /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 2bfb17b5c..7cb49c6cb 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -158,4 +158,13 @@ namespace Shader return found->second; } + void ShaderManager::releaseGLObjects(osg::State *state) + { + OpenThreads::ScopedLock lock(mMutex); + for (auto shader : mShaders) + shader.second->releaseGLObjects(state); + for (auto program : mPrograms) + program.second->releaseGLObjects(state); + } + } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 5196dbe80..bd820a725 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -32,6 +32,7 @@ namespace Shader osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); + void releaseGLObjects(osg::State* state); private: std::string mPath; diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 361dd6c04..1734686de 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -243,4 +243,18 @@ namespace Terrain } } + void BufferCache::releaseGLObjects(osg::State *state) + { + { + OpenThreads::ScopedLock lock(mIndexBufferMutex); + for (auto indexbuffer : mIndexBufferMap) + indexbuffer.second->releaseGLObjects(state); + } + { + OpenThreads::ScopedLock lock(mUvBufferMutex); + for (auto uvbuffer : mUvBufferMap) + uvbuffer.second->releaseGLObjects(state); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index bfdf558bc..37563d2c6 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -24,7 +24,7 @@ namespace Terrain void clearCache(); - // TODO: add releaseGLObjects() for our vertex/element buffer objects + void releaseGLObjects(osg::State* state); private: // Index buffers are shared across terrain batches where possible. There is one index buffer for each diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index ea71c726f..7575113ef 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -62,6 +62,12 @@ void ChunkManager::clearCache() mBufferCache.clearCache(); } +void ChunkManager::releaseGLObjects(osg::State *state) +{ + ResourceManager::releaseGLObjects(state); + mBufferCache.releaseGLObjects(state); +} + void ChunkManager::setCullingActive(bool active) { mCullingActive = active; diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 2f92fa836..46531f23e 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -36,6 +36,8 @@ namespace Terrain virtual void clearCache(); + void releaseGLObjects(osg::State* state) override; + void setCullingActive(bool active); private: From 5d2fe5e887b10ca84f645af42008723777b1e31a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 27 Aug 2017 21:22:17 +0000 Subject: [PATCH 128/136] Implement lightmode/vertmode of NiVertexColorProperty --- components/nifosg/nifloader.cpp | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e514cca12..522cf6ac3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1674,6 +1674,8 @@ namespace NifOsg bool hasMatCtrl = false; + int lightmode = 1; + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; @@ -1706,19 +1708,25 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: { const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) + lightmode = vertprop->data.lightmode; + + if (hasVertexColors) { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; + switch (vertprop->data.vertmode) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + if (lightmode != 0) + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + else + mat->setColorMode(osg::Material::OFF); + break; + } } break; } @@ -1772,6 +1780,14 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT); } + if (lightmode == 0) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse = osg::Vec4f(0,0,0,diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f()); + } + if (!hasMatCtrl && mat->getColorMode() == osg::Material::OFF && mat->getEmission(osg::Material::FRONT_AND_BACK) == osg::Vec4f(0,0,0,1) && mat->getDiffuse(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) From bc82c6a35da5c6d46581b91afcfb5300fd360b53 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 27 Aug 2017 21:22:44 +0000 Subject: [PATCH 129/136] Use white color if told to use nonexisting vertexcolors (Fixes #3833) --- components/nifosg/nifloader.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 522cf6ac3..78186c439 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1710,10 +1710,8 @@ namespace NifOsg const Nif::NiVertexColorProperty* vertprop = static_cast(property); lightmode = vertprop->data.lightmode; - if (hasVertexColors) + switch (vertprop->data.vertmode) { - switch (vertprop->data.vertmode) - { case 0: mat->setColorMode(osg::Material::OFF); break; @@ -1726,7 +1724,6 @@ namespace NifOsg else mat->setColorMode(osg::Material::OFF); break; - } } break; } @@ -1788,6 +1785,27 @@ namespace NifOsg mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f()); } + // If we're told to use vertex colors but there are none to use, use a default color instead. + if (!hasVertexColors) + { + switch (mat->getColorMode()) + { + case osg::Material::AMBIENT: + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + case osg::Material::AMBIENT_AND_DIFFUSE: + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + case osg::Material::EMISSION: + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + default: + break; + } + mat->setColorMode(osg::Material::OFF); + } + if (!hasMatCtrl && mat->getColorMode() == osg::Material::OFF && mat->getEmission(osg::Material::FRONT_AND_BACK) == osg::Vec4f(0,0,0,1) && mat->getDiffuse(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) From fb45995a41e55f3956459878e13f94c67f641880 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 19:24:34 +0400 Subject: [PATCH 130/136] Do not allow player to change weapon/spell during attack or spellcasting (bug #2445) --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwbase/windowmanager.hpp | 5 +- apps/openmw/mwclass/weapon.cpp | 4 ++ apps/openmw/mwgui/inventorywindow.cpp | 12 ++++- apps/openmw/mwgui/quickkeysmenu.cpp | 49 +++++++++++++++++++ apps/openmw/mwgui/quickkeysmenu.hpp | 3 +- apps/openmw/mwgui/spellwindow.cpp | 10 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 5 +- apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++ apps/openmw/mwmechanics/actors.cpp | 10 ++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 6 +++ apps/openmw/mwmechanics/character.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 16 files changed, 124 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2daaf9711..7966cb6da 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -221,6 +221,7 @@ namespace MWBase virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 416a7ad87..d7ccfa3e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -212,7 +212,10 @@ namespace MWBase virtual void setSpellVisibility(bool visible) = 0; virtual void setSneakVisibility(bool visible) = 0; - virtual void activateQuickKey (int index) = 0; + /// activate selected quick key + virtual void activateQuickKey (int index) = 0; + /// update activated quick key state (if action executing was delayed for some reason) + virtual void updateActivatedQuickKey () = 0; virtual std::string getSelectedSpell() = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index efb6248af..62a9b6d0f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -4,6 +4,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -373,6 +374,9 @@ namespace MWClass if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); if (slots_.first.empty()) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8b0f895d1..4cba7a0ae 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -29,6 +29,7 @@ #include "../mwrender/characterpreview.hpp" #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" @@ -660,9 +661,18 @@ namespace MWGui void InventoryWindow::cycle(bool next) { + MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player)) + return; + + const MWMechanics::CreatureStats &stats = player.getClass().getCreatureStats(player); + if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) + return; + ItemModel::ModelIndex selected = -1; // not using mSortFilterModel as we only need sorting, not filtering - SortFilterItemModel model(new InventoryItemModel(MWMechanics::getPlayer())); + SortFilterItemModel model(new InventoryItemModel(player)); model.setSortByType(false); model.update(); if (model.getItemCount() == 0) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 619540cff..4e4462409 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -14,6 +14,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -36,6 +37,7 @@ namespace MWGui , mItemSelectionDialog(0) , mMagicSelectionDialog(0) , mSelectedIndex(-1) + , mActivatedIndex(-1) { getWidget(mOkButton, "OKButton"); getWidget(mInstructionLabel, "InstructionLabel"); @@ -69,6 +71,8 @@ namespace MWGui void QuickKeysMenu::clear() { + mActivatedIndex = -1; + for (int i=0; i<10; ++i) { unassign(mQuickKeyButtons[i], i); @@ -254,6 +258,15 @@ namespace MWGui mMagicSelectionDialog->setVisible(false); } + void QuickKeysMenu::updateActivatedQuickKey() + { + // there is no delayed action, nothing to do. + if (mActivatedIndex < 0) + return; + + activateQuickKey(mActivatedIndex); + } + void QuickKeysMenu::activateQuickKey(int index) { assert (index-1 >= 0); @@ -263,6 +276,27 @@ namespace MWGui MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); + + // Delay action executing, + // if player is busy for now (casting a spell, attacking someone, etc.) + bool isDelayNeeded = MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player) + || playerStats.getKnockedDown() + || playerStats.getHitRecovery(); + + bool isReturnNeeded = playerStats.isParalyzed() || playerStats.isDead(); + if (isReturnNeeded && type != Type_Item) + { + return; + } + + if (isDelayNeeded && type != Type_Item) + { + mActivatedIndex = index; + return; + } + else + mActivatedIndex = -1; if (type == Type_Item || type == Type_MagicItem) { @@ -309,6 +343,21 @@ namespace MWGui else if (type == Type_Item) { MWWorld::Ptr item = *button->getUserData(); + bool isWeapon = item.getTypeName() == typeid(ESM::Weapon).name(); + + // delay weapon switching if player is busy + if (isDelayNeeded && isWeapon) + { + mActivatedIndex = index; + return; + } + + // disable weapon switching if player is dead or paralyzed + if (isReturnNeeded && isWeapon) + { + return; + } + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index afbcff001..64db9043e 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -36,6 +36,7 @@ namespace MWGui void onAssignMagicCancel (); void activateQuickKey(int index); + void updateActivatedQuickKey(); /// @note This enum is serialized, so don't move the items around! enum QuickKeyType @@ -64,7 +65,7 @@ namespace MWGui MagicSelectionDialog* mMagicSelectionDialog; int mSelectedIndex; - + int mActivatedIndex; void onQuickKeyButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 0c3485e6a..5ce3fd1fe 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -195,6 +196,15 @@ namespace MWGui void SpellWindow::cycle(bool next) { + MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player)) + return; + + const MWMechanics::CreatureStats &stats = player.getClass().getCreatureStats(player); + if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) + return; + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); SpellModel::ModelIndex selected = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..06854c43f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -518,6 +518,8 @@ namespace MWGui cleanupGarbage(); mHud->update(); + + updateActivatedQuickKey (); } void WindowManager::updateVisible() @@ -1528,6 +1530,11 @@ namespace MWGui mHud->setCrosshairVisible (show && mCrosshairEnabled); } + void WindowManager::updateActivatedQuickKey () + { + mQuickKeysMenu->updateActivatedQuickKey(); + } + void WindowManager::activateQuickKey (int index) { mQuickKeysMenu->activateQuickKey(index); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f74ba21a3..ceb6f62b7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -241,7 +241,10 @@ namespace MWGui virtual void setSpellVisibility(bool visible); virtual void setSneakVisibility(bool visible); - virtual void activateQuickKey (int index); + /// activate selected quick key + virtual void activateQuickKey (int index); + /// update activated quick key state (if action executing was delayed for some reason) + virtual void updateActivatedQuickKey (); virtual std::string getSelectedSpell() { return mSelectedSpell; } virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a823ae0fd..5f3e3152d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -20,6 +20,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -929,6 +930,9 @@ namespace MWInput inventory.getSelectedEnchantItem() == inventory.end()) return; + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + return; + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) mPlayer->setDrawState(MWMechanics::DrawState_Spell); @@ -944,6 +948,9 @@ namespace MWInput if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"]) return; + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + return; + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) mPlayer->setDrawState(MWMechanics::DrawState_Weapon); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9a23526f7..cd15c4074 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1784,6 +1784,16 @@ namespace MWMechanics return it->second->getCharacterController()->isReadyToBlock(); } + bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isAttackingOrSpell(); + } + void Actors::fastForwardAi() { if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index cd949696b..b7aae21e8 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -150,6 +150,7 @@ namespace MWMechanics void clear(); // Clear death counter bool isReadyToBlock(const MWWorld::Ptr& ptr) const; + bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; private: PtrActorMap mActors; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 25d04d176..e9f42476b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2228,6 +2228,12 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +bool CharacterController::isAttackingOrSpell() const +{ + return mUpperBodyState != UpperCharState_Nothing && + mUpperBodyState != UpperCharState_WeapEquiped; +} + bool CharacterController::isSneaking() const { return mIdleState == CharState_IdleSneak || diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 66039bf5d..bde64cdfb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -267,6 +267,7 @@ public: bool isKnockedOut() const; bool isSneaking() const; bool isRunning() const; + bool isAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell); void setAIAttackType(const std::string& attackType); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d182e40d7..c0685e6f0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1581,6 +1581,11 @@ namespace MWMechanics return mActors.isReadyToBlock(ptr); } + bool MechanicsManager::isAttackingOrSpell(const MWWorld::Ptr &ptr) const + { + return mActors.isAttackingOrSpell(ptr); + } + void MechanicsManager::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) { MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af0377a33..1cab13cbc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -188,6 +188,8 @@ namespace MWMechanics virtual void keepPlayerAlive(); virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + /// Is \a ptr casting spell or using weapon now? + virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); From 8003dbee12b67e9c52e4dc8a9c75a9861ee0d794 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 29 Aug 2017 16:40:55 +0400 Subject: [PATCH 131/136] Combat AI: use effective cast cost when rate enchanted weapon --- apps/openmw/mwmechanics/weaponpriority.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 07cf6ff5f..d06e73c93 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -13,6 +13,7 @@ #include "combat.hpp" #include "aicombataction.hpp" #include "spellpriority.hpp" +#include "spellcasting.hpp" namespace MWMechanics { @@ -90,10 +91,13 @@ namespace MWMechanics if (!weapon->mEnchant.empty()) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes - && (item.getCellRef().getEnchantmentCharge() == -1 - || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) - rating += rateEffects(enchantment->mEffects, actor, enemy); + if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) + { + int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), actor); + + if (item.getCellRef().getEnchantmentCharge() == -1 || item.getCellRef().getEnchantmentCharge() >= castCost) + rating += rateEffects(enchantment->mEffects, actor, enemy); + } } int skill = item.getClass().getEquipmentSkill(item); From 3fc86342061bab0c30bed6821f66933fef546930 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 29 Aug 2017 12:55:42 +0000 Subject: [PATCH 132/136] Check for a Geometry node when attaching bodyparts (Fixes #3957) --- components/nifosg/nifloader.cpp | 3 +++ components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 78186c439..b7d1c15b8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,6 +1130,8 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } + geometry->setName(triShape->name); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1219,6 +1221,7 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); + rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 1385f771e..8634a4df6 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - applyNode(node); - } - virtual void apply(osg::Geometry& node) - { - applyNode(node); + traverse(node); } virtual void apply(osg::Node& node) { - applyNode(node); + traverse(node); } virtual void apply(osg::Group& node) { - applyNode(node); + traverse(node); } - void applyNode(osg::Node& node) + virtual void apply(osg::Geometry& geom) { - std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - mToCopy.push_back(&node); - else - traverse(node); + { + osg::Node* node = &geom; + while (node && node->getNumParents() && !node->getStateSet()) + node = node->getParent(0); + if (node) + mToCopy.push_back(node); + } } void doCopy() From 73d5efabeed6b07cdaea8d7cf147fbc6a4739f6e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 29 Aug 2017 18:04:31 +0400 Subject: [PATCH 133/136] Display negative values on fatigue progress bar --- apps/openmw/mwgui/hud.cpp | 18 +++++++++++------- apps/openmw/mwgui/review.cpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 11 ++++++++--- apps/openmw/mwgui/widgets.cpp | 5 ++--- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 84e5794e3..0e1b2cc89 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -179,29 +179,33 @@ namespace MWGui void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); + // Fatigue can be negative + if (id != "FBar") + current = std::max(0, current); + MyGUI::Widget* w; std::string valStr = MyGUI::utility::toString(current) + " / " + MyGUI::utility::toString(modified); if (id == "HBar") { - mHealth->setProgressRange(modified); - mHealth->setProgressPosition(current); + mHealth->setProgressRange(std::max(0, modified)); + mHealth->setProgressPosition(std::max(0, current)); getWidget(w, "HealthFrame"); w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } else if (id == "MBar") { - mMagicka->setProgressRange (modified); - mMagicka->setProgressPosition (current); + mMagicka->setProgressRange(std::max(0, modified)); + mMagicka->setProgressPosition(std::max(0, current)); getWidget(w, "MagickaFrame"); w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { - mStamina->setProgressRange (modified); - mStamina->setProgressPosition (current); + mStamina->setProgressRange(std::max(0, modified)); + mStamina->setProgressPosition(std::max(0, current)); getWidget(w, "FatigueFrame"); w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1a680b801..bf18e7355 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -180,7 +180,7 @@ namespace MWGui void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); mFatigue->setValue(current, modified); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 22140b8b2..17e51e338 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -102,12 +102,13 @@ namespace MWGui { MyGUI::ProgressBar* pt; getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); std::stringstream out; out << val << "/" << max; setText(tname, out.str().c_str()); + + pt->setProgressRange(std::max(0, max)); + pt->setProgressPosition(std::max(0, val)); } void StatsWindow::setPlayerName(const std::string& playerName) @@ -147,9 +148,13 @@ namespace MWGui void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); + // Fatigue can be negative + if (id != "FBar") + current = std::max(0, current); + setBar (id, id + "T", current, modified); // health, magicka, fatigue tooltip diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 695337cde..744ef236f 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -502,11 +502,10 @@ namespace MWGui if (mBarWidget) { - mBarWidget->setProgressRange(mMax); - mBarWidget->setProgressPosition(mValue); + mBarWidget->setProgressRange(std::max(0, mMax)); + mBarWidget->setProgressPosition(std::max(0, mValue)); } - if (mBarTextWidget) { std::stringstream out; From 47d6c5091ff0ca0289dd686782d2bd6fbb14a42c Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Tue, 29 Aug 2017 23:39:24 +0100 Subject: [PATCH 134/136] OpenMW CS Manual - typo fixes etc (#1422) * Update files-and-directories.rst * OpenMW CS Manual - minor typo fixes --- .../openmw-cs/files-and-directories.rst | 46 +++++++++---------- .../manuals/openmw-cs/starting-dialog.rst | 4 +- docs/source/manuals/openmw-cs/tour.rst | 4 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/source/manuals/openmw-cs/files-and-directories.rst b/docs/source/manuals/openmw-cs/files-and-directories.rst index 34680fa94..77593dece 100644 --- a/docs/source/manuals/openmw-cs/files-and-directories.rst +++ b/docs/source/manuals/openmw-cs/files-and-directories.rst @@ -14,22 +14,22 @@ Basics Directories =========== -OpenMW and OpenMW CS us multiple directories on the file system. First of all +OpenMW and OpenMW CS use multiple directories on the file system. First of all there is a *user directory* that holds configuration files and a number of different sub-directories. The location of the user directory is hard-coded into the CS and depends on your operating system. ================ ========================================= -Operating System User Dircetory +Operating System User Directory ================ ========================================= -GNU/Linux ```` +GNU/Linux ``~/.config/openmw/`` OS X ``~/Library/Application Support/openmw/`` -Windows ```` +Windows ``C:\Users\ *Username* \Documents\my games\OpenMW`` ================ ========================================= In addition to to this single hard-coded directory both OpenMW and OpenMW CS -need a place to seek for a actuals data files of the game: textures, 3D models, -sounds and record files that store objects in game; dialogues an so one. These +need a place to search for actual data files of the game: textures, 3D models, +sounds and record files that store objects in game; dialogues and so on. These files are called *content files*. We support multiple such paths (we call them *data paths*) as specified in the configuration. Usually one data path points to the directory where the original Morrowind game is either installed or @@ -42,12 +42,12 @@ Content files ============= The original Morrowind engine by Bethesda Softworks uses two types of content -files: `esm` (master) and `esp` (plugin). The distinction between those two is -not clear, and often confusing. One would expect the `esm` (master) file to be -used to specify one master, which is then modified by the `esp` plugins. And +files: `ESM` (master) and `ESP` (plugin). The distinction between those two is +not clear, and often confusing. One would expect the `ESM` (master) file to be +used to specify one master, which is then modified by the `ESP` plugins. And indeed: this is the basic idea. However, the official expansions were also made as ESM files, even though they could essentially be described as really large -plugins, and therefore would rather use `esp` files. There were technical +plugins, and therefore should have been `ESP` files. There were technical reasons behind this decision – somewhat valid in the case of the original engine, but clearly it is better to create a system that can be used in a more sensible way. OpenMW achieves this with our own content file types. @@ -62,7 +62,7 @@ OpenMW content files The concepts of *Game* and *Addon* files are somewhat similar to the old concept of *ESM* and *ESP*, but more strictly enforced. It is quite -straight-formward: If you want to make new game using OpenMW as the engine (a +straight-forward: If you want to make new game using OpenMW as the engine (a so called *total conversion*) you should create a game file. If you want to create an addon for an existing game file create an addon file. Nothing else matters; the only distinction you should consider is if your project is about @@ -75,21 +75,21 @@ Another simple thing about content files are the extensions: we are using Morrowind content files ----------------------- -Using our content files is recommended for projects that are intended to used -with the OpenMW engine. However, some players might wish to still use the +Using our content files is recommended for projects that are intended to use +the OpenMW engine. However, some players might wish to still use the original Morrowind engine. In addition thousands of *ESP*/*ESM* files were created since 2002, some of them with really outstanding content. Because of this OpenMW CS simply has no other choice but to support *ESP*/*ESM* files. If -you decid to choose *ESP*/*ESM* file instead of using our own content file -types you are most likely aimng at compatibility with the original engine. This -subject is covered in it own chapter of this manual. +you decide to choose *ESP*/*ESM* file instead of using our own content file +types you are most likely aiming at compatibility with the original engine. This +subject is covered in its own chapter of this manual. .. TODO This paragraph sounds weird The actual creation of new files is described in the next chapter. Here we are going to focus only on the details you need to know in order to create your -first OpenMW CS file while fully understanding your needs. For now let’s jut +first OpenMW CS file while fully understanding your needs. For now let’s just remember that content files are created inside the user directory in the the ``data`` subdirectory (that is the one special data directory mentioned earlier). @@ -99,8 +99,8 @@ Dependencies ------------ Since an addon is supposed to change the game it follows that it also depends -on the said game to work. We can conceptualise this with an examples: your -modification is the changing prize of an iron sword, but what if there is no +on the said game to work. We can conceptualise this with an example: your +modification is changing the price of an iron sword, but what if there is no iron sword in game? That's right: we get nonsense. What you want to do is tie your addon to the files you are changing. Those can be either game files (for example when making an expansion island for a game) or other addon files @@ -112,9 +112,9 @@ files – it is only a theoretical introduction to the subject. For now just kee in mind that dependencies exist, and is up to you to decide whether your content file should depend on other content files. -Game files are not intend to have any dependencies for a very simple reasons: +Game files are not intended to have any dependencies for a very simple reasons: the player is using only one game file (excluding original and the dirty -ESP/ESM system) at a time and therefore no game file can depend on other game +ESP/ESM system) at a time and therefore no game file can depend on another game file, and since a game file makes the base for addon files it can not depend on addon files. @@ -123,7 +123,7 @@ Project files ------------- Project files act as containers for data not used by the OpenMW game engine -itself, but still useful for OpenMW CS. The shining example of this data +itself, but still useful for OpenMW CS. The shining examples of this data category are without doubt record filters (described in a later chapter of the manual). As a mod author you probably do not need or want to distribute project files at all, they are meant to be used only by you and your team. @@ -132,7 +132,7 @@ files at all, they are meant to be used only by you and your team. As you would imagine, project files make sense only in combination with actual content files. In fact, each time you start to work on new content file and a -project file was not found, one will be created. The extensio of project files +project file was not found, one will be created. The extension of project files is ``.project``. The whole name of the project file is the whole name of the content file with appended extension. For instance a ``swords.omwaddon`` file is associated with a ``swords.omwaddon.project`` file. diff --git a/docs/source/manuals/openmw-cs/starting-dialog.rst b/docs/source/manuals/openmw-cs/starting-dialog.rst index 02a65ff21..fa069d8d6 100644 --- a/docs/source/manuals/openmw-cs/starting-dialog.rst +++ b/docs/source/manuals/openmw-cs/starting-dialog.rst @@ -3,7 +3,7 @@ OpenMW CS Starting Dialog In this chapter we will cover starting up OpenMW CS and the starting interface. Start the CS the way intended for your operating system and you will be -presented with window and three main buttons and a small button with a +presented with a window and three main buttons and a small button with a wrench-icon. The wrench will open the configuration dialog which we will cover later. The three main buttons are the following: @@ -32,7 +32,7 @@ choose exactly one game and you can choose an arbitrary amount of addon dependencies. For the sake of simplicity and maintainability choose only the addons you actually want to depend on. Also keep in mind that your dependencies might have dependencies of their own, you have to depend on those as well. If -one of your dependencies nees something it will be indicated by a warning sign +one of your dependencies needs something it will be indicated by a warning sign and automatically include its dependencies when you choose it. If you want to edit an existing content file you will be presented with a diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 9844948ea..bb1097e0c 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -48,7 +48,7 @@ Once the addon has been created you will be presented with a table. If you see a blank window rather than a table choose *World* → *Objects* from the menu. .. figure:: _static/images/chapter-1/objects.png - :alt: The table showing all objet records in the game. + :alt: The table showing all object records in the game. Let's talk about the interface for a second. Every window in OpenMW CS has *panels*, these are often but not always tables. You can close a panel by @@ -139,7 +139,7 @@ the first character. Type the following into the field: A filter is defined by a number of *queries* which can be logically linked. For now all that matters is that the `string(, )` query will check -whether `` matches ``. The pattern is a regular expression, +whether `` matches ``. The pattern is a regular expression, if you don't know about them you should learn their syntax. For now all that matters is that `.` stands for any character and `*` stands for any amount, even zero. In other words, we are looking for all entries which have an ID that From a1e3fb7604a11307ed08f1ec84b31a359cb5ead5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 29 Aug 2017 22:40:19 +0000 Subject: [PATCH 135/136] Revert "Check for a Geometry node when attaching bodyparts" This reverts commit 3fc86342061bab0c30bed6821f66933fef546930. --- components/nifosg/nifloader.cpp | 3 --- components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b7d1c15b8..78186c439 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,8 +1130,6 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } - geometry->setName(triShape->name); - if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1221,7 +1219,6 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); - rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 8634a4df6..1385f771e 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - traverse(node); + applyNode(node); + } + virtual void apply(osg::Geometry& node) + { + applyNode(node); } virtual void apply(osg::Node& node) { - traverse(node); + applyNode(node); } virtual void apply(osg::Group& node) { - traverse(node); + applyNode(node); } - virtual void apply(osg::Geometry& geom) + void applyNode(osg::Node& node) { - std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - { - osg::Node* node = &geom; - while (node && node->getNumParents() && !node->getStateSet()) - node = node->getParent(0); - if (node) - mToCopy.push_back(node); - } + mToCopy.push_back(&node); + else + traverse(node); } void doCopy() From 8c6a8ca48d7077e360ff49cc2795cad271b2d139 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 30 Aug 2017 21:26:30 +0000 Subject: [PATCH 136/136] Respect the framelimit in all cases (Fixes #3531) Affects loading screen, videos & modal dialogs. Also skips rendering if window is minimized. --- apps/openmw/engine.cpp | 16 ++++------ apps/openmw/mwbase/environment.cpp | 27 ++++++++++++++++- apps/openmw/mwbase/environment.hpp | 5 ++++ apps/openmw/mwgui/loadingscreen.cpp | 15 ++++++++-- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 41 +++++++++++++++++++------- 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c921e17d0..f5ec86cc3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -84,7 +84,6 @@ void OMW::Engine::frame(float frametime) try { mStartTick = mViewer->getStartTick(); - mEnvironment.setFrameDuration (frametime); // update input mEnvironment.getInputManager()->update(frametime, false); @@ -651,6 +650,8 @@ void OMW::Engine::go() Settings::Manager::getString("screenshot format", "General"))); mViewer->addEventHandler(mScreenCaptureHandler); + mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video")); + // Create encoder ToUTF8::Utf8Encoder encoder (mEncoding); mEncoder = &encoder; @@ -684,7 +685,6 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; - float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video"); while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); @@ -697,6 +697,8 @@ void OMW::Engine::go() mViewer->advance(simulationTime); + mEnvironment.setFrameDuration(dt); + frame(dt); if (!mEnvironment.getInputManager()->isWindowVisible()) @@ -714,15 +716,7 @@ void OMW::Engine::go() mViewer->renderingTraversals(); } - if (framerateLimit > 0.f) - { - double thisFrameTime = frameTimer.time_s(); - double minFrameTime = 1.0 / framerateLimit; - if (thisFrameTime < minFrameTime) - { - OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); - } - } + mEnvironment.limitFrameRate(frameTimer.time_s()); } // Save user settings diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 4efa7c273..5d01525b9 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -2,6 +2,8 @@ #include +#include + #include "world.hpp" #include "scriptmanager.hpp" #include "dialoguemanager.hpp" @@ -17,7 +19,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0), - mFrameDuration (0) + mFrameDuration (0), mFrameRateLimit(0.f) { assert (!sThis); sThis = this; @@ -79,6 +81,29 @@ void MWBase::Environment::setFrameDuration (float duration) mFrameDuration = duration; } +void MWBase::Environment::setFrameRateLimit(float limit) +{ + mFrameRateLimit = limit; +} + +float MWBase::Environment::getFrameRateLimit() const +{ + return mFrameRateLimit; +} + +void MWBase::Environment::limitFrameRate(double dt) const +{ + if (mFrameRateLimit > 0.f) + { + double thisFrameTime = dt; + double minFrameTime = 1.0 / static_cast(mFrameRateLimit); + if (thisFrameTime < minFrameTime) + { + OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); + } + } +} + MWBase::World *MWBase::Environment::getWorld() const { assert (mWorld); diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 7f7919f81..9163b21f3 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -33,6 +33,7 @@ namespace MWBase InputManager *mInputManager; StateManager *mStateManager; float mFrameDuration; + float mFrameRateLimit; Environment (const Environment&); ///< not implemented @@ -67,6 +68,10 @@ namespace MWBase void setFrameDuration (float duration); ///< Set length of current frame in seconds. + void setFrameRateLimit(float frameRateLimit); + float getFrameRateLimit() const; + void limitFrameRate(double dt) const; + World *getWorld() const; SoundManager *getSoundManager() const; diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index ca6a0b0a4..c5836b653 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -102,6 +102,15 @@ namespace MWGui mBackgroundImage->setVisible(visible); } + double LoadingScreen::getTargetFrameRate() const + { + double frameRateLimit = MWBase::Environment::get().getFrameRateLimit(); + if (frameRateLimit > 0) + return std::min(frameRateLimit, mTargetFrameRate); + else + return mTargetFrameRate; + } + class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback { public: @@ -141,7 +150,7 @@ namespace MWGui if (mViewer->getIncrementalCompileOperation()) { mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100); - mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate); + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(getTargetFrameRate()); } // Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading @@ -210,7 +219,7 @@ namespace MWGui void LoadingScreen::setProgress (size_t value) { // skip expensive update if there isn't enough visible progress - if (value - mProgress < mProgressBar->getScrollRange()/200.f) + if (mProgressBar->getWidth() <= 0 || value - mProgress < mProgressBar->getScrollRange()/mProgressBar->getWidth()) return; value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; @@ -231,7 +240,7 @@ namespace MWGui bool LoadingScreen::needToDrawLoadingScreen() { - if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + if ( mTimer.time_m() <= mLastRenderTime + (1.0/getTargetFrameRate()) * 1000.0) return false; // the minimal delay before a loading screen shows diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 1a53495a9..2f8831fdc 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -43,6 +43,8 @@ namespace MWGui virtual void setVisible(bool visible); + double getTargetFrameRate() const; + private: void findSplashScreens(); bool needToDrawLoadingScreen(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b0d0d8acd..33ba58cc7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -906,19 +906,30 @@ namespace MWGui if (block) { + osg::Timer frameTimer; while (mMessageBoxManager->readPressedButton(false) == -1 && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - mMessageBoxManager->onFrame(0.f); - MWBase::Environment::get().getInputManager()->update(0, true, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + mMessageBoxManager->onFrame(dt); + MWBase::Environment::get().getInputManager()->update(dt, true, false); + + if (!MWBase::Environment::get().getInputManager()->isWindowVisible()) + OpenThreads::Thread::microSleep(5000); + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + + MWBase::Environment::get().limitFrameRate(frameTimer.time_s()); } } } @@ -1838,18 +1849,28 @@ namespace MWGui if (mVideoWidget->hasAudioStream()) MWBase::Environment::get().getSoundManager()->pauseSounds( MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie)); - + osg::Timer frameTimer; while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - MWBase::Environment::get().getInputManager()->update(0, true, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + MWBase::Environment::get().getInputManager()->update(dt, true, false); + + if (!MWBase::Environment::get().getInputManager()->isWindowVisible()) + OpenThreads::Thread::microSleep(5000); + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + + MWBase::Environment::get().limitFrameRate(frameTimer.time_s()); } mVideoWidget->stop();