mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-04 07:56:45 +00:00 
			
		
		
		
	Split greetings from AiWander (bug #4594)
This commit is contained in:
		
							parent
							
								
									b7a1e6561b
								
							
						
					
					
						commit
						69aceb5c1e
					
				
					 8 changed files with 204 additions and 109 deletions
				
			
		| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
    Bug #4411: Reloading a saved game while falling prevents damage in some cases
 | 
					    Bug #4411: Reloading a saved game while falling prevents damage in some cases
 | 
				
			||||||
    Bug #4456: AiActivate should not be cancelled after target activation
 | 
					    Bug #4456: AiActivate should not be cancelled after target activation
 | 
				
			||||||
    Bug #4540: Rain delay when exiting water
 | 
					    Bug #4540: Rain delay when exiting water
 | 
				
			||||||
 | 
					    Bug #4594: Actors without AI packages don't use Hello dialogue
 | 
				
			||||||
    Bug #4600: Crash when no sound output is available or --no-sound is used.
 | 
					    Bug #4600: Crash when no sound output is available or --no-sound is used.
 | 
				
			||||||
    Bug #4639: Black screen after completing first mages guild mission + training
 | 
					    Bug #4639: Black screen after completing first mages guild mission + training
 | 
				
			||||||
    Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog
 | 
					    Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@
 | 
				
			||||||
#include "../mwrender/vismask.hpp"
 | 
					#include "../mwrender/vismask.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "spellcasting.hpp"
 | 
					#include "spellcasting.hpp"
 | 
				
			||||||
 | 
					#include "steering.hpp"
 | 
				
			||||||
#include "npcstats.hpp"
 | 
					#include "npcstats.hpp"
 | 
				
			||||||
#include "creaturestats.hpp"
 | 
					#include "creaturestats.hpp"
 | 
				
			||||||
#include "movement.hpp"
 | 
					#include "movement.hpp"
 | 
				
			||||||
| 
						 | 
					@ -141,6 +142,9 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWMechanics
 | 
					namespace MWMechanics
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    static const int GREETING_SHOULD_START = 4; //how many updates should pass before NPC can greet player
 | 
				
			||||||
 | 
					    static const int GREETING_SHOULD_END = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class GetStuntedMagickaDuration : public MWMechanics::EffectSourceVisitor
 | 
					    class GetStuntedMagickaDuration : public MWMechanics::EffectSourceVisitor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
| 
						 | 
					@ -397,6 +401,113 @@ namespace MWMechanics
 | 
				
			||||||
            MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
 | 
					            MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Actors::updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!actor.getClass().isActor() || actor == getPlayer())
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CreatureStats &stats = actor.getClass().getCreatureStats(actor);
 | 
				
			||||||
 | 
					        int hello = stats.getAiSetting(CreatureStats::AI_Hello).getModified();
 | 
				
			||||||
 | 
					        if (hello == 0)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (MWBase::Environment::get().getWorld()->isSwimming(actor))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MWWorld::Ptr player = getPlayer();
 | 
				
			||||||
 | 
					        osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
 | 
				
			||||||
 | 
					        osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
 | 
				
			||||||
 | 
					        osg::Vec3f dir = playerPos - actorPos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const MWMechanics::AiSequence& seq = stats.getAiSequence();
 | 
				
			||||||
 | 
					        int packageId = seq.getTypeId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (seq.isInCombat() || (packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stats.setTurningToPlayer(false);
 | 
				
			||||||
 | 
					            stats.setGreetingTimer(0);
 | 
				
			||||||
 | 
					            stats.setGreetingState(Greet_None);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (stats.isTurningToPlayer())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Reduce the turning animation glitch by using a *HUGE* value of
 | 
				
			||||||
 | 
					            // epsilon...  TODO: a proper fix might be in either the physics or the
 | 
				
			||||||
 | 
					            // animation subsystem
 | 
				
			||||||
 | 
					            if (zTurn(actor, stats.getAngleToPlayer(), osg::DegreesToRadians(5.f)))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                stats.setTurningToPlayer(false);
 | 
				
			||||||
 | 
					                // An original engine launches an endless idle2 when an actor greets player.
 | 
				
			||||||
 | 
					                playAnimationGroup (actor, "idle2", 0, std::numeric_limits<int>::max(), false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (turnOnly)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Play a random voice greeting if the player gets too close
 | 
				
			||||||
 | 
					        float helloDistance = static_cast<float>(hello);
 | 
				
			||||||
 | 
					        static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
 | 
				
			||||||
 | 
					            .get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->mValue.getInteger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        helloDistance *= iGreetDistanceMultiplier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int greetingTimer = stats.getGreetingTimer();
 | 
				
			||||||
 | 
					        GreetingState greetingState = stats.getGreetingState();
 | 
				
			||||||
 | 
					        if (greetingState == Greet_None)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
 | 
				
			||||||
 | 
					                !player.getClass().getCreatureStats(player).isDead() && !actor.getClass().getCreatureStats(actor).isParalyzed()
 | 
				
			||||||
 | 
					                && MWBase::Environment::get().getWorld()->getLOS(player, actor)
 | 
				
			||||||
 | 
					                && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
 | 
				
			||||||
 | 
					                greetingTimer++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (greetingTimer >= GREETING_SHOULD_START)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                greetingState = Greet_InProgress;
 | 
				
			||||||
 | 
					                MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
 | 
				
			||||||
 | 
					                greetingTimer = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (greetingState == Greet_InProgress)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            greetingTimer++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            turnActorToFacePlayer(actor, dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (greetingTimer >= GREETING_SHOULD_END)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                greetingState = Greet_Done;
 | 
				
			||||||
 | 
					                greetingTimer = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (greetingState == Greet_Done)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            float resetDist = 2 * helloDistance;
 | 
				
			||||||
 | 
					            if ((playerPos - actorPos).length2() >= resetDist*resetDist)
 | 
				
			||||||
 | 
					                greetingState = Greet_None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stats.setGreetingTimer(greetingTimer);
 | 
				
			||||||
 | 
					        stats.setGreetingState(greetingState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
 | 
				
			||||||
 | 
					        actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CreatureStats &stats = actor.getClass().getCreatureStats(actor);
 | 
				
			||||||
 | 
					        if (!stats.isTurningToPlayer())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stats.setAngleToPlayer(std::atan2(dir.x(), dir.y()));
 | 
				
			||||||
 | 
					            stats.setTurningToPlayer(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
 | 
					    void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // No combat for totally static creatures
 | 
					        // No combat for totally static creatures
 | 
				
			||||||
| 
						 | 
					@ -1409,11 +1520,13 @@ namespace MWMechanics
 | 
				
			||||||
            static float timerUpdateAITargets = 0;
 | 
					            static float timerUpdateAITargets = 0;
 | 
				
			||||||
            static float timerUpdateHeadTrack = 0;
 | 
					            static float timerUpdateHeadTrack = 0;
 | 
				
			||||||
            static float timerUpdateEquippedLight = 0;
 | 
					            static float timerUpdateEquippedLight = 0;
 | 
				
			||||||
 | 
					            static float timerUpdateHello = 0;
 | 
				
			||||||
            const float updateEquippedLightInterval = 1.0f;
 | 
					            const float updateEquippedLightInterval = 1.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // target lists get updated once every 1.0 sec
 | 
					            // target lists get updated once every 1.0 sec
 | 
				
			||||||
            if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0;
 | 
					            if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0;
 | 
				
			||||||
            if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0;
 | 
					            if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0;
 | 
				
			||||||
 | 
					            if (timerUpdateHello >= 0.25f) timerUpdateHello = 0;
 | 
				
			||||||
            if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0;
 | 
					            if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0;
 | 
				
			||||||
            if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0;
 | 
					            if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1532,6 +1645,7 @@ namespace MWMechanics
 | 
				
			||||||
                            if (isConscious(iter->first))
 | 
					                            if (isConscious(iter->first))
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                stats.getAiSequence().execute(iter->first, *ctrl, duration);
 | 
					                                stats.getAiSequence().execute(iter->first, *ctrl, duration);
 | 
				
			||||||
 | 
					                                updateGreetingState(iter->first, timerUpdateHello > 0);
 | 
				
			||||||
                                playIdleDialogue(iter->first);
 | 
					                                playIdleDialogue(iter->first);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
| 
						 | 
					@ -1554,6 +1668,7 @@ namespace MWMechanics
 | 
				
			||||||
            timerUpdateAITargets += duration;
 | 
					            timerUpdateAITargets += duration;
 | 
				
			||||||
            timerUpdateHeadTrack += duration;
 | 
					            timerUpdateHeadTrack += duration;
 | 
				
			||||||
            timerUpdateEquippedLight += duration;
 | 
					            timerUpdateEquippedLight += duration;
 | 
				
			||||||
 | 
					            timerUpdateHello += duration;
 | 
				
			||||||
            mTimerDisposeSummonsCorpses += duration;
 | 
					            mTimerDisposeSummonsCorpses += duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Animation/movement update
 | 
					            // Animation/movement update
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,6 +121,8 @@ namespace MWMechanics
 | 
				
			||||||
            void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer);
 | 
					            void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void playIdleDialogue(const MWWorld::Ptr& actor);
 | 
					            void playIdleDialogue(const MWWorld::Ptr& actor);
 | 
				
			||||||
 | 
					            void updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly);
 | 
				
			||||||
 | 
					            void turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
 | 
					            void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
 | 
				
			||||||
                                            MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
 | 
					                                            MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,11 +43,16 @@ namespace MWMechanics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
 | 
					    bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        auto& stats = actor.getClass().getCreatureStats(actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (stats.isTurningToPlayer() || stats.getGreetingState() == Greet_InProgress)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
 | 
					        const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
 | 
				
			||||||
        const osg::Vec3f targetPos(mX, mY, mZ);
 | 
					        const osg::Vec3f targetPos(mX, mY, mZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
 | 
					        stats.setMovementFlag(CreatureStats::Flag_Run, false);
 | 
				
			||||||
        actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
 | 
					        stats.setDrawState(DrawState_Nothing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!isWithinMaxRange(targetPos, actorPos))
 | 
					        if (!isWithinMaxRange(targetPos, actorPos))
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pathgrid.hpp"
 | 
					#include "pathgrid.hpp"
 | 
				
			||||||
#include "creaturestats.hpp"
 | 
					#include "creaturestats.hpp"
 | 
				
			||||||
#include "steering.hpp"
 | 
					 | 
				
			||||||
#include "movement.hpp"
 | 
					#include "movement.hpp"
 | 
				
			||||||
#include "coordinateconverter.hpp"
 | 
					#include "coordinateconverter.hpp"
 | 
				
			||||||
#include "actorutil.hpp"
 | 
					#include "actorutil.hpp"
 | 
				
			||||||
| 
						 | 
					@ -26,8 +25,6 @@ namespace MWMechanics
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static const int COUNT_BEFORE_RESET = 10;
 | 
					    static const int COUNT_BEFORE_RESET = 10;
 | 
				
			||||||
    static const float DOOR_CHECK_INTERVAL = 1.5f;
 | 
					    static const float DOOR_CHECK_INTERVAL = 1.5f;
 | 
				
			||||||
    static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
 | 
					 | 
				
			||||||
    static const int GREETING_SHOULD_END = 10;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // to prevent overcrowding
 | 
					    // to prevent overcrowding
 | 
				
			||||||
    static const int DESTINATION_TOLERANCE = 64;
 | 
					    static const int DESTINATION_TOLERANCE = 64;
 | 
				
			||||||
| 
						 | 
					@ -176,6 +173,17 @@ namespace MWMechanics
 | 
				
			||||||
                storage.setState(AiWanderStorage::Wander_Walking);
 | 
					                storage.setState(AiWanderStorage::Wander_Walking);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GreetingState greetingState = cStats.getGreetingState();
 | 
				
			||||||
 | 
					        if (greetingState == Greet_InProgress)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (storage.mState == AiWanderStorage::Wander_Walking)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                stopWalking(actor, storage, false);
 | 
				
			||||||
 | 
					                mObstacleCheck.clear();
 | 
				
			||||||
 | 
					                storage.setState(AiWanderStorage::Wander_IdleNow);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        doPerFrameActionsForState(actor, duration, storage);
 | 
					        doPerFrameActionsForState(actor, duration, storage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        float& lastReaction = storage.mReaction;
 | 
					        float& lastReaction = storage.mReaction;
 | 
				
			||||||
| 
						 | 
					@ -245,13 +253,7 @@ namespace MWMechanics
 | 
				
			||||||
        if(mDistance && cellChange)
 | 
					        if(mDistance && cellChange)
 | 
				
			||||||
            mDistance = 0;
 | 
					            mDistance = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Allow interrupting a walking actor to trigger a greeting
 | 
					 | 
				
			||||||
        AiWanderStorage::WanderState& wanderState = storage.mState;
 | 
					        AiWanderStorage::WanderState& wanderState = storage.mState;
 | 
				
			||||||
        if ((wanderState == AiWanderStorage::Wander_IdleNow) || (wanderState == AiWanderStorage::Wander_Walking))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            playGreetingIfPlayerGetsTooClose(actor, storage);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
 | 
					        if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Construct a new path if there isn't one
 | 
					            // Construct a new path if there isn't one
 | 
				
			||||||
| 
						 | 
					@ -416,19 +418,9 @@ namespace MWMechanics
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer;
 | 
					 | 
				
			||||||
        if (rotate)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // Reduce the turning animation glitch by using a *HUGE* value of
 | 
					 | 
				
			||||||
            // epsilon...  TODO: a proper fix might be in either the physics or the
 | 
					 | 
				
			||||||
            // animation subsystem
 | 
					 | 
				
			||||||
            if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f)))
 | 
					 | 
				
			||||||
                rotate = false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Check if idle animation finished
 | 
					        // Check if idle animation finished
 | 
				
			||||||
        AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
 | 
					        GreetingState greetingState = actor.getClass().getCreatureStats(actor).getGreetingState();
 | 
				
			||||||
        if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == AiWanderStorage::Greet_Done || greetingState == AiWanderStorage::Greet_None))
 | 
					        if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (mPathFinder.isPathConstructed())
 | 
					            if (mPathFinder.isPathConstructed())
 | 
				
			||||||
                storage.setState(AiWanderStorage::Wander_Walking);
 | 
					                storage.setState(AiWanderStorage::Wander_Walking);
 | 
				
			||||||
| 
						 | 
					@ -517,74 +509,7 @@ namespace MWMechanics
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Play a random voice greeting if the player gets too close
 | 
					 | 
				
			||||||
        int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
 | 
					 | 
				
			||||||
        float helloDistance = static_cast<float>(hello);
 | 
					 | 
				
			||||||
        static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
 | 
					 | 
				
			||||||
            .get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->mValue.getInteger();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        helloDistance *= iGreetDistanceMultiplier;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MWWorld::Ptr player = getPlayer();
 | 
					 | 
				
			||||||
        osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
 | 
					 | 
				
			||||||
        osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int& greetingTimer = storage.mGreetingTimer;
 | 
					 | 
				
			||||||
        AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
 | 
					 | 
				
			||||||
        if (greetingState == AiWanderStorage::Greet_None)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
 | 
					 | 
				
			||||||
                !player.getClass().getCreatureStats(player).isDead() && !actor.getClass().getCreatureStats(actor).isParalyzed()
 | 
					 | 
				
			||||||
                && MWBase::Environment::get().getWorld()->getLOS(player, actor)
 | 
					 | 
				
			||||||
                && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
 | 
					 | 
				
			||||||
                greetingTimer++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (greetingTimer >= GREETING_SHOULD_START)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                greetingState = AiWanderStorage::Greet_InProgress;
 | 
					 | 
				
			||||||
                MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
 | 
					 | 
				
			||||||
                greetingTimer = 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (greetingState == AiWanderStorage::Greet_InProgress)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            greetingTimer++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (storage.mState == AiWanderStorage::Wander_Walking)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                stopWalking(actor, storage, false);
 | 
					 | 
				
			||||||
                mObstacleCheck.clear();
 | 
					 | 
				
			||||||
                storage.setState(AiWanderStorage::Wander_IdleNow);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            turnActorToFacePlayer(actorPos, playerPos, storage);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (greetingTimer >= GREETING_SHOULD_END)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                greetingState = AiWanderStorage::Greet_Done;
 | 
					 | 
				
			||||||
                greetingTimer = 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (greetingState == AiWanderStorage::Greet_Done)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            float resetDist = 2 * helloDistance;
 | 
					 | 
				
			||||||
            if ((playerPos - actorPos).length2() >= resetDist*resetDist)
 | 
					 | 
				
			||||||
                greetingState = AiWanderStorage::Greet_None;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void AiWander::turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        osg::Vec3f dir = playerPosition - actorPosition;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        float faceAngleRadians = std::atan2(dir.x(), dir.y());
 | 
					 | 
				
			||||||
        storage.mTargetAngleRadians = faceAngleRadians;
 | 
					 | 
				
			||||||
        storage.mTurnActorGivingGreetingToFacePlayer = true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
 | 
					    void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,21 +25,8 @@ namespace MWMechanics
 | 
				
			||||||
    /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
 | 
					    /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive.
 | 
				
			||||||
    struct AiWanderStorage : AiTemporaryBase
 | 
					    struct AiWanderStorage : AiTemporaryBase
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // the z rotation angle to reach
 | 
					 | 
				
			||||||
        // when mTurnActorGivingGreetingToFacePlayer is true
 | 
					 | 
				
			||||||
        float mTargetAngleRadians;
 | 
					 | 
				
			||||||
        bool mTurnActorGivingGreetingToFacePlayer;
 | 
					 | 
				
			||||||
        float mReaction; // update some actions infrequently
 | 
					        float mReaction; // update some actions infrequently
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        enum GreetingState
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Greet_None,
 | 
					 | 
				
			||||||
            Greet_InProgress,
 | 
					 | 
				
			||||||
            Greet_Done
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        GreetingState mSaidGreeting;
 | 
					 | 
				
			||||||
        int mGreetingTimer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const MWWorld::CellStore* mCell; // for detecting cell change
 | 
					        const MWWorld::CellStore* mCell; // for detecting cell change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // AiWander states
 | 
					        // AiWander states
 | 
				
			||||||
| 
						 | 
					@ -72,11 +59,7 @@ namespace MWMechanics
 | 
				
			||||||
        int mStuckCount;
 | 
					        int mStuckCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        AiWanderStorage():
 | 
					        AiWanderStorage():
 | 
				
			||||||
            mTargetAngleRadians(0),
 | 
					 | 
				
			||||||
            mTurnActorGivingGreetingToFacePlayer(false),
 | 
					 | 
				
			||||||
            mReaction(0),
 | 
					            mReaction(0),
 | 
				
			||||||
            mSaidGreeting(Greet_None),
 | 
					 | 
				
			||||||
            mGreetingTimer(0),
 | 
					 | 
				
			||||||
            mCell(nullptr),
 | 
					            mCell(nullptr),
 | 
				
			||||||
            mState(Wander_ChooseAction),
 | 
					            mState(Wander_ChooseAction),
 | 
				
			||||||
            mIsWanderingManually(false),
 | 
					            mIsWanderingManually(false),
 | 
				
			||||||
| 
						 | 
					@ -136,7 +119,6 @@ namespace MWMechanics
 | 
				
			||||||
            bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
 | 
					            bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
 | 
				
			||||||
            short unsigned getRandomIdle();
 | 
					            short unsigned getRandomIdle();
 | 
				
			||||||
            void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
 | 
					            void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
 | 
				
			||||||
            void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage);
 | 
					 | 
				
			||||||
            void evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
 | 
					            void evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
 | 
				
			||||||
            void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
 | 
					            void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
 | 
				
			||||||
            void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
 | 
					            void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,12 +23,53 @@ namespace MWMechanics
 | 
				
			||||||
          mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false),
 | 
					          mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false),
 | 
				
			||||||
          mHitRecovery(false), mBlock(false), mMovementFlags(0),
 | 
					          mHitRecovery(false), mBlock(false), mMovementFlags(0),
 | 
				
			||||||
          mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1),
 | 
					          mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1),
 | 
				
			||||||
          mDeathAnimation(-1), mTimeOfDeath(), mLevel (0)
 | 
					          mDeathAnimation(-1), mTimeOfDeath(), mGreetingState(Greet_None),
 | 
				
			||||||
 | 
					          mGreetingTimer(0), mTargetAngleRadians(0), mIsTurningToPlayer(false), mLevel (0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        for (int i=0; i<4; ++i)
 | 
					        for (int i=0; i<4; ++i)
 | 
				
			||||||
            mAiSettings[i] = 0;
 | 
					            mAiSettings[i] = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int MWMechanics::CreatureStats::getGreetingTimer() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return mGreetingTimer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MWMechanics::CreatureStats::setGreetingTimer(int timer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mGreetingTimer = timer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    float MWMechanics::CreatureStats::getAngleToPlayer() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return mTargetAngleRadians;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MWMechanics::CreatureStats::setAngleToPlayer(float angle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mTargetAngleRadians = angle;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GreetingState MWMechanics::CreatureStats::getGreetingState() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return mGreetingState;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MWMechanics::CreatureStats::setGreetingState(GreetingState state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mGreetingState = state;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool MWMechanics::CreatureStats::isTurningToPlayer() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return mIsTurningToPlayer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MWMechanics::CreatureStats::setTurningToPlayer(bool turning)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        mIsTurningToPlayer = turning;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const AiSequence& CreatureStats::getAiSequence() const
 | 
					    const AiSequence& CreatureStats::getAiSequence() const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return mAiSequence;
 | 
					        return mAiSequence;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,13 @@ namespace ESM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MWMechanics
 | 
					namespace MWMechanics
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    enum GreetingState
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Greet_None,
 | 
				
			||||||
 | 
					        Greet_InProgress,
 | 
				
			||||||
 | 
					        Greet_Done
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// \brief Common creature stats
 | 
					    /// \brief Common creature stats
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
| 
						 | 
					@ -70,6 +77,11 @@ namespace MWMechanics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MWWorld::TimeStamp mTimeOfDeath;
 | 
					        MWWorld::TimeStamp mTimeOfDeath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GreetingState mGreetingState;
 | 
				
			||||||
 | 
					        int mGreetingTimer;
 | 
				
			||||||
 | 
					        float mTargetAngleRadians;
 | 
				
			||||||
 | 
					        bool mIsTurningToPlayer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        typedef std::pair<int, std::string> SummonKey; // <ESM::MagicEffect index, spell ID>
 | 
					        typedef std::pair<int, std::string> SummonKey; // <ESM::MagicEffect index, spell ID>
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
| 
						 | 
					@ -85,6 +97,18 @@ namespace MWMechanics
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        CreatureStats();
 | 
					        CreatureStats();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int getGreetingTimer() const;
 | 
				
			||||||
 | 
					        void setGreetingTimer(int timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        float getAngleToPlayer() const;
 | 
				
			||||||
 | 
					        void setAngleToPlayer(float angle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GreetingState getGreetingState() const;
 | 
				
			||||||
 | 
					        void setGreetingState(GreetingState state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool isTurningToPlayer() const;
 | 
				
			||||||
 | 
					        void setTurningToPlayer(bool turning);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DrawState_ getDrawState() const;
 | 
					        DrawState_ getDrawState() const;
 | 
				
			||||||
        void setDrawState(DrawState_ state);
 | 
					        void setDrawState(DrawState_ state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue