forked from teamnwah/openmw-tes3coop
Merge pull request #148 from OpenMW/master
Add OpenMW commits up to 13 Feb 2017
This commit is contained in:
commit
a5d7c5fd39
24 changed files with 142 additions and 56 deletions
|
@ -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…
Reference in a new issue