diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index e6d71eaa2..3a0bf3d03 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -235,6 +235,10 @@ namespace MWBase virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f1c35df19..2b3cf1f0d 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -82,9 +82,6 @@ namespace MWBase ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle() = 0; - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying() = 0; ///< Returns true if music is playing diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..bfe173b47 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -206,7 +206,8 @@ namespace MWGui int textButtonPadding = 10; // padding between the text-widget und the button-widget int buttonLeftPadding = 10; // padding between the buttons if horizontal int buttonTopPadding = 10; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself + int buttonLabelLeftPadding = 12; // padding between button label and button itself, from left + int buttonLabelTopPadding = 4; // padding between button label and button itself, from top int buttonMainPadding = 10; // padding between buttons and bottom of the main widget mMarkedToDelete = false; @@ -245,10 +246,10 @@ namespace MWGui if (buttonsWidth != 0) buttonsWidth += buttonLeftPadding; - int buttonWidth = button->getTextSize().width + 2*buttonPadding; + int buttonWidth = button->getTextSize().width + 2*buttonLabelLeftPadding; buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding; + buttonHeight = button->getTextSize().height + 2*buttonLabelTopPadding; if (buttonsHeight != 0) buttonsHeight += buttonTopPadding; @@ -295,8 +296,8 @@ namespace MWGui buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + buttonSize.width = (*button)->getTextSize().width + 2*buttonLabelLeftPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonLabelTopPadding; (*button)->setCoord(buttonCord); (*button)->setSize(buttonSize); @@ -322,8 +323,8 @@ namespace MWGui std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + buttonSize.width = (*button)->getTextSize().width + buttonLabelLeftPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonLabelTopPadding*2; buttonCord.top = top; buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2254b8194..df8f486ef 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1175,6 +1175,39 @@ namespace MWMechanics } } + bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + if (!actor.getClass().isActor()) + return false; + + // If an observer is NPC, check if he detected an actor + if (!observer.isEmpty() && observer.getClass().isNpc()) + { + return + MWBase::Environment::get().getWorld()->getLOS(observer, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + } + + // Otherwise check if any actor in AI processing range sees the target actor + std::vector actors; + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); + getObjectsInRange(position, aiProcessingDistance, actors); + for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + { + if (*it == actor) + continue; + + bool result = + MWBase::Environment::get().getWorld()->getLOS(*it, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it); + + if (result) + return true; + } + + return false; + } + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { PtrActorMap::iterator iter = mActors.find(old); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 680e3c9cb..36f200647 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -57,6 +57,10 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) void updateMagicEffects (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2cd860a4c..f820d96e0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2146,76 +2146,71 @@ void CharacterController::unpersistAnimationState() bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - { - std::cerr<< "Animation "<getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && + mAnimation->isPlaying(groupname)) { - // If this animation is a looped animation (has a "loop start" key) that is already playing - // and has not yet reached the end of the loop, allow it to continue animating with its existing loop count - // and remove any other animations that were queued. - // This emulates observed behavior from the original allows the script "OutsideBanner" to animate banners correctly. - if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname && - mAnimation->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && - mAnimation->isPlaying(groupname)) - { - float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); + float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); - if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key - endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); + if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key + endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); - if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) - { - mAnimQueue.resize(1); - return true; - } + if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) + { + mAnimQueue.resize(1); + return true; } + } - count = std::max(count, 1); + count = std::max(count, 1); - AnimationQueueEntry entry; - entry.mGroup = groupname; - entry.mLoopCount = count-1; - entry.mPersist = persist; + AnimationQueueEntry entry; + entry.mGroup = groupname; + entry.mLoopCount = count-1; + entry.mPersist = persist; - if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) - { - clearAnimQueue(); - mAnimQueue.push_back(entry); + if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) + { + clearAnimQueue(); + mAnimQueue.push_back(entry); - mAnimation->disable(mCurrentIdle); - mCurrentIdle.clear(); + mAnimation->disable(mCurrentIdle); + mCurrentIdle.clear(); - mIdleState = CharState_SpecialIdle; - bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); - mAnimation->play(groupname, Priority_Default, - MWRender::Animation::BlendMask_All, false, 1.0f, - ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); + mIdleState = CharState_SpecialIdle; + bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); + mAnimation->play(groupname, Priority_Default, + MWRender::Animation::BlendMask_All, false, 1.0f, + ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); - /* - Start of tes3mp addition + /* + Start of tes3mp addition - If we are the cell authority over this actor, we need to record this new - animation for it - */ - if (mwmp::Main::get().getCellController()->isLocalActor(mPtr)) - { - mwmp::LocalActor *actor = mwmp::Main::get().getCellController()->getLocalActor(mPtr); - actor->animation.groupname = groupname; - actor->animation.mode = mode; - actor->animation.count = count; - actor->animation.persist = persist; - } - /* - End of tes3mp addition - */ - } - else if(mode == 0) + If we are the cell authority over this actor, we need to record this new + animation for it + */ + if (mwmp::Main::get().getCellController()->isLocalActor(mPtr)) { - mAnimQueue.resize(1); - mAnimQueue.push_back(entry); + mwmp::LocalActor *actor = mwmp::Main::get().getCellController()->getLocalActor(mPtr); + actor->animation.groupname = groupname; + actor->animation.mode = mode; + actor->animation.count = count; + actor->animation.persist = persist; } + /* + End of tes3mp addition + */ + } + else if(mode == 0) + { + mAnimQueue.resize(1); + mAnimQueue.push_back(entry); } return true; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b922c9d74..390f17135 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -436,6 +436,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + return mActors.isActorDetected(actor, observer); + } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) { return mActors.isAttackPrepairing(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 7660d651e..af0863381 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -201,6 +201,10 @@ namespace MWMechanics /// Is \a ptr casting spell or using weapon now? virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df9b8545a..90b69de8e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -757,8 +757,6 @@ namespace MWRender break; } } - if(iter == mAnimSources.rend()) - std::cerr<< "Failed to find animation "<second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) + && (stopkey->second.size() < stoptag.size() || stopkey->second.compare(0,stoptag.size(), stoptag) != 0)) ++stopkey; if(stopkey == keys.rend()) return false; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 76130be24..c98e0fc5a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -372,21 +372,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr observer = R()(runtime); + MWWorld::Ptr observer = R()(runtime, false); // required=false + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true); - if(!actor.getClass().isActor() || !observer.getClass().isActor()) - { - runtime.push(0); - return; - } - - Interpreter::Type_Integer value = - MWBase::Environment::get().getWorld()->getLOS(observer, actor) && - MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer); runtime.push (value); } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ac87a2f06..a798d350c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -391,11 +391,6 @@ namespace MWSound mMusic->setFadeout(0.5f); } - void SoundManager::streamMusic(const std::string& filename) - { - advanceMusic("Music/"+filename); - } - void SoundManager::startRandomTitle() { std::vector filelist; @@ -446,6 +441,12 @@ namespace MWSound tracklist.pop_back(); } + + void SoundManager::streamMusic(const std::string& filename) + { + advanceMusic("Music/"+filename); + } + bool SoundManager::isMusicPlaying() { return mMusic && mOutput->isStreamPlaying(mMusic); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d2dce3928..e31a0e575 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -127,6 +127,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void advanceMusic(const std::string& filename); + void startRandomTitle(); void updateSounds(float duration); void updateRegionSound(float duration); @@ -157,9 +158,6 @@ namespace MWSound ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle(); - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying(); ///< Returns true if music is playing diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 65524f76e..b223353c2 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -141,11 +141,11 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); /// @see ResourceManager::updateCache - virtual void updateCache(double referenceTime); + void updateCache(double referenceTime) override; - virtual void clearCache(); + void clearCache() override; - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; private: diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 46531f23e..d8c4fd084 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -32,9 +32,9 @@ namespace Terrain osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; - virtual void clearCache(); + void clearCache() override; void releaseGLObjects(osg::State* state) override;