Merge pull request #148 from OpenMW/master

Add OpenMW commits up to 13 Feb 2017
pull/163/head
David Cernat 8 years ago committed by GitHub
commit a5d7c5fd39

@ -90,6 +90,7 @@ Programmers
Mark Siewert (mark76)
Marco Melletti (mellotanica)
Marco Schulze
MAtahualpa
Mateusz Kołaczek (PL_kolek)
Mateusz Malisz (malice)
megaton

@ -494,7 +494,7 @@ void Record<ESM::Book>::print()
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
std::cout << " Value: " << mData.mData.mValue << std::endl;
std::cout << " IsScroll: " << mData.mData.mIsScroll << std::endl;
std::cout << " SkillID: " << mData.mData.mSkillID << std::endl;
std::cout << " SkillId: " << mData.mData.mSkillId << std::endl;
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
if (mPrintPlain)
{

@ -202,7 +202,7 @@ public:
bool isDeleted = false;
book.load(esm, isDeleted);
if (book.mData.mSkillID == -1)
if (book.mData.mSkillId == -1)
mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId));
mRecords[book.mId] = book;

@ -316,7 +316,7 @@ QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column,
return record.get().mData.mIsScroll!=0;
if (column==mSkill)
return record.get().mData.mSkillID;
return record.get().mData.mSkillId;
if (column==mText)
return QString::fromUtf8 (record.get().mText.c_str());
@ -335,7 +335,7 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
if (column==mScroll)
book.mData.mIsScroll = value.toInt();
else if (column==mSkill)
book.mData.mSkillID = value.toInt();
book.mData.mSkillId = value.toInt();
else if (column==mText)
book.mText = value.toString().toUtf8().data();
else

@ -294,8 +294,8 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scroll, ColumnBase::Display_Boolean));
const RefIdColumn *scroll = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
const RefIdColumn *attribute = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
const RefIdColumn *skill = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString));
const RefIdColumn *text = &mColumns.back();
@ -659,7 +659,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mAdapters.insert (std::make_pair (UniversalId::Type_Armor,
new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef)));
mAdapters.insert (std::make_pair (UniversalId::Type_Book,
new BookRefIdAdapter (enchantableColumns, scroll, attribute, text)));
new BookRefIdAdapter (enchantableColumns, scroll, skill, text)));
mAdapters.insert (std::make_pair (UniversalId::Type_Clothing,
new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef)));
mAdapters.insert (std::make_pair (UniversalId::Type_Container,

@ -255,7 +255,7 @@ namespace MWBase
/// Returns a pointer to the object the provided object would hit (if within the
/// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance) = 0;
virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &targets) = 0;
virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0;
///< Adjust position after load to be on ground. Must be called after model load.

@ -249,7 +249,12 @@ namespace MWClass
if (!weapon.isEmpty())
dist *= weapon.get<ESM::Weapon>()->mBase->mData.mReach;
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist);
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors;
if (!ptr.isEmpty() && ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
ptr.getClass().getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist, targetActors);
if (result.first.isEmpty())
return; // Didn't hit anything

@ -574,8 +574,13 @@ namespace MWClass
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat());
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors;
if (!ptr.isEmpty() && ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
ptr.getClass().getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
// TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist);
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors);
MWWorld::Ptr victim = result.first;
osg::Vec3f hitPosition(result.second);
if (victim.isEmpty()) // Didn't hit anything

@ -75,6 +75,17 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
return !targetActor.isEmpty();
}
bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
{
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCombat)
targetActors.push_back((*it)->getTarget());
}
return !targetActors.empty();
}
std::list<AiPackage*>::const_iterator AiSequence::begin() const
{
return mPackages.begin();

@ -79,6 +79,9 @@ namespace MWMechanics
/// Return true and assign target if combat package is currently active, return false otherwise
bool getCombatTarget (MWWorld::Ptr &targetActor) const;
/// Return true and assign targets for all combat packages, or return false if there are no combat packages
bool getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const;
/// Is there any combat package?
bool isInCombat () const;

@ -29,8 +29,7 @@ void Objects::addObject(const MWWorld::Ptr& ptr)
removeObject(ptr);
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if (anim && anim->hasAnimSources())
mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
if(anim) mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
}
void Objects::removeObject(const MWWorld::Ptr& ptr)

@ -417,10 +417,6 @@ namespace MWMechanics
float magnitudeMult = 1;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
{
// Notify the target actor they've been hit
if (target != caster && !caster.isEmpty())
target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
if (absorbed)
continue;
@ -453,6 +449,10 @@ namespace MWMechanics
// If player is attempting to cast a harmful spell, show the target's HP bar
if (castByPlayer && target != caster)
MWBase::Environment::get().getWindowManager()->setEnemy(target);
// Notify the target actor they've been hit
if (target != caster && !caster.isEmpty())
target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
}
if (magnitudeMult > 0 && !absorbed)

@ -798,6 +798,7 @@ namespace MWPhysics
class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback
{
const btCollisionObject* mMe;
const std::vector<const btCollisionObject*> mTargets;
// Store the real origin, since the shape's origin is its center
btVector3 mOrigin;
@ -807,8 +808,8 @@ namespace MWPhysics
btVector3 mContactPoint;
btScalar mLeastDistSqr;
DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const btVector3 &origin)
: mMe(me), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0),
DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector<const btCollisionObject*> targets, const btVector3 &origin)
: mMe(me), mTargets(targets), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0),
mLeastDistSqr(std::numeric_limits<float>::max())
{ }
@ -819,6 +820,16 @@ namespace MWPhysics
const btCollisionObject* collisionObject = col1Wrap->m_collisionObject;
if (collisionObject != mMe)
{
if (!mTargets.empty())
{
if ((std::find(mTargets.begin(), mTargets.end(), collisionObject) == mTargets.end()))
{
PtrHolder* holder = static_cast<PtrHolder*>(collisionObject->getUserPointer());
if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor())
return 0.f;
}
}
btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
if(!mObject || distsqr < mLeastDistSqr)
{
@ -835,7 +846,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin,
const osg::Quat &orient,
float queryDistance)
float queryDistance, std::vector<MWWorld::Ptr> targets)
{
const MWWorld::Store<ESM::GameSetting> &store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
@ -852,11 +863,23 @@ namespace MWPhysics
object.setWorldTransform(btTransform(toBullet(orient), toBullet(center)));
const btCollisionObject* me = NULL;
std::vector<const btCollisionObject*> targetCollisionObjects;
const Actor* physactor = getActor(actor);
if (physactor)
me = physactor->getCollisionObject();
DeepestNotMeContactTestResultCallback resultCallback(me, toBullet(origin));
if (!targets.empty())
{
for (std::vector<MWWorld::Ptr>::const_iterator it = targets.begin(); it != targets.end(); ++it)
{
const Actor* physactor2 = getActor(*it);
if (physactor2)
targetCollisionObjects.push_back(physactor2->getCollisionObject());
}
}
DeepestNotMeContactTestResultCallback resultCallback(me, targetCollisionObjects, toBullet(origin));
resultCallback.m_collisionFilterGroup = CollisionType_Actor;
resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor;
mCollisionWorld->contactTest(&object, resultCallback);
@ -903,28 +926,40 @@ namespace MWPhysics
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{
public:
ClosestNotMeRayResultCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to)
ClosestNotMeRayResultCallback(const btCollisionObject* me, const std::vector<const btCollisionObject*> targets, const btVector3& from, const btVector3& to)
: btCollisionWorld::ClosestRayResultCallback(from, to)
, mMe(me)
, mMe(me), mTargets(targets)
{
}
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
{
if (rayResult.m_collisionObject == mMe)
return 1.f;
if (!mTargets.empty())
{
if ((std::find(mTargets.begin(), mTargets.end(), rayResult.m_collisionObject) == mTargets.end()))
{
PtrHolder* holder = static_cast<PtrHolder*>(rayResult.m_collisionObject->getUserPointer());
if (holder && !holder->getPtr().isEmpty() && holder->getPtr().getClass().isActor())
return 1.f;
}
}
return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
}
private:
const btCollisionObject* mMe;
const std::vector<const btCollisionObject*> mTargets;
};
PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore, int mask, int group) const
PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore, std::vector<MWWorld::Ptr> targets, int mask, int group) const
{
btVector3 btFrom = toBullet(from);
btVector3 btTo = toBullet(to);
const btCollisionObject* me = NULL;
std::vector<const btCollisionObject*> targetCollisionObjects;
if (!ignore.isEmpty())
{
const Actor* actor = getActor(ignore);
@ -938,7 +973,17 @@ namespace MWPhysics
}
}
ClosestNotMeRayResultCallback resultCallback(me, btFrom, btTo);
if (!targets.empty())
{
for (std::vector<MWWorld::Ptr>::const_iterator it = targets.begin(); it != targets.end(); ++it)
{
const Actor* actor = getActor(*it);
if (actor)
targetCollisionObjects.push_back(actor->getCollisionObject());
}
}
ClosestNotMeRayResultCallback resultCallback(me, targetCollisionObjects, btFrom, btTo);
resultCallback.m_collisionFilterGroup = group;
resultCallback.m_collisionFilterMask = mask;
@ -991,7 +1036,7 @@ namespace MWPhysics
osg::Vec3f pos1 (physactor1->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.9)); // eye level
osg::Vec3f pos2 (physactor2->getCollisionObjectPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.9));
RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door);
RayResult result = castRay(pos1, pos2, MWWorld::ConstPtr(), std::vector<MWWorld::Ptr>(), CollisionType_World|CollisionType_HeightMap|CollisionType_Door);
return !result.mHit;
}

@ -95,7 +95,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin,
const osg::Quat &orientation,
float queryDistance);
float queryDistance, std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>());
/// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the
@ -112,9 +112,10 @@ namespace MWPhysics
MWWorld::Ptr mHitObject;
};
/// @param me Optional, a Ptr to ignore in the list of results
RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore = MWWorld::ConstPtr(), int mask =
CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const;
/// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all other actors.
RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore = MWWorld::ConstPtr(),
std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>(),
int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const;
RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius);

@ -565,11 +565,6 @@ namespace MWRender
}
}
bool Animation::hasAnimSources() const
{
return !mAnimSources.empty();
}
void Animation::clearAnimSources()
{
mStates.clear();

@ -341,8 +341,6 @@ public:
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
virtual ~Animation();
bool hasAnimSources() const;
MWWorld::ConstPtr getPtr() const;
/// Set active flag on the object skeleton, if one exists.

@ -44,7 +44,7 @@ namespace MWWorld
MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor);
// Skill gain from books
if (ref->mBase->mData.mSkillID >= 0 && ref->mBase->mData.mSkillID < ESM::Skill::Length
if (ref->mBase->mData.mSkillId >= 0 && ref->mBase->mData.mSkillId < ESM::Skill::Length
&& !npcStats.hasBeenUsed (ref->mBase->mId))
{
MWWorld::LiveCellRef<ESM::NPC> *playerRef = actor.get<ESM::NPC>();
@ -54,7 +54,7 @@ namespace MWWorld
playerRef->mBase->mClass
);
npcStats.increaseSkill (ref->mBase->mData.mSkillID, *class_, true);
npcStats.increaseSkill (ref->mBase->mData.mSkillId, *class_, true);
npcStats.flagAsUsed (ref->mBase->mId);
}

@ -6,8 +6,10 @@
#include <components/esm/esmwriter.hpp>
#include <components/esm/projectilestate.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/lightmanager.hpp>
@ -25,6 +27,7 @@
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/aipackage.hpp"
#include "../mwrender/effectmanager.hpp"
#include "../mwrender/animation.hpp"
@ -49,8 +52,8 @@ namespace
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
iter->mEffectID);
// All the projectiles should use the same speed. From observations in the
// original engine, this seems to be the average of the constituent effects.
// Speed of multi-effect projectiles should be the average of the constituent effects,
// based on observation of the original engine.
speed += magicEffect->mData.mSpeed;
count++;
@ -337,9 +340,14 @@ namespace MWWorld
MWWorld::Ptr caster = it->getCaster();
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors;
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors);
// Check for impact
// TODO: use a proper btRigidBody / btGhostObject?
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile);
bool hit = false;
if (result.mHit)
@ -404,11 +412,17 @@ namespace MWWorld
MWWorld::Ptr caster = it->getCaster();
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors;
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
caster.getClass().getCreatureStats(caster).getAiSequence().getCombatTargets(targetActors);
// Check for impact
// TODO: use a proper btRigidBody / btGhostObject?
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, 0xff, MWPhysics::CollisionType_Projectile);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(pos, newPos, caster, targetActors, 0xff, MWPhysics::CollisionType_Projectile);
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos);
if (result.mHit || underwater)
{
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow);

@ -731,7 +731,7 @@ void WeatherManager::update(float duration, bool paused)
{
stopSounds();
if (!mResult.mAmbientLoopSoundID.empty())
mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
mPlayingSoundID = mResult.mAmbientLoopSoundID;
}

