mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 06:23:52 +00:00
Merge pull request #2126 from Capostrophic/sneaking
Account for running/sneaking stances while in air (bug #4797)
This commit is contained in:
commit
4d09c8bb50
4 changed files with 98 additions and 74 deletions
|
@ -20,6 +20,7 @@
|
||||||
Bug #4768: Fallback numerical value recovery chokes on invalid arguments
|
Bug #4768: Fallback numerical value recovery chokes on invalid arguments
|
||||||
Bug #4775: Slowfall effect resets player jumping flag
|
Bug #4775: Slowfall effect resets player jumping flag
|
||||||
Bug #4778: Interiors of Illusion puzzle in Sotha Sil Expanded mod is broken
|
Bug #4778: Interiors of Illusion puzzle in Sotha Sil Expanded mod is broken
|
||||||
|
Bug #4797: Player sneaking and running stances are not accounted for when in air
|
||||||
Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change
|
Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change
|
||||||
Bug #4803: Stray special characters before begin statement break script compilation
|
Bug #4803: Stray special characters before begin statement break script compilation
|
||||||
Bug #4804: Particle system with the "Has Sizes = false" causes an exception
|
Bug #4804: Particle system with the "Has Sizes = false" causes an exception
|
||||||
|
|
|
@ -1543,72 +1543,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
killDeadActors();
|
killDeadActors();
|
||||||
|
updateSneaking(playerCharacter, duration);
|
||||||
static float sneakTimer = 0.f; // times update of sneak icon
|
|
||||||
|
|
||||||
// if player is in sneak state see if anyone detects him
|
|
||||||
if (playerCharacter && playerCharacter->isSneaking())
|
|
||||||
{
|
|
||||||
static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice"
|
|
||||||
|
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
|
||||||
const int radius = esmStore.get<ESM::GameSetting>().find("fSneakUseDist")->mValue.getInteger();
|
|
||||||
|
|
||||||
static float fSneakUseDelay = esmStore.get<ESM::GameSetting>().find("fSneakUseDelay")->mValue.getFloat();
|
|
||||||
|
|
||||||
if (sneakTimer >= fSneakUseDelay)
|
|
||||||
sneakTimer = 0.f;
|
|
||||||
|
|
||||||
if (sneakTimer == 0.f)
|
|
||||||
{
|
|
||||||
// Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress.
|
|
||||||
bool avoidedNotice = false;
|
|
||||||
|
|
||||||
bool detected = false;
|
|
||||||
|
|
||||||
for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr observer = iter->first;
|
|
||||||
|
|
||||||
if (iter->first == player) // not the player
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (observer.getClass().getCreatureStats(observer).isDead())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// is the player in range and can they be detected
|
|
||||||
if ((observer.getRefData().getPosition().asVec3() - playerPos).length2() <= radius*radius
|
|
||||||
&& MWBase::Environment::get().getWorld()->getLOS(player, observer))
|
|
||||||
{
|
|
||||||
if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer))
|
|
||||||
{
|
|
||||||
detected = true;
|
|
||||||
avoidedNotice = false;
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
avoidedNotice = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sneakSkillTimer >= fSneakUseDelay)
|
|
||||||
sneakSkillTimer = 0.f;
|
|
||||||
|
|
||||||
if (avoidedNotice && sneakSkillTimer == 0.f)
|
|
||||||
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0);
|
|
||||||
|
|
||||||
if (!detected)
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(true);
|
|
||||||
}
|
|
||||||
sneakTimer += duration;
|
|
||||||
sneakSkillTimer += duration;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sneakTimer = 0.f;
|
|
||||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCombatMusic();
|
updateCombatMusic();
|
||||||
|
@ -1757,6 +1692,86 @@ namespace MWMechanics
|
||||||
fastForwardAi();
|
fastForwardAi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actors::updateSneaking(CharacterController* ctrl, float duration)
|
||||||
|
{
|
||||||
|
static float sneakTimer = 0.f; // Times update of sneak icon
|
||||||
|
|
||||||
|
if (!ctrl)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
|
CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
|
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||||
|
bool inair = !world->isOnGround(player) && !world->isSwimming(player) && !world->isFlying(player);
|
||||||
|
sneaking = sneaking && (ctrl->isSneaking() || inair);
|
||||||
|
|
||||||
|
if (!sneaking)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sneakSkillTimer = 0.f; // Times sneak skill progress from "avoid notice"
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
|
static const float fSneakUseDist = gmst.find("fSneakUseDist")->mValue.getFloat();
|
||||||
|
static const float fSneakUseDelay = gmst.find("fSneakUseDelay")->mValue.getFloat();
|
||||||
|
|
||||||
|
if (sneakTimer >= fSneakUseDelay)
|
||||||
|
sneakTimer = 0.f;
|
||||||
|
|
||||||
|
if (sneakTimer == 0.f)
|
||||||
|
{
|
||||||
|
// Set when an NPC is within line of sight and distance, but is still unaware. Used for skill progress.
|
||||||
|
bool avoidedNotice = false;
|
||||||
|
bool detected = false;
|
||||||
|
|
||||||
|
std::vector<MWWorld::Ptr> observers;
|
||||||
|
osg::Vec3f position(player.getRefData().getPosition().asVec3());
|
||||||
|
float radius = std::min(fSneakUseDist, mActorsProcessingRange);
|
||||||
|
getObjectsInRange(position, radius, observers);
|
||||||
|
|
||||||
|
for (const MWWorld::Ptr &observer : observers)
|
||||||
|
{
|
||||||
|
if (observer == player || observer.getClass().getCreatureStats(observer).isDead())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (world->getLOS(player, observer))
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, observer))
|
||||||
|
{
|
||||||
|
detected = true;
|
||||||
|
avoidedNotice = false;
|
||||||
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
avoidedNotice = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sneakSkillTimer >= fSneakUseDelay)
|
||||||
|
sneakSkillTimer = 0.f;
|
||||||
|
|
||||||
|
if (avoidedNotice && sneakSkillTimer == 0.f)
|
||||||
|
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 0);
|
||||||
|
|
||||||
|
if (!detected)
|
||||||
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
sneakTimer += duration;
|
||||||
|
sneakSkillTimer += duration;
|
||||||
|
}
|
||||||
|
|
||||||
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
|
int Actors::getHoursToRest(const MWWorld::Ptr &ptr) const
|
||||||
{
|
{
|
||||||
float healthPerHour, magickaPerHour;
|
float healthPerHour, magickaPerHour;
|
||||||
|
|
|
@ -122,6 +122,9 @@ namespace MWMechanics
|
||||||
void rest(bool sleep);
|
void rest(bool sleep);
|
||||||
///< Update actors while the player is waiting or sleeping. This should be called every hour.
|
///< Update actors while the player is waiting or sleeping. This should be called every hour.
|
||||||
|
|
||||||
|
void updateSneaking(CharacterController* ctrl, float duration);
|
||||||
|
///< Update the sneaking indicator state according to the given player character controller.
|
||||||
|
|
||||||
void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep);
|
void restoreDynamicStats(const MWWorld::Ptr& actor, bool sleep);
|
||||||
|
|
||||||
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
|
||||||
|
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
#include "ref.hpp"
|
#include "ref.hpp"
|
||||||
|
@ -168,12 +167,15 @@ namespace MWScript
|
||||||
|
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
const MWWorld::Class &cls = ptr.getClass();
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
bool isRunning = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
|
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||||
|
bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
|
||||||
|
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
||||||
|
|
||||||
runtime.push (isRunning && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run));
|
runtime.push(stanceOn && (running || inair));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,11 +186,14 @@ namespace MWScript
|
||||||
virtual void execute (Interpreter::Runtime& runtime)
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
const MWWorld::Class &cls = ptr.getClass();
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
bool isSneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||||
|
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
||||||
|
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
||||||
|
|
||||||
runtime.push (isSneaking && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak));
|
runtime.push(stanceOn && (sneaking || inair));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue