Exemplo n.º 1
0
inline bool i_QuickSphereTest2(const LTVector &pVector, const float fRadius) 
{
    // Find the closest point to the line.
    // Here's the equation for t:
    // P = point1
    // V = point2 - point1 (ie: direction vector)
    // S = point you're testing
    // t = parametric (P + Vt)
    // t = -(-VS + VP) / VV

    //dirVec = *pPoint2 - *pPoint1;
    //t = pServerObj->m_Pos.Dot(dirVec) - dirVec.Dot(*pPoint1);
    //t /= dirVec.Dot(dirVec);

    float t = g_VTimesInvVV.Dot(pVector) - g_VPTimesInvVV;

    if (t < -fRadius || t > (g_LineLen + fRadius)) 
	{
        return false;
    }
    
    // Now see if it's within range.
    LTVector vecTo = g_pCurQuery->m_From + g_V * t - pVector;
    return vecTo.MagSqr() < (fRadius * fRadius);
}
Exemplo n.º 2
0
void Body::FacePos(const LTVector& vTargetPos)
{
    if (!g_pLTServer || !m_hObject) return;

	LTVector vPos;
    g_pLTServer->GetObjectPos(m_hObject, &vPos);

	LTVector vDir;
	VEC_SUB(vDir, vTargetPos, vPos);

	if ( vDir.MagSqr() == 0.0f )
	{
		// Facing the same position... this would be a divide by zero case
		// when we normalize. So just return.
		return;
	}

	vDir.y = 0.0f; // Don't look up/down
	VEC_NORM(vDir);

    LTRotation rRot;
    LTVector temp(0,1,0);
    g_pMathLT->AlignRotation(rRot, vDir, temp);
    g_pLTServer->SetObjectRotation(m_hObject, &rRot);
}
Exemplo n.º 3
0
inline bool i_QuickSphereTest(const LTObject *pServerObj) 
{
    // Find the closest point to the line.
    // Here's the equation for t:
    // P = point1
    // V = point2 - point1 (ie: direction vector)
    // S = point you're testing
    // t = parametric (P + Vt)
    // t = -(-VS + VP) / VV

    //dirVec = *pPoint2 - *pPoint1;
    //t = pServerObj->m_Pos.Dot(dirVec) - dirVec.Dot(*pPoint1);
    //t /= dirVec.Dot(dirVec);

    float t = g_VTimesInvVV.Dot(pServerObj->GetPos()) - g_VPTimesInvVV;

	//cache this radius since it is a virtual function call and can be somewhat expensive on some
	//object types
	float fRadius = pServerObj->GetRadius();

    if (t < -fRadius || t > (g_LineLen + fRadius)) 
	{
        return false;
    }
    
    // Now see if it's within range.
    LTVector vecTo = g_pCurQuery->m_From + g_V * t - pServerObj->GetPos();
    return vecTo.MagSqr() < pServerObj->GetRadiusSquared();
}
Exemplo n.º 4
0
bool ObjectDetector::TestParamsCylinder( ObjectDetectorLink* pLink, LTVector& vPos, LTVector& vDims, float& fMetRR )
{
	// Make sure we've got some valid parameters
	if( ( m_vParamsCylinder.x <= 0.0f ) || ( m_vParamsCylinder.y <= m_vParamsCylinder.x ) || ( m_vParamsCylinder.z <= 0.0f ) )
	{
		fMetRR = 1.0f;
		return false;
	}

	// Get the object position in the space of the source
	LTVector vRelPos;

	vRelPos = ( vPos - m_tTransform.m_vPos );
	vRelPos = ( ~m_tTransform.m_rRot ).RotateVector( vRelPos );

	// Calculate the requirement range values
	float fHeightDelta = fabs( vRelPos.y );
	vRelPos.y = 0.0f;

	float fMagSqr = vRelPos.MagSqr();
	float fMagRR = ( ( fMagSqr - m_vParamsCylinder.x ) / ( m_vParamsCylinder.y - m_vParamsCylinder.x ) );
	float fHeightRR = ( fHeightDelta / m_vParamsCylinder.z );

	// Weigh the magnitude higher than the angles
	fMetRR = ( fMagRR * 0.5f ) + ( fHeightRR * 0.5f );

	// Return true if it was contained by the cylinder
	return ( ( fMagSqr >= m_vParamsCylinder.x ) && ( fMagSqr <= m_vParamsCylinder.y ) && ( fHeightDelta <= m_vParamsCylinder.z ) );
}
Exemplo n.º 5
0
void CWeaponFX::PlayBulletFlyBySound()
{
	if (!m_pWeapon || !m_pAmmo) return;

	if (m_pAmmo->eType != VECTOR) return;

	// Camera pos

	HOBJECT hCamera = g_pGameClientShell->GetCamera();
    LTVector vPos;
    g_pLTClient->GetObjectPos(hCamera, &vPos);

	// We only play the flyby sound if we won't hear an impact or
	// fire sound...

	LTVector vDist = m_vFirePos - vPos;
	if (vDist.Mag() < m_pWeapon->nFireSoundRadius) return;

	if (m_pAmmo->pImpactFX)
	{
		vDist = m_vPos - vPos;
		if (vDist.Mag() < m_pAmmo->pImpactFX->nSoundRadius) return;
	}


	// See if the camera is close enough to the bullet path to hear the
	// bullet...

	LTFLOAT fRadius = g_cvarFlyByRadius.GetFloat();

	LTVector vDir = m_vDir;

	const LTVector vRelativePos = vPos - m_vFirePos;
    const LTFLOAT fRayDist = vDir.Dot(vRelativePos);
	LTVector vBulletDir = (vDir*fRayDist - vRelativePos);

    const LTFLOAT fDistSqr = vBulletDir.MagSqr();

	if (fDistSqr < fRadius*fRadius)
	{
		vPos += vBulletDir;
		g_pClientSoundMgr->PlaySoundFromPos(vPos, "Guns\\Snd\\flyby.wav",
			g_cvarFlyBySoundRadius.GetFloat(), SOUNDPRIORITY_MISC_LOW);
	}
}
Exemplo n.º 6
0
	//called when a sphere shape is encountered. This will provide the center of the sphere relative
	//to the transform heirarchy and the radius of that sphere
	virtual void HandleSphere(const LTVector& vCenter, float fRadius, float fMassKg, float fDensityG)							
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		if(ApplySphereBuoyancy(vCenter, fRadius, m_SurfacePlane, fVolume, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcSphereWaterDensity(m_fDensity, fRadius, fMassKg, fDensityG);
            LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vCenter, vForce);
		}
	}
