1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-03 18:15:35 +00:00

Merged pull request #1932

This commit is contained in:
Marc Zinnschlag 2018-09-24 11:57:08 +02:00
commit 6ce6108eb4
2 changed files with 52 additions and 50 deletions

View file

@ -501,12 +501,6 @@ namespace MWMechanics
} }
} }
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration)
{
updateDrowning(ptr, duration);
calculateNpcStatModifiers(ptr, duration);
}
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
{ {
CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature); CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature);
@ -926,13 +920,8 @@ namespace MWMechanics
return ctrl->isSneaking(); return ctrl->isSneaking();
} }
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer)
{ {
PtrActorMap::iterator it = mActors.find(ptr);
if (it == mActors.end())
return;
CharacterController* ctrl = it->second->getCharacterController();
NpcStats &stats = ptr.getClass().getNpcStats(ptr); NpcStats &stats = ptr.getClass().getNpcStats(ptr);
// When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST // When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST
@ -940,9 +929,10 @@ namespace MWMechanics
if (stats.getTimeToStartDrowning() == -1.f) if (stats.getTimeToStartDrowning() == -1.f)
stats.setTimeToStartDrowning(fHoldBreathTime); stats.setTimeToStartDrowning(fHoldBreathTime);
if (ptr.getClass().isNpc() && stats.getTimeToStartDrowning() < fHoldBreathTime / 2) if (stats.getTimeToStartDrowning() < fHoldBreathTime / 2)
{ {
if(ptr != MWMechanics::getPlayer() ) { if(!isPlayer)
{
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once
seq.stack(MWMechanics::AiBreathe(), ptr); seq.stack(MWMechanics::AiBreathe(), ptr);
@ -950,7 +940,7 @@ namespace MWMechanics
} }
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); bool knockedOutUnderwater = (isKnockedOut && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3())));
if((world->isSubmerged(ptr) || knockedOutUnderwater) if((world->isSubmerged(ptr) || knockedOutUnderwater)
&& stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0) && stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0)
{ {
@ -965,7 +955,7 @@ namespace MWMechanics
stats.setTimeToStartDrowning(timeLeft); stats.setTimeToStartDrowning(timeLeft);
} }
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
if(timeLeft == 0.0f && !godmode) if(timeLeft == 0.0f && !godmode)
{ {
@ -980,7 +970,7 @@ namespace MWMechanics
if(!sndmgr->getSoundPlaying(ptr, "drown")) if(!sndmgr->getSoundPlaying(ptr, "drown"))
sndmgr->playSound3D(ptr, "drown", 1.0f, 1.0f); sndmgr->playSound3D(ptr, "drown", 1.0f, 1.0f);
if(ptr == world->getPlayerPtr()) if(isPlayer)
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
} }
} }
@ -1242,21 +1232,24 @@ namespace MWMechanics
void Actors::updateCombatMusic () void Actors::updateCombatMusic ()
{ {
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
int hostilesCount = 0; // need to know this to play Battle music const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
bool hasHostiles = false; // need to know this to play Battle music
bool aiActive = MWBase::Environment::get().getMechanicsManager()->isAIActive();
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) if (aiActive)
{ {
if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() if (iter->first == player) continue;
<= sqrAiProcessingDistance;
if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) bool inProcessingRange = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrAiProcessingDistance;
if (inProcessingRange)
{ {
if (iter->first != player) MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
if (!stats.isDead() && stats.getAiSequence().isInCombat())
{ {
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); hasHostiles = true;
if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; break;
} }
} }
} }
@ -1265,13 +1258,13 @@ namespace MWMechanics
// check if we still have any player enemies to switch music // check if we still have any player enemies to switch music
static int currentMusic = 0; static int currentMusic = 0;
if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && if (currentMusic != 1 && !hasHostiles && !(player.getClass().getCreatureStats(player).isDead() &&
MWBase::Environment::get().getSoundManager()->isMusicPlaying())) MWBase::Environment::get().getSoundManager()->isMusicPlaying()))
{ {
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
currentMusic = 1; currentMusic = 1;
} }
else if (currentMusic != 2 && hostilesCount > 0) else if (currentMusic != 2 && hasHostiles)
{ {
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
currentMusic = 2; currentMusic = 2;
@ -1298,17 +1291,29 @@ namespace MWMechanics
bool showTorches = MWBase::Environment::get().getWorld()->useTorches(); bool showTorches = MWBase::Environment::get().getWorld()->useTorches();
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
/// \todo move update logic to Actor class where appropriate /// \todo move update logic to Actor class where appropriate
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> > cachedAllies; // will be filled as engageCombat iterates std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> > cachedAllies; // will be filled as engageCombat iterates
bool aiActive = MWBase::Environment::get().getMechanicsManager()->isAIActive();
int attackedByPlayerId = player.getClass().getCreatureStats(player).getHitAttemptActorId();
if (attackedByPlayerId != -1)
{
const MWWorld::Ptr playerHitAttemptActor = MWBase::Environment::get().getWorld()->searchPtrViaActorId(attackedByPlayerId);
if (!playerHitAttemptActor.isInCell())
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
}
// AI and magic effects update // AI and magic effects update
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
bool isPlayer = iter->first == player; bool isPlayer = iter->first == player;
CharacterController* ctrl = iter->second->getCharacterController();
float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2(); float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not) // (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
// This distance could be made configurable later, but the setting must be marked with a big warning: // This distance could be made configurable later, but the setting must be marked with a big warning:
@ -1316,7 +1321,7 @@ namespace MWMechanics
bool inProcessingRange = distSqr <= sqrAiProcessingDistance; bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
if (isPlayer) if (isPlayer)
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell()); ctrl->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player. // If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead() if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
@ -1328,11 +1333,6 @@ namespace MWMechanics
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1); player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
} }
const MWWorld::Ptr playerHitAttemptActor = MWBase::Environment::get().getWorld()->searchPtrViaActorId(player.getClass().getCreatureStats(player).getHitAttemptActorId());
if (!playerHitAttemptActor.isInCell())
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
{ {
bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged(); bool cellChanged = MWBase::Environment::get().getWorld()->hasCellChanged();
@ -1343,7 +1343,7 @@ namespace MWMechanics
return; // for now abort update of the old cell when cell changes by teleportation magic effect return; // for now abort update of the old cell when cell changes by teleportation magic effect
// a better solution might be to apply cell changes at the end of the frame // a better solution might be to apply cell changes at the end of the frame
} }
if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) if (aiActive && inProcessingRange)
{ {
if (timerUpdateAITargets == 0) if (timerUpdateAITargets == 0)
{ {
@ -1381,7 +1381,7 @@ namespace MWMechanics
} }
} }
iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); ctrl->setHeadTrackTarget(headTrackTarget);
} }
if (iter->first.getClass().isNpc() && iter->first != player) if (iter->first.getClass().isNpc() && iter->first != player)
@ -1391,13 +1391,14 @@ namespace MWMechanics
{ {
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
if (isConscious(iter->first)) if (isConscious(iter->first))
stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), duration); stats.getAiSequence().execute(iter->first, *ctrl, duration);
} }
} }
if(iter->first.getTypeName() == typeid(ESM::NPC).name()) if(iter->first.getTypeName() == typeid(ESM::NPC).name())
{ {
updateNpc(iter->first, duration); updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer);
calculateNpcStatModifiers(iter->first, duration);
if (timerUpdateEquippedLight == 0) if (timerUpdateEquippedLight == 0)
updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches); updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches);
@ -1423,7 +1424,7 @@ namespace MWMechanics
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation. const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation.
const float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2(); const float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
bool isPlayer = iter->first == player; bool isPlayer = iter->first == player;
bool inAnimationRange = isPlayer || (animationDistance == 0 || distSqr <= animationDistance*animationDistance); bool inAnimationRange = isPlayer || (animationDistance == 0 || distSqr <= animationDistance*animationDistance);
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower) int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
@ -1437,22 +1438,24 @@ namespace MWMechanics
inAnimationRange = true; inAnimationRange = true;
active = std::max(1, active); active = std::max(1, active);
} }
iter->second->getCharacterController()->setActive(active);
CharacterController* ctrl = iter->second->getCharacterController();
ctrl->setActive(active);
if (!inAnimationRange) if (!inAnimationRange)
continue; continue;
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
iter->second->getCharacterController()->skipAnim(); ctrl->skipAnim();
// Handle player last, in case a cell transition occurs by casting a teleportation spell // Handle player last, in case a cell transition occurs by casting a teleportation spell
// (would invalidate the iterator) // (would invalidate the iterator)
if (iter->first == getPlayer()) if (iter->first == getPlayer())
{ {
playerCharacter = iter->second->getCharacterController(); playerCharacter = ctrl;
continue; continue;
} }
iter->second->getCharacterController()->update(duration); ctrl->update(duration);
} }
if (playerCharacter) if (playerCharacter)
@ -1512,7 +1515,7 @@ namespace MWMechanics
continue; continue;
// is the player in range and can they be detected // is the player in range and can they be detected
if ((observer.getRefData().getPosition().asVec3() - player.getRefData().getPosition().asVec3()).length2() <= radius*radius if ((observer.getRefData().getPosition().asVec3() - playerPos).length2() <= radius*radius
&& MWBase::Environment::get().getWorld()->getLOS(player, observer)) && MWBase::Environment::get().getWorld()->getLOS(player, observer))
{ {
if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer)) if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer))
@ -1656,7 +1659,8 @@ namespace MWMechanics
void Actors::rest(bool sleep) void Actors::rest(bool sleep)
{ {
float duration = 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor(); float duration = 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
@ -1666,7 +1670,7 @@ namespace MWMechanics
restoreDynamicStats(iter->first, sleep); restoreDynamicStats(iter->first, sleep);
if ((!iter->first.getRefData().getBaseNode()) || if ((!iter->first.getRefData().getBaseNode()) ||
(player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance) (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance)
continue; continue;
adjustMagicEffects (iter->first); adjustMagicEffects (iter->first);

View file

@ -28,8 +28,6 @@ namespace MWMechanics
void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void addBoundItem (const std::string& itemId, const MWWorld::Ptr& actor);
void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor); void removeBoundItem (const std::string& itemId, const MWWorld::Ptr& actor);
void updateNpc(const MWWorld::Ptr &ptr, float duration);
void adjustMagicEffects (const MWWorld::Ptr& creature); void adjustMagicEffects (const MWWorld::Ptr& creature);
void calculateDynamicStats (const MWWorld::Ptr& ptr); void calculateDynamicStats (const MWWorld::Ptr& ptr);
@ -39,7 +37,7 @@ namespace MWMechanics
void calculateRestoration (const MWWorld::Ptr& ptr, float duration); void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
void updateDrowning (const MWWorld::Ptr& ptr, float duration); void updateDrowning (const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer);
void updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip); void updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip);