mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 13:49:56 +00:00
32108adc31
- enchanted arrow explode upon hit the water plane - non enchanted arrow disappear (or more accurately, they hit nothingness) - enchanted arrow shot underwater explode immediately - non enchanted arrow disappear immediately Also, solve a bug that occured previously and could theoritically still happens where we use the last tested collision position for instead of the last registered hit: Use the hit position as saved inside Projectile::hit() instead of the last position saved inside the callback. If a projectile collides with several objects (bottom of the sea and water surface for instance), the last collision tested won't necessarily be the impact position as we have no control over the order in which the tests are performed.
67 lines
2.6 KiB
C++
67 lines
2.6 KiB
C++
#include "../mwworld/class.hpp"
|
|
|
|
#include "actor.hpp"
|
|
#include "collisiontype.hpp"
|
|
#include "projectile.hpp"
|
|
#include "projectileconvexcallback.hpp"
|
|
#include "ptrholder.hpp"
|
|
|
|
namespace MWPhysics
|
|
{
|
|
ProjectileConvexCallback::ProjectileConvexCallback(const btCollisionObject* me, const btVector3& from, const btVector3& to, Projectile* proj)
|
|
: btCollisionWorld::ClosestConvexResultCallback(from, to)
|
|
, mMe(me), mProjectile(proj)
|
|
{
|
|
assert(mProjectile);
|
|
}
|
|
|
|
btScalar ProjectileConvexCallback::addSingleResult(btCollisionWorld::LocalConvexResult& result, bool normalInWorldSpace)
|
|
{
|
|
// don't hit the caster
|
|
if (result.m_hitCollisionObject == mMe)
|
|
return 1.f;
|
|
|
|
// don't hit the projectile
|
|
if (result.m_hitCollisionObject == mProjectile->getCollisionObject())
|
|
return 1.f;
|
|
|
|
btCollisionWorld::ClosestConvexResultCallback::addSingleResult(result, normalInWorldSpace);
|
|
switch (result.m_hitCollisionObject->getBroadphaseHandle()->m_collisionFilterGroup)
|
|
{
|
|
case CollisionType_Actor:
|
|
{
|
|
auto* target = static_cast<Actor*>(result.m_hitCollisionObject->getUserPointer());
|
|
if (!mProjectile->isValidTarget(target->getPtr()))
|
|
return 1.f;
|
|
mProjectile->hit(target->getPtr(), result.m_hitPointLocal, result.m_hitNormalLocal);
|
|
break;
|
|
}
|
|
case CollisionType_Projectile:
|
|
{
|
|
auto* target = static_cast<Projectile*>(result.m_hitCollisionObject->getUserPointer());
|
|
if (!mProjectile->isValidTarget(target->getCaster()))
|
|
return 1.f;
|
|
target->hit(mProjectile->getPtr(), m_hitPointWorld, m_hitNormalWorld);
|
|
mProjectile->hit(target->getPtr(), m_hitPointWorld, m_hitNormalWorld);
|
|
break;
|
|
}
|
|
case CollisionType_Water:
|
|
{
|
|
mProjectile->setHitWater();
|
|
mProjectile->hit(MWWorld::Ptr(), m_hitPointWorld, m_hitNormalWorld);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
auto* target = static_cast<PtrHolder*>(result.m_hitCollisionObject->getUserPointer());
|
|
auto ptr = target ? target->getPtr() : MWWorld::Ptr();
|
|
mProjectile->hit(ptr, m_hitPointWorld, m_hitNormalWorld);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result.m_hitFraction;
|
|
}
|
|
|
|
}
|
|
|