@ -13,10 +13,11 @@
#include <components/esm/esmwriter.hpp>
#include <components/esm/cellid.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/misc/rng.hpp>
#include <components/files/collections.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
@ -1079,7 +1080,7 @@ namespace MWWorld
return osg::Matrixf::translate(actor.getRefData().getPosition().asVec3());
}
std::pair<MWWorld::Ptr,osg::Vec3f> World::getHitContact(const MWWorld::ConstPtr &ptr, float distance)
std::pair<MWWorld::Ptr,osg::Vec3f> World::getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &targets)
{
const ESM::Position &posdata = ptr.getRefData().getPosition();
@ -1099,7 +1100,7 @@ namespace MWWorld
distance += halfExtents.y();
}
std::pair<MWWorld::Ptr,osg::Vec3f> result = mPhysics->getHitContact(ptr, pos, rot, distance);
std::pair<MWWorld::Ptr,osg::Vec3f> result = mPhysics->getHitContact(ptr, pos, rot, distance, targets);
if(result.first.isEmpty())
return std::make_pair(MWWorld::Ptr(), osg::Vec3f());
@ -1476,7 +1477,7 @@ namespace MWWorld
{
osg::Vec3f a(x1,y1,z1);
osg::Vec3f b(x2,y2,z2);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector<MWWorld::Ptr>(), MWPhysics::CollisionType_World|MWPhysics::CollisionType_Door);
return result.mHit;
}
@ -2526,7 +2527,7 @@ namespace MWWorld
if (includeWater) {
collisionTypes |= MWPhysics::CollisionType_Water;
}
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), collisionTypes);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector<MWWorld::Ptr>(), collisionTypes);
if (!result.mHit)
return maxDist;
@ -2747,12 +2748,17 @@ namespace MWWorld
osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
osg::Vec3f dest = origin + direction * distance;
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
std::vector<MWWorld::Ptr> targetActors;
if (!actor.isEmpty() && actor != MWMechanics::getPlayer())
actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors);
// For actor targets, we want to use bounding boxes (physics raycast).
// This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise.
// For object targets, we want the detailed shapes (rendering raycast).
// If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf.
MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, MWPhysics::CollisionType_Actor);
MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, targetActors, MWPhysics::CollisionType_Actor);
MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true);
@ -2764,7 +2770,7 @@ namespace MWWorld
if (result2.mHit)
dist2 = (origin - result2.mHitPointWorld).length();
if (dist1 <= dist2 && result1.mHit)
if (result1.mHit)
{
target = result1.mHitObject;
hitPosition = result1.mHitPos;
@ -2775,7 +2781,7 @@ namespace MWWorld
{
target = result2.mHitObject;
hitPosition = result2.mHitPointWorld;
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && (target.getClass().isActor() || !target.getClass().canBeActivated(target)))
if (dist2 > getMaxActivationDistance() && !target.isEmpty() && !target.getClass().canBeActivated(target))
target = NULL;
}
@ -2785,7 +2791,7 @@ namespace MWWorld
if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats (target).getAiSequence().isInCombat())
{
distance = std::min (distance, getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat());
if (distance < dist1 && distance < dist2)
if (distance < dist1)
target = NULL;
}

@ -354,7 +354,7 @@ namespace MWWorld
/// Returns a pointer to the object the provided object would hit (if within the
/// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node as a basis.
virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance);
virtual std::pair<MWWorld::Ptr,osg::Vec3f> getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector<MWWorld::Ptr> &targets);
/// @note No-op for items in containers. Use ContainerStore::removeItem instead.
virtual void deleteObject (const Ptr& ptr);

@ -84,7 +84,7 @@ namespace ESM
mData.mWeight = 0;
mData.mValue = 0;
mData.mIsScroll = 0;
mData.mSkillID = 0;
mData.mSkillId = 0;
mData.mEnchant = 0;
mName.clear();
mModel.clear();

@ -21,7 +21,7 @@ struct Book
struct BKDTstruct
{
float mWeight;
int mValue, mIsScroll, mSkillID, mEnchant;
int mValue, mIsScroll, mSkillId, mEnchant;
};
BKDTstruct mData;

@ -552,6 +552,9 @@ namespace NifOsg
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager,
std::vector<int> boundTextures, int animflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
{
if (rootNode != NULL && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
return NULL;
osg::ref_ptr<osg::Group> node = new osg::MatrixTransform(nifNode->trafo.toMatrix());
// Set a default DataVariance (used as hint by optimization routines).

Loading…
Cancel
Save