Merge pull request #148 from OpenMW/master

Add OpenMW commits up to 13 Feb 2017
coverity_scan^2
David Cernat 8 years ago committed by GitHub
commit a5d7c5fd39

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

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

@ -202,7 +202,7 @@ public:
bool isDeleted = false; bool isDeleted = false;
book.load(esm, isDeleted); 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)); mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId));
mRecords[book.mId] = book; mRecords[book.mId] = book;

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

@ -294,8 +294,8 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scroll, ColumnBase::Display_Boolean)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scroll, ColumnBase::Display_Boolean));
const RefIdColumn *scroll = &mColumns.back(); const RefIdColumn *scroll = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
const RefIdColumn *attribute = &mColumns.back(); const RefIdColumn *skill = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString));
const RefIdColumn *text = &mColumns.back(); const RefIdColumn *text = &mColumns.back();
@ -659,7 +659,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mAdapters.insert (std::make_pair (UniversalId::Type_Armor, mAdapters.insert (std::make_pair (UniversalId::Type_Armor,
new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef))); new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef)));
mAdapters.insert (std::make_pair (UniversalId::Type_Book, 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, mAdapters.insert (std::make_pair (UniversalId::Type_Clothing,
new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef))); new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef)));
mAdapters.insert (std::make_pair (UniversalId::Type_Container, 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 /// 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 /// 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. /// 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; virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0;
///< Adjust position after load to be on ground. Must be called after model load. ///< Adjust position after load to be on ground. Must be called after model load.

@ -249,7 +249,12 @@ namespace MWClass
if (!weapon.isEmpty()) if (!weapon.isEmpty())
dist *= weapon.get<ESM::Weapon>()->mBase->mData.mReach; 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()) if (result.first.isEmpty())
return; // Didn't hit anything return; // Didn't hit anything

@ -574,8 +574,13 @@ namespace MWClass
weapon.get<ESM::Weapon>()->mBase->mData.mReach : weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat()); 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 // 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; MWWorld::Ptr victim = result.first;
osg::Vec3f hitPosition(result.second); osg::Vec3f hitPosition(result.second);
if (victim.isEmpty()) // Didn't hit anything if (victim.isEmpty()) // Didn't hit anything

@ -75,6 +75,17 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
return !targetActor.isEmpty(); 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 std::list<AiPackage*>::const_iterator AiSequence::begin() const
{ {
return mPackages.begin(); return mPackages.begin();

@ -79,6 +79,9 @@ namespace MWMechanics
/// Return true and assign target if combat package is currently active, return false otherwise /// Return true and assign target if combat package is currently active, return false otherwise
bool getCombatTarget (MWWorld::Ptr &targetActor) const; 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? /// Is there any combat package?
bool isInCombat () const; bool isInCombat () const;

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

@ -417,10 +417,6 @@ namespace MWMechanics
float magnitudeMult = 1; float magnitudeMult = 1;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor()) 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) if (absorbed)
continue; continue;
@ -453,6 +449,10 @@ namespace MWMechanics
// If player is attempting to cast a harmful spell, show the target's HP bar // If player is attempting to cast a harmful spell, show the target's HP bar
if (castByPlayer && target != caster) if (castByPlayer && target != caster)
MWBase::Environment::get().getWindowManager()->setEnemy(target); 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) if (magnitudeMult > 0 && !absorbed)

@ -798,6 +798,7 @@ namespace MWPhysics
class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback class DeepestNotMeContactTestResultCallback : public btCollisionWorld::ContactResultCallback
{ {
const btCollisionObject* mMe; const btCollisionObject* mMe;
const std::vector<const btCollisionObject*> mTargets;
// Store the real origin, since the shape's origin is its center // Store the real origin, since the shape's origin is its center
btVector3 mOrigin; btVector3 mOrigin;
@ -807,8 +808,8 @@ namespace MWPhysics
btVector3 mContactPoint; btVector3 mContactPoint;
btScalar mLeastDistSqr; btScalar mLeastDistSqr;
DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const btVector3 &origin) DeepestNotMeContactTestResultCallback(const btCollisionObject* me, const std::vector<const btCollisionObject*> targets, const btVector3 &origin)
: mMe(me), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0), : mMe(me), mTargets(targets), mOrigin(origin), mObject(NULL), mContactPoint(0,0,0),
mLeastDistSqr(std::numeric_limits<float>::max()) mLeastDistSqr(std::numeric_limits<float>::max())
{ } { }
@ -819,6 +820,16 @@ namespace MWPhysics
const btCollisionObject* collisionObject = col1Wrap->m_collisionObject; const btCollisionObject* collisionObject = col1Wrap->m_collisionObject;
if (collisionObject != mMe) 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()); btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA());
if(!mObject || distsqr < mLeastDistSqr) if(!mObject || distsqr < mLeastDistSqr)
{ {
@ -835,7 +846,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor, std::pair<MWWorld::Ptr, osg::Vec3f> PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin, const osg::Vec3f &origin,
const osg::Quat &orient, 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>(); 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))); object.setWorldTransform(btTransform(toBullet(orient), toBullet(center)));
const btCollisionObject* me = NULL; const btCollisionObject* me = NULL;
std::vector<const btCollisionObject*> targetCollisionObjects;
const Actor* physactor = getActor(actor); const Actor* physactor = getActor(actor);
if (physactor) if (physactor)
me = physactor->getCollisionObject(); 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_collisionFilterGroup = CollisionType_Actor;
resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor;
mCollisionWorld->contactTest(&object, resultCallback); mCollisionWorld->contactTest(&object, resultCallback);
@ -903,28 +926,40 @@ namespace MWPhysics
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{ {
public: 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) : 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) if (rayResult.m_collisionObject == mMe)
return 1.f; 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); return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
} }
private: private:
const btCollisionObject* mMe; 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 btFrom = toBullet(from);
btVector3 btTo = toBullet(to); btVector3 btTo = toBullet(to);
const btCollisionObject* me = NULL; const btCollisionObject* me = NULL;
std::vector<const btCollisionObject*> targetCollisionObjects;
if (!ignore.isEmpty()) if (!ignore.isEmpty())
{ {
const Actor* actor = getActor(ignore); 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_collisionFilterGroup = group;
resultCallback.m_collisionFilterMask = mask; 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 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)); 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; return !result.mHit;
} }