Exemplo n.º 7
0
bool ObjectDetector::TestParamsSphere( ObjectDetectorLink* pLink, LTVector& vPos, LTVector& vDims, float& fMetRR )
{
	// Make sure we've got some valid parameters
	if( ( m_vParamsSphere.x <= 0.0f ) || ( m_vParamsSphere.y <= m_vParamsSphere.x ) )
	{
		fMetRR = 1.0f;
		return false;
	}

	// Get the object position in the space of the source
	LTVector vRelPos;

	vRelPos = ( vPos - m_tTransform.m_vPos );

	// Calculate the magnitude and requirement range
	float fMagSqr = vRelPos.MagSqr();
	fMetRR = ( ( fMagSqr - m_vParamsSphere.x ) / ( m_vParamsSphere.y - m_vParamsSphere.x ) );

	return ( ( fMagSqr >= m_vParamsSphere.x ) && ( fMagSqr <= m_vParamsSphere.y ) );
}
Exemplo n.º 8
0
	//called when an OBB shape is encountered. This will provide the transform of the OBB relative to
	//the transform heirarchy and the half dimensions of the OBB
	virtual void HandleOBB(const LTRigidTransform& tTransform, const LTVector& vHalfDims, float fMassKg, float fDensityG)		
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		LTVector vApplyAt;

		if(ApplyOBBBuoyancy(tTransform, vHalfDims, m_SurfacePlane, fVolume, vApplyAt, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcOBBWaterDensity(m_fDensity, vHalfDims, fMassKg, fDensityG);
			LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vApplyAt, vForce);
		}
	}
