Make greeting-related actor data temporary (bug #5397)

pull/2860/head
Capostrophic 5 years ago
parent 505a5e9ca6
commit efd5f13b2b

@ -13,6 +13,7 @@
Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
Bug #5370: Opening an unlocked but trapped door uses the key Bug #5370: Opening an unlocked but trapped door uses the key
Bug #5397: NPC greeting does not reset if you leave + reenter area
Bug #5400: Editor: Verifier checks race of non-skin bodyparts Bug #5400: Editor: Verifier checks race of non-skin bodyparts
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
Bug #5416: Junk non-node records before the root node are not handled gracefully Bug #5416: Junk non-node records before the root node are not handled gracefully

@ -7,6 +7,9 @@
#include <set> #include <set>
#include <stdint.h> #include <stdint.h>
#include "../mwmechanics/actorutil.hpp"
// For MWMechanics::GreetingState
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
namespace osg namespace osg
@ -272,6 +275,11 @@ namespace MWBase
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;
virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const = 0;
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
}; };
} }

@ -18,4 +18,44 @@ namespace MWMechanics
{ {
return mCharacterController.get(); return mCharacterController.get();
} }
int Actor::getGreetingTimer() const
{
return mGreetingTimer;
}
void Actor::setGreetingTimer(int timer)
{
mGreetingTimer = timer;
}
float Actor::getAngleToPlayer() const
{
return mTargetAngleRadians;
}
void Actor::setAngleToPlayer(float angle)
{
mTargetAngleRadians = angle;
}
GreetingState Actor::getGreetingState() const
{
return mGreetingState;
}
void Actor::setGreetingState(GreetingState state)
{
mGreetingState = state;
}
bool Actor::isTurningToPlayer() const
{
return mIsTurningToPlayer;
}
void Actor::setTurningToPlayer(bool turning)
{
mIsTurningToPlayer = turning;
}
} }

@ -3,6 +3,8 @@
#include <memory> #include <memory>
#include "../mwmechanics/actorutil.hpp"
namespace MWRender namespace MWRender
{ {
class Animation; class Animation;
@ -27,8 +29,24 @@ namespace MWMechanics
CharacterController* getCharacterController(); CharacterController* getCharacterController();
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);
private: private:
std::unique_ptr<CharacterController> mCharacterController; std::unique_ptr<CharacterController> mCharacterController;
int mGreetingTimer{0};
float mTargetAngleRadians{0.f};
GreetingState mGreetingState{Greet_None};
bool mIsTurningToPlayer{false};
}; };
} }