@ -95,7 +95,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor, std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin, const osg::Vec3f &origin,
const osg::Quat &orientation, 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 /// 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; MWWorld::Ptr mHitObject;
}; };
/// @param me Optional, a Ptr to ignore in the list of results /// @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(), int mask = RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::ConstPtr ignore = MWWorld::ConstPtr(),
CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; 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); 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() void Animation::clearAnimSources()
{ {
mStates.clear(); mStates.clear();

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

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

@ -6,8 +6,10 @@
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/projectilestate.hpp> #include <components/esm/projectilestate.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/lightmanager.hpp> #include <components/sceneutil/lightmanager.hpp>
@ -25,6 +27,7 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/aipackage.hpp"
#include "../mwrender/effectmanager.hpp" #include "../mwrender/effectmanager.hpp"
#include "../mwrender/animation.hpp" #include "../mwrender/animation.hpp"
@ -49,8 +52,8 @@ namespace
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find ( const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
iter->mEffectID); iter->mEffectID);
// All the projectiles should use the same speed. From observations in the // Speed of multi-effect projectiles should be the average of the constituent effects,
// original engine, this seems to be the average of the constituent effects. // based on observation of the original engine.
speed += magicEffect->mData.mSpeed; speed += magicEffect->mData.mSpeed;
count++; count++;
@ -337,9 +340,14 @@ namespace MWWorld
MWWorld::Ptr caster = it->getCaster(); 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 // Check for impact
// TODO: use a proper btRigidBody / btGhostObject? // 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; bool hit = false;
if (result.mHit) if (result.mHit)
@ -404,11 +412,17 @@ namespace MWWorld
MWWorld::Ptr caster = it->getCaster(); 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 // Check for impact
// TODO: use a proper btRigidBody / btGhostObject? // 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); bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos);
if (result.mHit || underwater) if (result.mHit || underwater)
{ {
MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow); MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mIdArrow);

@ -731,7 +731,7 @@ void WeatherManager::update(float duration, bool paused)
{ {
stopSounds(); stopSounds();
if (!mResult.mAmbientLoopSoundID.empty()) 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; mPlayingSoundID = mResult.mAmbientLoopSoundID;
} }

@ -13,10 +13,11 @@
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/cellid.hpp> #include <components/esm/cellid.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/files/collections.hpp> #include <components/files/collections.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
@ -1079,7 +1080,7 @@ namespace MWWorld
return osg::Matrixf::translate(actor.getRefData().getPosition().asVec3()); 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(); const ESM::Position &posdata = ptr.getRefData().getPosition();
@ -1099,7 +1100,7 @@ namespace MWWorld
distance += halfExtents.y(); 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()) if(result.first.isEmpty())
return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); return std::make_pair(MWWorld::Ptr(), osg::Vec3f());
@ -1476,7 +1477,7 @@ namespace MWWorld
{ {
osg::Vec3f a(x1,y1,z1); osg::Vec3f a(x1,y1,z1);
osg::Vec3f b(x2,y2,z2); 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; return result.mHit;
} }
@ -2526,7 +2527,7 @@ namespace MWWorld
if (includeWater) { if (includeWater) {
collisionTypes |= MWPhysics::CollisionType_Water; 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) if (!result.mHit)
return maxDist; return maxDist;
@ -2747,12 +2748,17 @@ namespace MWWorld
osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
osg::Vec3f dest = origin + direction * distance; 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). // 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. // 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). // 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. // 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); MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true);
@ -2764,7 +2770,7 @@ namespace MWWorld
if (result2.mHit) if (result2.mHit)
dist2 = (origin - result2.mHitPointWorld).length(); dist2 = (origin - result2.mHitPointWorld).length();
if (dist1 <= dist2 && result1.mHit) if (result1.mHit)
{ {
target = result1.mHitObject; target = result1.mHitObject;
hitPosition = result1.mHitPos; hitPosition = result1.mHitPos;
@ -2775,7 +2781,7 @@ namespace MWWorld
{ {
target = result2.mHitObject; target = result2.mHitObject;
hitPosition = result2.mHitPointWorld; 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; target = NULL;
} }
@ -2785,7 +2791,7 @@ namespace MWWorld
if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats (target).getAiSequence().isInCombat()) if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats (target).getAiSequence().isInCombat())
{ {
distance = std::min (distance, getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat()); distance = std::min (distance, getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat());
if (distance < dist1 && distance < dist2) if (distance < dist1)
target = NULL; target = NULL;
} }

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

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

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

@ -552,6 +552,9 @@ namespace NifOsg
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, 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) 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()); osg::ref_ptr<osg::Group> node = new osg::MatrixTransform(nifNode->trafo.toMatrix());
// Set a default DataVariance (used as hint by optimization routines). // Set a default DataVariance (used as hint by optimization routines).

Loading…
Cancel
Save