Exemplo n.º 9
0
void CClientMgr::MoveObject(LTObject *pObject, const LTVector *pNewPos, bool bForce)
{
    LTVector vDiff;

    if (!bForce)
    {
        vDiff = pObject->GetPos() - *pNewPos;
        if (vDiff.MagSqr() < 0.001f)
            return;
    }

    pObject->SetPos(*pNewPos);

    // Do special stuff if it's a WorldModel.
    if (pObject->HasWorldModel())
    {
        RetransformWorldModel(pObject->ToWorldModel());
    }

    world_bsp_client->ClientTree()->InsertObject(pObject);
}
Exemplo n.º 10
0
bool ObjectDetector::TestParamsFOV( ObjectDetectorLink* pLink, LTVector& vPos, LTVector& vDims, float& fMetRR )
{
	// Make sure we've got some valid parameters
	if( ( m_vParamsFOV.z < 0.0f ) || ( m_vParamsFOV.w <= m_vParamsFOV.z ) )
	{
		fMetRR = 1.0f;
		return false;
	}

	// Get the object position in the space of the source
	LTVector vRelPos;

	vRelPos = ( vPos - m_tTransform.m_vPos );
	vRelPos = ( ~m_tTransform.m_rRot ).RotateVector( vRelPos );

	// Get the normalized axis vectors flat along the FOV
	LTVector vForward( 0.0f, 0.0f, 1.0f );
	LTVector vFlatX( vRelPos.x, 0.0f, vRelPos.z );
	LTVector vFlatY( 0.0f, vRelPos.y, vRelPos.z );

	vFlatX.Normalize();
	vFlatY.Normalize();

	// Check the range
	float fMagSqr = vRelPos.MagSqr();
	float fXCos = vForward.Dot( vFlatX );
	float fYCos = vForward.Dot( vFlatY );

	// Calculate the requirement range values
	float fMagRR = ( ( fMagSqr - m_vParamsFOV.z ) / ( m_vParamsFOV.w - m_vParamsFOV.z ) );
	float fFOVXRR = ( ( fXCos - 1.0f ) / ( m_vParamsFOV.x - 1.0f ) );
	float fFOVYRR = ( ( fYCos - 1.0f ) / ( m_vParamsFOV.y - 1.0f ) );

	// Apply the weights to the various parameters
	fMetRR = ( fMagRR * m_vParamsFOVWeights.x ) + ( fFOVXRR * m_vParamsFOVWeights.y ) + ( fFOVYRR * m_vParamsFOVWeights.z );

	// Return true if it was contained by the FOV
	return ( ( fMagSqr >= m_vParamsFOV.z ) && ( fMagSqr < m_vParamsFOV.w ) && ( fXCos >= m_vParamsFOV.x ) && ( fYCos >= m_vParamsFOV.y ) );
}
Exemplo n.º 11
0
	//called when a capsule shape is encounered. This will provide the two end points of the capsule
	//relative to the transform heirarchy and the radius of the capsule
	virtual void HandleCapsule(const LTVector& vPt1, const LTVector& vPt2, float fRadius, float fMassKg, float fDensityG)		
	{
		m_fTotalMassKg += fMassKg;

		float fVolume, fSurfaceArea;
		LTVector vApplyAt;

		//determine the lenght of the capsule axis
		float fLength = vPt1.Dist(vPt2);

		if(ApplyCapsuleBuoyancy(vPt1, vPt2, fLength, fRadius, m_SurfacePlane, fVolume, vApplyAt, fSurfaceArea))
		{
			m_fSurfaceArea += fSurfaceArea;
			float fWaterDensity = CalcCapsuleWaterDensity(m_fDensity, fRadius, fLength, fMassKg, fDensityG);
			LTVector vForce = CalcBuoyancyForceVector(m_vGravity, fWaterDensity, fVolume);
			if( LTIsNaN( vForce ) || vForce.MagSqr() > 1000000.0f * 1000000.0f )
			{
				LTERROR( "Invalid force detected." );
				vForce.Init( 0.0f, 10.0f, 0.0f );
			}
			g_pLTBase->PhysicsSim()->ApplyRigidBodyForceWorldSpace(m_hRigidBody, vApplyAt, vForce);
		}
	}