@ -447,7 +447,7 @@ namespace MWMechanics
actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor; actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor;
} }
void Actors::updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly) void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly)
{ {
if (!actor.getClass().isActor() || actor == getPlayer()) if (!actor.getClass().isActor() || actor == getPlayer())
return; return;
@ -460,9 +460,9 @@ namespace MWMechanics
MWBase::Environment::get().getWorld()->isSwimming(actor) || MWBase::Environment::get().getWorld()->isSwimming(actor) ||
(packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1)) (packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1))
{ {
stats.setTurningToPlayer(false); actorState->setTurningToPlayer(false);
stats.setGreetingTimer(0); actorState->setGreetingTimer(0);
stats.setGreetingState(Greet_None); actorState->setGreetingState(Greet_None);
return; return;
} }
@ -471,14 +471,14 @@ namespace MWMechanics
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
osg::Vec3f dir = playerPos - actorPos; osg::Vec3f dir = playerPos - actorPos;
if (stats.isTurningToPlayer()) if (actorState->isTurningToPlayer())
{ {
// Reduce the turning animation glitch by using a *HUGE* value of // Reduce the turning animation glitch by using a *HUGE* value of
// epsilon... TODO: a proper fix might be in either the physics or the // epsilon... TODO: a proper fix might be in either the physics or the
// animation subsystem // animation subsystem
if (zTurn(actor, stats.getAngleToPlayer(), osg::DegreesToRadians(5.f))) if (zTurn(actor, actorState->getAngleToPlayer(), osg::DegreesToRadians(5.f)))
{ {
stats.setTurningToPlayer(false); actorState->setTurningToPlayer(false);
// An original engine launches an endless idle2 when an actor greets player. // An original engine launches an endless idle2 when an actor greets player.
playAnimationGroup (actor, "idle2", 0, std::numeric_limits<int>::max(), false); playAnimationGroup (actor, "idle2", 0, std::numeric_limits<int>::max(), false);
} }
@ -493,8 +493,8 @@ namespace MWMechanics
float helloDistance = static_cast<float>(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier); float helloDistance = static_cast<float>(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier);
int greetingTimer = stats.getGreetingTimer(); int greetingTimer = actorState->getGreetingTimer();
GreetingState greetingState = stats.getGreetingState(); GreetingState greetingState = actorState->getGreetingState();
if (greetingState == Greet_None) if (greetingState == Greet_None)
{ {
if ((playerPos - actorPos).length2() <= helloDistance*helloDistance && if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
@ -516,7 +516,7 @@ namespace MWMechanics
greetingTimer++; greetingTimer++;
if (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor)) if (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor))
turnActorToFacePlayer(actor, dir); turnActorToFacePlayer(actor, actorState, dir);
if (greetingTimer >= GREETING_COOLDOWN) if (greetingTimer >= GREETING_COOLDOWN)
{ {
@ -532,20 +532,19 @@ namespace MWMechanics
greetingState = Greet_None; greetingState = Greet_None;
} }
stats.setGreetingTimer(greetingTimer); actorState->setGreetingTimer(greetingTimer);
stats.setGreetingState(greetingState); actorState->setGreetingState(greetingState);
} }
void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir) void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, const osg::Vec3f& dir)
{ {
actor.getClass().getMovementSettings(actor).mPosition[1] = 0; actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
actor.getClass().getMovementSettings(actor).mPosition[0] = 0; actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
CreatureStats &stats = actor.getClass().getCreatureStats(actor); if (!actorState->isTurningToPlayer())
if (!stats.isTurningToPlayer())
{ {
stats.setAngleToPlayer(std::atan2(dir.x(), dir.y())); actorState->setAngleToPlayer(std::atan2(dir.x(), dir.y()));
stats.setTurningToPlayer(true); actorState->setTurningToPlayer(true);
} }
} }
@ -1695,7 +1694,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); updateGreetingState(iter->first, iter->second, timerUpdateHello > 0);
playIdleDialogue(iter->first); playIdleDialogue(iter->first);
updateMovementSpeed(iter->first); updateMovementSpeed(iter->first);
} }
@ -2390,6 +2389,42 @@ namespace MWMechanics
return ctrl->isAttackingOrSpell(); return ctrl->isAttackingOrSpell();
} }
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const
{
PtrActorMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end())
return 0;
return it->second->getGreetingTimer();
}
float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const
{
PtrActorMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end())
return 0.f;
return it->second->getAngleToPlayer();
}
GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const
{
PtrActorMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end())
return Greet_None;
return it->second->getGreetingState();
}
bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const
{
PtrActorMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end())
return false;
return it->second->isTurningToPlayer();
}
void Actors::fastForwardAi() void Actors::fastForwardAi()
{ {
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())

@ -7,6 +7,8 @@
#include <list> #include <list>
#include <map> #include <map>
#include "../mwmechanics/actorutil.hpp"
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
@ -123,8 +125,8 @@ namespace MWMechanics
void playIdleDialogue(const MWWorld::Ptr& actor); void playIdleDialogue(const MWWorld::Ptr& actor);
void updateMovementSpeed(const MWWorld::Ptr& actor); void updateMovementSpeed(const MWWorld::Ptr& actor);
void updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly); void updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly);
void turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir); void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, 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);
@ -195,6 +197,11 @@ namespace MWMechanics
bool isReadyToBlock(const MWWorld::Ptr& ptr) const; bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
int getGreetingTimer(const MWWorld::Ptr& ptr) const;
float getAngleToPlayer(const MWWorld::Ptr& ptr) const;
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const;
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const;
private: private:
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl); void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);

@ -8,6 +8,13 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
enum GreetingState
{
Greet_None,
Greet_InProgress,
Greet_Done
};
MWWorld::Ptr getPlayer(); MWWorld::Ptr getPlayer();
bool isPlayerInCombat(); bool isPlayerInCombat();
bool canActorMoveByZAxis(const MWWorld::Ptr& actor); bool canActorMoveByZAxis(const MWWorld::Ptr& actor);

@ -3,6 +3,7 @@
#include <components/esm/aisequence.hpp> #include <components/esm/aisequence.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -43,14 +44,15 @@ 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); MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager();
if (stats.isTurningToPlayer() || stats.getGreetingState() == Greet_InProgress) if (mechMgr->isTurningToPlayer(actor) || mechMgr->getGreetingState(actor) == Greet_InProgress)
return false; 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);
auto& stats = actor.getClass().getCreatureStats(actor);
stats.setMovementFlag(CreatureStats::Flag_Run, false); stats.setMovementFlag(CreatureStats::Flag_Run, false);
stats.setDrawState(DrawState_Nothing); stats.setDrawState(DrawState_Nothing);

@ -206,7 +206,7 @@ namespace MWMechanics
storage.setState(AiWanderStorage::Wander_Walking); storage.setState(AiWanderStorage::Wander_Walking);
} }
GreetingState greetingState = cStats.getGreetingState(); GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor);
if (greetingState == Greet_InProgress) if (greetingState == Greet_InProgress)
{ {
if (storage.mState == AiWanderStorage::Wander_Walking) if (storage.mState == AiWanderStorage::Wander_Walking)
@ -442,7 +442,7 @@ namespace MWMechanics
} }
// Check if idle animation finished // Check if idle animation finished
GreetingState greetingState = actor.getClass().getCreatureStats(actor).getGreetingState(); GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor);
if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None))
{ {
if (mPathFinder.isPathConstructed()) if (mPathFinder.isPathConstructed())

@ -23,53 +23,12 @@ 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(), mGreetingState(Greet_None), mDeathAnimation(-1), mTimeOfDeath(), mLevel (0)
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,13 +19,6 @@ namespace ESM
namespace MWMechanics namespace MWMechanics
{ {
enum GreetingState
{
Greet_None,
Greet_InProgress,
Greet_Done
};
/// \brief Common creature stats /// \brief Common creature stats
/// ///
/// ///
@ -77,11 +70,6 @@ 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:
@ -97,18 +85,6 @@ 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);

@ -1951,4 +1951,24 @@ namespace MWMechanics
stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size()); stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size());
stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size()); stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size());
} }
int MechanicsManager::getGreetingTimer(const MWWorld::Ptr &ptr) const
{
return mActors.getGreetingTimer(ptr);
}
float MechanicsManager::getAngleToPlayer(const MWWorld::Ptr &ptr) const
{
return mActors.getAngleToPlayer(ptr);
}
GreetingState MechanicsManager::getGreetingState(const MWWorld::Ptr &ptr) const
{
return mActors.getGreetingState(ptr);
}
bool MechanicsManager::isTurningToPlayer(const MWWorld::Ptr &ptr) const
{
return mActors.isTurningToPlayer(ptr);
}
} }

@ -242,6 +242,11 @@ namespace MWMechanics
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const override;
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const override;
virtual GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
private: private:
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers); bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers);

@ -430,13 +430,13 @@ namespace MWScript
if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId) if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId)
targetsAreEqual = true; targetsAreEqual = true;
} }
else else if (testedTargetId == "player") // Currently the player ID is hardcoded
{ {
bool turningToPlayer = creatureStats.isTurningToPlayer(); MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager();
bool greeting = creatureStats.getGreetingState() == MWMechanics::Greet_InProgress; bool greeting = mechMgr->getGreetingState(actor) == MWMechanics::Greet_InProgress;
bool sayActive = MWBase::Environment::get().getSoundManager()->sayActive(actor); bool sayActive = MWBase::Environment::get().getSoundManager()->sayActive(actor);
if (turningToPlayer || (greeting && sayActive)) if ((greeting && sayActive) || mechMgr->isTurningToPlayer(actor))
targetsAreEqual = (testedTargetId == "player"); // Currently the player ID is hardcoded targetsAreEqual = true;
} }
runtime.push(int(targetsAreEqual)); runtime.push(int(targetsAreEqual));
} }

Loading…
Cancel
Save