Exemplo n.º 12
0
bool i_IntersectSegment(IntersectQuery *pQuery, IntersectInfo *pInfo, WorldTree *pWorldTree)
{
    float InvVV, VP, testMag;

    ++g_nIntersectCalls;
	CountAdder cTicks_Intersect(&g_Ticks_Intersect);
        
    // Init..
    g_pCurQuery = pQuery;
    g_pIntersection = LTNULL;
    g_pWorldIntersection = LTNULL;
    g_hWorldPoly = INVALID_HPOLY;
	g_hModelNode = INVALID_MODEL_NODE;
    g_bProcessNonSolid = !(pQuery->m_Flags & IGNORE_NONSOLID);
    g_bProcessObjects = !!(pQuery->m_Flags & INTERSECT_OBJECTS);
	g_bCheckIfFromPointIsInsideObject = !!(pQuery->m_Flags & CHECK_FROM_POINT_INSIDE_OBJECTS);
	g_bProcessModelObbs = !!(pQuery->m_Flags & INTERSECT_MODELOBBS);
    g_IntersectionBestDistSqr = (pQuery->m_From - pQuery->m_To).MagSqr() + 1.0f;

    // Precalculate stuff to totally accelerate i_QuickSphereTest.
    g_VOrigin = pQuery->m_From;
    g_V = pQuery->m_To - pQuery->m_From;

    // Calc Direction
    g_VDir = g_V.Unit();  

    g_LineLen = g_V.Mag();
    g_V /= g_LineLen;
    
    // Was it too short?
    testMag = g_V.MagSqr();
    if (testMag < 0.5f || testMag > 2.0f) 
	{
        return false;
    }
    
    VP = g_V.Dot(pQuery->m_From);
    InvVV = 1.0f / g_V.MagSqr();
    g_VTimesInvVV = g_V * InvVV;
    g_VPTimesInvVV = VP * InvVV;

    if (pQuery->m_Flags & INTERSECT_HPOLY) 
	{
        g_FindIntersectionsFn = i_FindIntersectionsHPoly;
    }
    else 
	{
        g_FindIntersectionsFn = i_FindIntersections;
    }

    // Start at the world tree.
    pWorldTree->IntersectSegment((LTVector*)&pQuery->m_From, (LTVector*)&pQuery->m_To, i_ISCallback, LTNULL);

    // If an object was hit, use it!
    if (g_pIntersection) 
	{
        pInfo->m_Point = g_IntersectionPos;
        pInfo->m_Plane = g_IntersectionPlane;
        pInfo->m_hObject = (HOBJECT)g_pIntersection;
        pInfo->m_hPoly = g_hWorldPoly;
		pInfo->m_hNode = g_hModelNode;
        
        if (g_pWorldIntersection) 
		{
            pInfo->m_SurfaceFlags = g_pWorldIntersection->m_pPoly->GetSurface()->m_TextureFlags;
        }
        else 
		{
            pInfo->m_SurfaceFlags = 0;
        }

        return true;
    }
    else 
	{
        return false;
    }
}
Exemplo n.º 13
0
// Wrap the textures, starting at a poly index
void CRVTrackerTextureWrap::WrapTexture(CTWPolyInfo *pPoly, const CVector &vWrapDir, CTextExtents &cExtents) const
{
	// Mark this poly as wrapped
	pPoly->m_bTouched = TRUE;

	CTexturedPlane& Texture = pPoly->m_pPoly->GetTexture(GetCurrTexture());

	// Get the texture space
	LTVector vWrapO = Texture.GetO();
	LTVector vWrapP = Texture.GetP();
	LTVector vWrapQ = Texture.GetQ();

	// Get the texture offset projections
	float fWrapOdotP = vWrapO.Dot(vWrapP);
	float fWrapOdotQ = vWrapO.Dot(vWrapQ);

	// Update the texturing extents
	for (uint32 nExtentLoop = 0; nExtentLoop < pPoly->m_aEdges.GetSize(); ++nExtentLoop)
	{
		LTVector vEdgePt = pPoly->m_aEdges[nExtentLoop]->m_aPt[0];

		float fCurU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fCurV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		cExtents.m_fMinU = LTMIN(fCurU, cExtents.m_fMinU);
		cExtents.m_fMaxU = LTMAX(fCurU, cExtents.m_fMaxU);
		cExtents.m_fMinV = LTMIN(fCurV, cExtents.m_fMinV);
		cExtents.m_fMaxV = LTMAX(fCurV, cExtents.m_fMaxV);
	}

	CMoArray<uint32> aNeighbors;
	CMoArray<float> aDots;

	// Insert the neighbors into a list in dot-product order
	for (uint32 nNeighborLoop = 0; nNeighborLoop < pPoly->m_aNeighbors.GetSize(); ++nNeighborLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[nNeighborLoop];

		// Skip edges that don't have a neighbor
		if (!pNeighbor)
			continue;

		// Skip neighbors that are already wrapped
		if (pNeighbor->m_bTouched)
			continue;

		// Get our dot product
		float fCurDot = vWrapDir.Dot(pPoly->m_aEdges[nNeighborLoop]->m_Plane.m_Normal);

		if ((m_bRestrictWalkDir) && (fCurDot < 0.707f))
			continue;

		// Mark this neighbor as touched (to avoid later polygons pushing it onto the stack)
		pNeighbor->m_bTouched = TRUE;

		// Insert it into the list
		for (uint32 nInsertLoop = 0; nInsertLoop < aNeighbors.GetSize(); ++nInsertLoop)
		{
			if (fCurDot > aDots[nInsertLoop])
				break;
		}
		aDots.Insert(nInsertLoop, fCurDot);
		aNeighbors.Insert(nInsertLoop, nNeighborLoop);
	}

	// Recurse through its neighbors
	for (uint32 nWrapLoop = 0; nWrapLoop < aNeighbors.GetSize(); ++nWrapLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[aNeighbors[nWrapLoop]];
		CTWEdgeInfo *pEdge = pPoly->m_aEdges[aNeighbors[nWrapLoop]];

		//////////////////////////////////////////////////////////////////////////////
		// Wrap this neighbor

		// Create a matrix representing the basis of the polygon in relation to this edge
		LTMatrix mPolyBasis;
		mPolyBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mPolyBasis.SetBasisVectors(&pEdge->m_vDir, &pPoly->m_pPoly->m_Plane.m_Normal, &pEdge->m_Plane.m_Normal);

		// Create a new basis for the neighbor polygon
		LTMatrix mNeighborBasis;
		LTVector vNeighborForward;
		vNeighborForward = pNeighbor->m_pPoly->m_Plane.m_Normal.Cross(pEdge->m_vDir);
		// Just to be sure..
		vNeighborForward.Norm();
		mNeighborBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mNeighborBasis.SetBasisVectors(&pEdge->m_vDir, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborForward);

		// Create a rotation matrix from here to there
		LTMatrix mRotation;
		mRotation = mNeighborBasis * ~mPolyBasis;

		// Rotate the various vectors
		LTVector vNewP;
		LTVector vNewQ;
		LTVector vNewDir;

		mRotation.Apply3x3(vWrapP, vNewP);
		mRotation.Apply3x3(vWrapQ, vNewQ);
		mRotation.Apply3x3(vWrapDir, vNewDir);

		// Rotate the texture basis if we're following a path
		if (m_nWrapStyle == k_WrapPath)
		{
			LTVector vNeighborEdgeDir;
			if (GetSimilarEdgeDir(pNeighbor, vNewDir, vNeighborEdgeDir, 0.707f))
			{
				LTMatrix mRotatedNeighbor;
				LTVector vNeighborRight;
				vNeighborRight = vNeighborEdgeDir.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vNeighborRight.Norm();
				// Make sure we're pointing the right way...
				if (vNeighborRight.Dot(pEdge->m_vDir) < 0.0f)
					vNeighborRight = -vNeighborRight;
				mRotatedNeighbor.SetTranslation(0.0f, 0.0f, 0.0f);
				mRotatedNeighbor.SetBasisVectors(&vNeighborRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborEdgeDir);
				// Build a basis based on an edge from the current polygon 
				LTVector vBestPolyEdge;
				GetSimilarEdgeDir(pPoly, vWrapDir, vBestPolyEdge);
				LTVector vPolyRight = vBestPolyEdge.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vPolyRight.Norm();
				// Make sure we're pointing the right way...
				if (vPolyRight.Dot(pEdge->m_vDir) < 0.0f)
					vPolyRight = -vPolyRight;
				// Build the poly edge matrix
				LTMatrix mPolyEdgeBasis;
				mPolyEdgeBasis.SetTranslation(0.0f, 0.0f, 0.0f);
				mPolyEdgeBasis.SetBasisVectors(&vPolyRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vBestPolyEdge);

				// Get a matrix from here to there
				LTMatrix mRotator;
				mRotator = mRotatedNeighbor * ~mPolyEdgeBasis;
				// Rotate the texture basis
				mRotator.Apply3x3(vNewP);
				mRotator.Apply3x3(vNewQ);
				// And use the new edge as the new direction
				vNewDir = vNeighborEdgeDir;
			}

			// Remove skew from vNewP/vNewQ
			if ((float)fabs(vNewP.Dot(vNewQ)) > 0.001f)
			{
				float fMagP = vNewP.Mag();
				float fMagQ = vNewQ.Mag();
				vNewQ *= 1.0f / fMagQ;
				vNewP -= vNewQ * vNewQ.Dot(vNewP);
				vNewP.Norm(fMagP);
				vNewQ *= fMagQ;
			}
		}

		// Get the first edge point..
		CVector vEdgePt = pEdge->m_aPt[0];

		// Calculate the texture coordinate at this point
		float fWrapU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fWrapV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		// Build the new offset
		float fNewOdotP = vNewP.Dot(vEdgePt) - fWrapU;
		float fNewOdotQ = vNewQ.Dot(vEdgePt) - fWrapV;
		LTVector vNewO;
		vNewO.Init();
		float fNewPMag = vNewP.MagSqr();
		if (fNewPMag > 0.0f)
			vNewO += vNewP * (fNewOdotP / fNewPMag);
		float fNewQMag = vNewQ.MagSqr();
		if (fNewQMag > 0.0f)
			vNewO += vNewQ * (fNewOdotQ / fNewQMag);

		pNeighbor->m_pPoly->SetTextureSpace(GetCurrTexture(), vNewO, vNewP, vNewQ);

		// Recurse into this neighbor
		WrapTexture(pNeighbor, vNewDir, cExtents);
	}
}
Exemplo n.º 14
0
LTBOOL CAIMovement::Update()
{
	// Clear any past movement.
	m_pAI->Stop();
	m_pAI->SetCheapMovement(LTTRUE);

	LTVector vNewPos;
	LTBOOL bMove = LTTRUE;

	// Bound a new path to the volume.

	if( ( m_eState == eStateSet ) && m_bNewPathSet )
	{
		BoundPathToVolume( m_pDestVolume );
		m_bNewPathSet = LTFALSE;
		m_iBoundPt = 0;
	}

	EnumAnimMovement eMovementType = m_pAI->GetAnimationContext()->GetAnimMovementType();

	switch( eMovementType )
	{
		case kAM_None: 

			// Safety mechanism to pop AI up if they fall thru the level.

			if( m_bMoved && 
				( m_pAI->GetLastVolume() ) && 
				( m_pAI->GetPosition().y + Max( 16.f, m_pAI->GetDims().y ) < m_pAI->GetLastVolume()->GetBackBottomLeft().y ) )
			{
				LTVector vPos = m_pAI->GetPosition();
				vPos = ConvertToDEditPos( vPos );
				AIError( "AI '%s' fell thru the level at pos(%.2f %.2f %.2f )!! Popping back up.", 
					m_pAI->GetName(), vPos.x, vPos.y, vPos.z );
				LTVector vDir = m_pAI->GetPosition() - m_vLastValidVolumePos;
				vDir.y = 0.f;
				if( vDir.MagSqr() == 0.f )
				{
					vDir = LTVector( 1.f, 0.f, 0.f );
				}
				vDir.Normalize();

				vNewPos = m_pAI->GetPosition() + vDir;
				vNewPos.y = m_pAI->GetLastVolume()->GetBackBottomLeft().y + m_pAI->GetDims().y;
				m_pAI->Move( vNewPos );

				m_bMoved = LTFALSE;
				return LTTRUE;
			}

			// Ensure AI stays in volumes.

			bMove = LTFALSE;
			m_bMoved = LTFALSE;
			if( m_pAI->GetCurrentVolume() )
			{
				m_vLastValidVolumePos = m_pAI->GetPosition();
			}
			else if( ( !m_bIgnoreVolumes ) && m_pAI->GetLastVolume() )
			{
				vNewPos = m_vLastValidVolumePos;
				bMove = LTTRUE;
			}
			break;

		case kAM_Set:
		case kAM_Walk:
		case kAM_Run:
		case kAM_JumpUp:
		case kAM_JumpOver:
		case kAM_Fall:
		case kAM_Climb:
		case kAM_Swim:

		case kAM_Hover:
			if( (m_eState != eStateSet) || 
				(!UpdateConstantVelocity( eMovementType, &vNewPos ) ) )
			{
				bMove = LTFALSE;
			}
			break;

		case kAM_Encode_NG:
		case kAM_Encode_G:
		case kAM_Encode_GB:
		case kAM_Encode_V:
			if( LTFALSE == UpdateMovementEncoding( eMovementType, &vNewPos ) )
			{
				bMove = LTFALSE;
			}
			break;

		default:
			AIASSERT( 0, m_pAI->GetHOBJECT(), "Unknown Movement type!" );
			break;
	}

	m_pAI->ClearLastHintTransform();

	m_eLastMovementType = eMovementType;

	if( bMove && ( m_pAI->GetPosition() != vNewPos ) )
	{
		// Make sure new position is inside an AI volume.
		// This NEEDS to check eAxisAll with the vertical threshold.

		AIVolume* pVolume = g_pAIVolumeMgr->FindContainingVolume( LTNULL, vNewPos, eAxisAll, m_pAI->GetVerticalThreshold(), m_pAI->GetLastVolume() );		
		if( ( pVolume && pVolume->IsVolumeEnabled() ) || m_bIgnoreVolumes )
		{
			if( m_eState != eStateSet )
			{
				// If an AI is playing a movement encoded animation with
				// gravity, and does not have a destination, do not allow
				// him to move over a large verticle drop.
				// (For example, do not let ninjas fall off roofs while
				// drawing a sword and taking a step).
	
				if( ( ( eMovementType == kAM_Encode_G ) || ( eMovementType == kAM_Encode_GB ) ) && 
					pVolume &&
					( m_vLastValidVolumePos.y > pVolume->GetBackTopLeft().y + m_pAI->GetVerticalThreshold() ) )
				{
					return LTFALSE;
				}

				// If an AI does not have a destination do not allow
				// him to move into a JumpOver volume.

				if( pVolume && ( pVolume->GetVolumeType() == AIVolume::kVolumeType_JumpOver ) )
				{
					return LTFALSE;
				}
			}

			// Adjust the height for a parabola.

			if( m_bDoParabola )
			{
				m_pAI->SetCheapMovement( LTFALSE );
				vNewPos.y = m_vParabolaOrigin.y + UpdateParabola();
			}

			// Do not allow any elevation changes in door volumes.
			// Keeps AI from popping onto doors.

			if( pVolume && pVolume->HasDoors() )
			{
				m_pAI->SetCheapMovement(LTFALSE);
			}

			// Avoid characters if AI has a destination, and movement 
			// is not locked, and AI is in volumes.

			if( ( m_eState == eStateSet ) && 
				( m_pDestVolume ) &&
				( !m_bNoDynamicPathfinding ) &&
				( !m_bIgnoreVolumes ) &&
				( !m_bMovementLocked ) &&
				( !m_bRotationLocked ) &&
				( eMovementType != kAM_Encode_V ) )
			{
				AvoidDynamicObstacles( &vNewPos, eMovementType );
			}

			// Move us - tells the AI where to move to

			m_pAI->Move(vNewPos);
			m_bMoved = LTTRUE;

			// Record last valid volume position.

			if( pVolume )
			{
				m_vLastValidVolumePos = vNewPos;
			}

			// If we reached an intermediate bound point, move on
			// to the next one.

			if( ( m_eState == eStateDone ) && ( m_iBoundPt + 1 < m_cBoundPts ) )
			{
				++m_iBoundPt;
				m_vDest = m_vBoundPts[m_iBoundPt];
				m_eState = eStateSet;
			}

			return LTTRUE;
		}

		// Destination is unreachable by volumes.
		// Put us somewhere valid.

		else if( m_eState == eStateSet )
		{
			m_pAI->Move(m_vLastValidVolumePos);
			m_eState = eStateDone;
			m_bMoved = LTTRUE;
		}
	}

	return LTFALSE;
}
Exemplo n.º 15
0
//*
// ----------------------------------------------------------------------- //
// Returns the vector that the physics would have the object move by.
// ----------------------------------------------------------------------- //
void CalcMotion
(
    MotionInfo* pInfo,
    LTObject*   pObj,           //the object
    LTVector&   dr,             //displacement
    LTVector&   v,              //velocity
    LTVector&   a,              //acceleration
    const bool  bApplyGravity,
    const float dt              //time step
)
{
	LTVector velocityDelta, accelDelta;
	LTVector q, slopeVel, slopeAccel, vel;
	const LTVector *n;
	LTVector objectNormal, vTemp, vTemp2;

	float fExp;
	float timeIntegral;
	float velocityMagSqr, accelMagSqr;
	LTBOOL bFriction;

	bFriction = LTFALSE;
	timeIntegral = dt * dt * 0.5f;	
	velocityMagSqr = v.MagSqr();
	accelMagSqr = a.MagSqr();

	// [KLS - 3/12/02] - Added support for per-object force override...

	LTVector vForce = pObj->GetGlobalForceOverride();
	
	// If the global force override is zero, use the MotionInfo force...

	if (LTVector(0.0, 0.0, 0.0) == vForce)
	{
		vForce = pInfo->m_Force;
	}

	/* 
	// Debug variables
	LTVector vOldAccel, vOldVel, vOldPos;
	vOldAccel = a;
	vOldVel = v;
	vOldPos = pObj->GetPos();
	//*/

	// Stop objects that are moving very slowly...
	if(velocityMagSqr < 0.1f )
	{
		v.Init();
		velocityMagSqr = 0;
	}

	if( accelMagSqr < 0.1f )
	{
		a.Init();
		accelMagSqr = 0;
	}

	// Zero out the displacement to start with.
	dr.Init();

	// Update objects affected by gravity...
	if(bApplyGravity)
	{
		// Add friction to objects standing on something...
		if(pObj->m_pStandingOn)
		{
			// Try to disable their physics.
			if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f )
			{
				pObj->m_Velocity.Init();
				pObj->m_Acceleration.Init();
				pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS;
				return;
			}
			else
			{
				// Check if object on world geometry...
				if( pObj->m_pNodeStandingOn )
				{
					// Calculate vector parallel to plane...
					n = &pObj->m_pNodeStandingOn->GetPlane()->m_Normal;
				}
				else
				{
					// Object standing on another object, so assume opposite to gravity...
					n = &objectNormal;
					objectNormal = -pInfo->m_UnitForce;
				}

				// Calculate the acceleration including the force
				LTVector vAccelWithForce = a + vForce;

				// If we're on a slope that's at enough of an angle, allow it to slide
				LTVector vForceDir = vForce;
				vForceDir.Norm();
				if (vForceDir.Dot(*n) > pInfo->m_SlideRatio)
				{
					float fAccelMag = vAccelWithForce.Mag();
					a = vAccelWithForce - *n * n->Dot(vAccelWithForce);

					// Don't allow it to accelerate up the slope..
					float fAccelDotForce = a.Dot(vForceDir);
					if (fAccelDotForce < 0.0f)
					{
						a -= vForceDir * fAccelDotForce;
					}
					
					a.Norm(fAccelMag);

					// dsi_ConsolePrint("Steep");
				}				
				else
				{
					// Figure out what our new velocity would be if only the force was used (i.e. are they jumping?)
					LTVector vNewVel = v + vForce * dt;
					// If we're going to be moving away from the plane, use the full force
					if (vNewVel.Dot(*n) > 0.01f)
					{
						a = vAccelWithForce;
						// dsi_ConsolePrint("Jump");
					}
					// If the acceleration without the force isn't moving into the surface, project it there
					else if (a.Dot(*n) > 0.01f)
					{
						float fAccelMag = a.Mag();
						a -= *n * (n->Dot(a) + 1.0f);
						a.Norm(fAccelMag);

						bFriction = LTTRUE;

						// dsi_ConsolePrint("Downhill");
					}
					else
					{
						bFriction = LTTRUE;

						// dsi_ConsolePrint("Walk");
					}
				}
			}
		}
		// Otherwise just apply gravity
		else
		{
			a += vForce;
			// dsi_ConsolePrint("Fall");
		}
	}
	// If there's no gravity and they aren't moving, then disable their physics
	else if( velocityMagSqr < 0.1f && accelMagSqr < 0.1f )
	{
		pObj->m_Velocity.Init();
		pObj->m_Acceleration.Init();
		pObj->m_InternalFlags &= ~IFLAG_APPLYPHYSICS;
		return;
	}

	// If friction
	// new velocity is given by:		v = ( a / k ) + ( v_0 - a / k ) * exp( -k * t )
	// new position is given by:		x = x_0 + ( a / k ) * t + ( k * v_0 - a ) * ( 1 - exp( -k * t )) / k^2
	if( bFriction && pObj->m_FrictionCoefficient > 0.0f )
	{
		// Velocity...
		fExp = ( float )exp( -pObj->m_FrictionCoefficient * dt );
		vTemp = a / pObj->m_FrictionCoefficient;
		vTemp2 = v - vTemp;
		vTemp2 *= fExp;
		vel = vTemp2 + vTemp;

		// Position delta...
		dr = vTemp * dt;
		vTemp = v * pObj->m_FrictionCoefficient;
		vTemp -= a;
		vTemp *= (( 1.0f - fExp ) / pObj->m_FrictionCoefficient / pObj->m_FrictionCoefficient);
		dr += vTemp;
		pObj->m_Velocity = vel;
		v = pObj->m_Velocity;
	}
	// If no friction
	// new velocity is given by:	v = v_0 + a * t
	// new position is given by:	x = x_0 + v_0 * t + .5 * a * t^2
	else
	{
		// Find the change in velocity...
		velocityDelta = a * dt;

		// Position delta...
		dr = v * dt;

		vTemp = a * (timeIntegral * 0.5f);
		dr += vTemp;

		// Add the final velocity to the new velocity.
		pObj->m_Velocity += velocityDelta;
		v = pObj->m_Velocity;
	}

	/*
	// Show debug information, filtering out the server-side player object
	if(bApplyGravity)
	{
		dsi_ConsolePrint("Old - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>",
			VEC_EXPAND(vOldAccel), VEC_EXPAND(vOldVel), VEC_EXPAND(vOldPos));

		LTVector vNewAccel, vNewVel, vNewPos;
		vNewAccel = a;
		vNewVel = v;
		vNewPos = vOldPos + dr;

		dsi_ConsolePrint("New   - A:<%7.1f,%7.1f,%7.1f> V:<%7.1f,%7.1f,%7.1f> P:<%7.1f,%7.1f,%7.1f>",
			VEC_EXPAND(vNewAccel), VEC_EXPAND(vNewVel), VEC_EXPAND(vNewPos));
	}
	//*/

	return;
}