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);
	}
}
Esempio n. 2
0
inline void linesystem_CalcExtents(LineSystem *pSystem)
{
	LTVector half;

	half = pSystem->m_MaxPos - pSystem->m_MinPos;
	half *= 0.5f;
	pSystem->m_SystemCenter = pSystem->m_MinPos + half;
	pSystem->m_SystemRadius = half.Mag() + 1.0f;
}
Esempio n. 3
0
void CRagDollDistanceConstraint::Apply(uint32 nPosIndex)
{
	//find the distance between them
	LTVector vToOther = m_pNode[1]->m_vPosition[nPosIndex] - 
						m_pNode[0]->m_vPosition[nPosIndex];

	float fDist = vToOther.Mag();
	float fScale = (fDist - m_fDistance) / fDist;
	
	//now offset the vertices
	m_pNode[0]->m_vPosition[nPosIndex] += vToOther * fScale * m_fNode1Weight;
	m_pNode[1]->m_vPosition[nPosIndex] -= vToOther * fScale * m_fNode2Weight;
}
LTBOOL CProjectile::UpdateDoVectorValues(SURFACE & surf, LTFLOAT fThickness,
                                        LTVector vImpactPos, LTVector & vFrom, LTVector & vTo)
{
	// See if we've traveled the distance...

    LTVector vDistTraveled = vImpactPos - m_vFirePos;
    LTFLOAT fDist = m_fRange - vDistTraveled.Mag();
    if (fDist < 1.0f) return LTTRUE;

	// Just dampen based on the bute file values, don't worry about the
	// surface thinkness...

	m_fInstDamage *= surf.fBulletDamageDampen;
	fDist *= surf.fBulletRangeDampen;

	int nPerturb = surf.nMaxShootThroughPerturb;

	if (nPerturb)
	{
        LTRotation rRot;
        g_pLTServer->AlignRotation(&rRot, &m_vDir, LTNULL);

        LTVector vU, vR, vF;
        g_pLTServer->GetRotationVectors(&rRot, &vU, &vR, &vF);

        LTFLOAT fRPerturb = ((LTFLOAT)GetRandom(-nPerturb, nPerturb))/1000.0f;
        LTFLOAT fUPerturb = ((LTFLOAT)GetRandom(-nPerturb, nPerturb))/1000.0f;

		m_vDir += (vR * fRPerturb);
		m_vDir += (vU * fUPerturb);

		m_vDir.Norm();
	}

	// Make sure we move the from position...

	if (vFrom.Equals(vImpactPos, 1.0f))
	{
		vFrom += m_vDir;
	}
	else
	{
		vFrom = vImpactPos;
	}

	vTo = vFrom + (m_vDir * fDist);

    return LTFALSE;
}
Esempio n. 5
0
HLTSOUND CClientSoundMgr::PlaySound(PlaySoundInfo & psi)
{
	HLTSOUND hSnd = LTNULL;
	if (!GetConsoleInt("SoundEnable",1)) return LTNULL;

	// Play the sound...

	// Optimization, if we can't hear the sound and it isn't looping
	// don't play it!

	if ((psi.m_dwFlags & PLAYSOUND_3D) && 
		!(psi.m_dwFlags & PLAYSOUND_LOOP) && 
		 g_vtSoundPlayOnlyIfHeard.GetFloat())
	{
		LTVector vListenerPos;
		bool bListenerInClient;
		LTRotation rRot;
		g_pLTClient->GetListener(&bListenerInClient, &vListenerPos, &rRot);

		LTVector vPos = psi.m_vPosition - vListenerPos;
		if (vPos.Mag() > psi.m_fOuterRadius)
		{
			return LTNULL;
		}
	}


	LTRESULT hResult = g_pLTClient->SoundMgr()->PlaySound(&psi, hSnd);

	if (hResult != LT_OK)
	{
		g_pLTClient->CPrint("ERROR in CClientSoundMgr::PlaySound() - Couldn't play sound '%s'", psi.m_szSoundName);
		
		return LTNULL;
	}
	
	// [RP] The sound handle that gets passed into PlaySound(), hSnd, will *always* get set.  Since the
	// SoundTracks get recycled if we return hSnd we may be setting a handle to a SoundTrack that will
	// get removed by the engine and put back on the free list.  Any future calls to KillSound() using that
	// handle will be killing the wrong sound or *worse*, a sound that doesn't exist.  Returning the handle 
	// of the PlaySoundInfo struct will ensure we only return a valid handle if explicitly told to (ie. PLAYSOUND_GETHANDLE);

	return psi.m_hSound;
}
Esempio n. 6
0
static void SetFallbackActivationObject(HOBJECT hObj, IntersectQuery* pQuery)
{
	if (!pQuery) 
		return;

	// Use the Query object to determine how far away this object is from the
	// activation start point.  It must be within the activation range for us
	// to use it...

	LTVector vObjPos;
	g_pLTClient->GetObjectPos(hObj, &vObjPos);

	LTVector vDir = (pQuery->m_From - vObjPos);
	float fDist = vDir.Mag();

	// Since fDist is the distance to the center of the object we need to account
	// for the object's radius.  This may give us some false positives since the
	// object's using an axis-aligned bounding box, but a false positive is better
	// than a negative ;).  Since we can't get the object's dims here's a nice
	// magic number for all you kiddies at home that are paying attention...

	fDist -= 35.0f;

	if (fDist > g_vtActivationDistance.GetFloat()) 
		return;


	if (g_adFallbackActivationObject.m_hTarget)
	{
		// Don't set if my current target is activatable (doesn't matter
		// if new one is activatable or not, we'll just keep the one we have)...

		if ( !IsUserFlagSet(g_adFallbackActivationObject.m_hTarget, 
						    (USRFLG_CAN_ACTIVATE | USRFLG_CAN_SEARCH)) )
		{
			g_adFallbackActivationObject.m_hTarget = hObj;
		}
	}
	else
	{
		g_adFallbackActivationObject.m_hTarget = hObj;
	}
}
HLTSOUND CClientSoundMgr::PlaySound(PlaySoundInfo & psi)
{
	HLTSOUND hSnd = LTNULL;
	if (!GetConsoleInt("SoundEnable",1)) return LTNULL;

	// Play the sound...

	// Optimization, if we can't hear the sound and it isn't looping
	// don't play it!

	if ((psi.m_dwFlags & PLAYSOUND_3D) && !(psi.m_dwFlags & PLAYSOUND_LOOP) && 
		g_vtSoundPlayOnlyIfHeard.GetFloat())
	{
		LTVector vListenerPos;
		LTBOOL bListenerInClient;
		LTRotation rRot;
		g_pLTClient->GetListener(&bListenerInClient, &vListenerPos, &rRot);

		LTVector vPos = psi.m_vPosition - vListenerPos;
		if (vPos.Mag() > psi.m_fOuterRadius)
		{
			return LTNULL;
		}
	}

	LTRESULT hResult = g_pLTClient->PlaySound(&psi);

	if (hResult == LT_OK)
	{
		hSnd = psi.m_hSound;
	}
	else
	{
		_ASSERT(LTFALSE);
		m_pInterface->CPrint("ERROR in CClientSoundMgr::PlaySound() - Couldn't play sound '%s'", psi.m_szSoundName);
		return LTNULL;
	}

	return hSnd;
}
Esempio n. 8
0
LTBOOL CAIMovement::IsAtDest(const LTVector& vDest)
{
	LTVector vMove = vDest - m_pAI->GetPosition();

	if ( !m_pAI->GetAnimationContext()->IsPropSet(kAPG_Movement, kAP_ClimbUp) && !m_pAI->GetAnimationContext()->IsPropSet(kAPG_Movement, kAP_ClimbDown) &&
		 !m_pAI->GetAnimationContext()->IsPropSet(kAPG_Movement, kAP_ClimbUp) && !m_pAI->GetAnimationContext()->IsPropSet(kAPG_Movement, kAP_ClimbDown) )
	{
		vMove.y = 0.0f;
	}

	// See if we're already at the dest exactly.

	LTFLOAT fRemainingDist = vMove.Mag();
	if(fRemainingDist == 0.f)
	{
		Clear();
		m_eState = eStateDone;
		return LTTRUE;
	}

	return LTFALSE;
}
Esempio n. 9
0
static void GeneratePolyGridFresnelAlpha(const LTVector& vViewPos, CPolyGridVertex* pVerts, LTPolyGrid* pGrid, uint32 nNumVerts)
{
	//we need to transform the camera position into our view space
	LTMatrix mInvWorldTrans;

	mInvWorldTrans.Identity();
	mInvWorldTrans.SetTranslation(-pGrid->GetPos());

	LTMatrix mOrientation;
	pGrid->m_Rotation.ConvertToMatrix(mOrientation);

	mInvWorldTrans = mOrientation * mInvWorldTrans;

	LTVector vCameraPos = mInvWorldTrans * vViewPos;

	//now generate the internals of the polygrid
	CPolyGridVertex* pCurrVert	= pVerts;
	CPolyGridVertex* pEnd		= pCurrVert + nNumVerts;

	//determine the fresnel table that we are going to be using
	const CFresnelTable* pTable = g_FresnelCache.GetTable(LTMAX(1.0003f, pGrid->m_fFresnelVolumeIOR), pGrid->m_fBaseReflection);

	//use a vector from the camera to the center of the grid to base our approximations off of. The further
	//we get to the edges the more likely this error will be, but it is better than another sqrt per vert
	LTVector vToPGPt;

	while(pCurrVert < pEnd)
	{
		//the correct but slow way, so only do it every once in a while
		//if((pCurrVert - g_TriVertList) % 4 == 0)
		{
			vToPGPt = vCameraPos - pCurrVert->m_Vec;
		}

		pCurrVert->m_nColor |= pTable->GetValue(vToPGPt.Dot(pCurrVert->m_Normal) / vToPGPt.Mag());
		++pCurrVert;
	}
}
LTBOOL CProjectile::HandleVectorImpact(IntersectInfo & iInfo, LTVector & vFrom,
                                     LTVector & vTo)
{
	// Get the surface type...

	SurfaceType eSurfType = GetSurfaceType(iInfo);


	// See if we hit an invisible surface...

	if (eSurfType == ST_INVISIBLE)
	{
		if (!CalcInvisibleImpact(iInfo, eSurfType))
		{
			SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurfType);
            if (!pSurf) return LTTRUE;

			return UpdateDoVectorValues(*pSurf, 0, iInfo.m_Point, vFrom, vTo);
		}
	}


	// See if we hit an object that should be damaged...

    LTBOOL bHitWorld = IsMainWorld(iInfo.m_hObject);

	if (!bHitWorld && eSurfType != ST_LIQUID)
	{
		ImpactDamageObject(m_hFiredFrom, iInfo.m_hObject);
	}


	// If the fire position is the initial fire position, use the flash
	// position when building the impact special fx...

    LTVector vFirePos = (vFrom.Equals(m_vFirePos) ? m_vFlashPos : vFrom);

	AddImpact(iInfo.m_hObject, vFirePos, iInfo.m_Point, iInfo.m_Plane.m_Normal, eSurfType);


	// See if we can shoot through the surface...

	SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurfType);
    if (!pSurf) return LTTRUE;  // Done.

	if (pSurf->bCanShootThrough)
	{
		int nMaxThickness = pSurf->nMaxShootThroughThickness;
		if (nMaxThickness == 0)
		{
			// Special case of always being able to shoot through surface...

			// Calculate new values for next DoVector iteration...

			return UpdateDoVectorValues(*pSurf, 0, iInfo.m_Point, vFrom, vTo);
		}

		// Test if object/wall intersected is thin enough to be shot
		// through...

		// Test object case first...

		if (!bHitWorld && iInfo.m_hObject)
		{
			// Test to see if we can shoot through the object...

            LTVector vDims;
            g_pLTServer->GetObjectDims(iInfo.m_hObject, &vDims);

			if (vDims.x*2.0f >= nMaxThickness &&  vDims.y*2.0f >= nMaxThickness &&
				vDims.z*2.0f >= nMaxThickness)
			{
				// Can't shoot through this object...
                return LTTRUE;
			}
		}

		// Determine if we shot through the wall/object...

		IntersectInfo iTestInfo;
		IntersectQuery qTestInfo;

        qTestInfo.m_From = iInfo.m_Point + (m_vDir * (LTFLOAT)(nMaxThickness + 1));
		qTestInfo.m_To   = iInfo.m_Point - m_vDir;

		qTestInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY;

		qTestInfo.m_FilterFn  = DoVectorFilterFn;
		qTestInfo.m_pUserData = m_hFiredFrom;

        if (g_pLTServer->IntersectSegment(&qTestInfo, &iTestInfo))
		{
			// Calculate new values for next DoVector iteration...

            LTVector vThickness = iTestInfo.m_Point - iInfo.m_Point;
			return UpdateDoVectorValues(*pSurf, vThickness.Mag(), iTestInfo.m_Point, vFrom, vTo);
		}
	}

    return LTTRUE;
}
Esempio n. 11
0
LTBOOL CAIMovementHuman::Update()
{
    LTFLOAT fTimeDelta = g_pLTServer->GetFrameTime();

	switch ( m_eState )
	{
		case eStateUnset:
		{

		}
		break;

		case eStateSet:
		{
			// Set our speed based on our movement type

			if ( GetAI()->GetAnimationContext()->IsPropSet(aniWalk) )
			{
				GetAI()->Walk();
			}
			else if ( GetAI()->GetAnimationContext()->IsPropSet(aniRun) )
			{
				GetAI()->Run();
			}
			else if ( GetAI()->GetAnimationContext()->IsPropSet(aniSwim) )
			{
				GetAI()->Swim();
			}
			else
			{
				// We're not moving yet...

				GetAI()->Stop();
			}

			// Find our unit movement vector

			LTVector vMove = m_vDest - GetAI()->GetPosition();

			if ( !m_bUnderwater )
			{
				vMove.y = 0.0f;
			}

			// See if we'll overshoot our

			LTFLOAT fRemainingDist = vMove.Mag();
			LTFLOAT fMoveDist;

			fMoveDist = GetAI()->GetSpeed()*fTimeDelta;

			// If we'd overshoot our destination, just move us there

			if ( fRemainingDist < fMoveDist )
			{
				fMoveDist = fRemainingDist;
				m_eState = eStateDone;
			}

			// Scale based on our movement distance

			vMove.Norm();
			vMove *= fMoveDist;

			// Calculate our new position

			LTVector vNewPos = GetAI()->GetPosition() + vMove;

			// Move us - this is an expensive call

			GetAI()->Move(vNewPos);

			// Face us in the right direction

			GetAI()->FacePos(vNewPos);
		}
		break;

		case eStateDone:
		{

		}
		break;
	}

	return LTTRUE;
}
Esempio n. 12
0
//function that handles the custom rendering
void CTracerFX::RenderTracer(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera)
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXTracer);

	//first determine the length, position, and U range for this tracer (this allows for some
	//early outs)
	float fTracerLen	= GetTracerLength();
	float fTracerStart	= m_fRayPosition;
	float fTracerEnd	= fTracerStart - fTracerLen;

	if((fTracerStart <= 0.0f) || (fTracerEnd >= m_fRayLength))
	{
		//the tracer has fully gone through the ray, don't render
		return;
	}

	//now we need to clip the extents to the range [0..ray length], and handle cropping of the texture
	float fUMin = 0.0f;
	float fUMax = 1.0f;

	if(fTracerEnd < 0.0f)
	{
		//adjust the U max if we are cropping
		if(GetProps()->m_bCropTexture)
		{
			fUMax += fTracerEnd / fTracerLen;
		}
		fTracerEnd = 0.0f;
	}
	if(fTracerStart >= m_fRayLength)
	{
		//adjust the U min if we are cropping
		if(GetProps()->m_bCropTexture)
		{
			fUMin += (fTracerStart - m_fRayLength) / fTracerLen;
		}
		fTracerStart = m_fRayLength;
	}

	//setup our vertex declaration
	if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK)
		return;

	//bind a quad index stream
	if(pInterface->BindQuadIndexStream() != LT_OK)
		return;

	//sanity check to ensure that we can at least render a sprite
	LTASSERT(QUAD_RENDER_INDEX_STREAM_SIZE >= 6, "Error: Quad index list is too small to render a tracer");
	LTASSERT(DYNAMIC_RENDER_VERTEX_STREAM_SIZE / sizeof(STexTangentSpaceVert) > 4, "Error: Dynamic vertex buffer size is too small to render a tracer");

	//we need to determine the facing of this tracer. This is formed by creating a plane from the points
	//Camera, Start, and another point on the ray. The plane normal is then the up, the right is the ray
	//direction, and the normal is ray cross plane normal. 
	LTVector vStartToCamera = m_vStartPos - tCamera.m_vPos;
	float fMag = vStartToCamera.Mag( );
	if( fMag < 0.00001f )
	{
		vStartToCamera = tCamera.m_rRot.Forward();
	}
	else
	{
		vStartToCamera /= fMag;
	}

	//determine the up vector
	LTVector vUp = vStartToCamera.Cross(m_vDirection);
	vUp.Normalize();

	//now determine the actual normal (doesn't need to be normalized since the vectors are
	//unit length and orthogonal)
	LTVector vNormal = vUp.Cross(m_vDirection);

	//lock down our buffer for rendering
	SDynamicVertexBufferLockRequest LockRequest;
	if(pInterface->LockDynamicVertexBuffer(4, LockRequest) != LT_OK)
		return;

	//fill in our sprite vertices
	STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData;

	//determine the color of this tracer
	float fUnitLifetime = GetUnitLifetime();
	uint32 nColor = CFxProp_Color4f::ToColor(GetProps()->m_cfcColor.GetValue(fUnitLifetime));

	//calculate the front of the tracer in world space
	LTVector vFront = m_vStartPos + m_vDirection * fTracerStart;
	LTVector vBack	= m_vStartPos + m_vDirection * fTracerEnd;

	//and the thickness vector
	float fThickness = GetProps()->m_ffcThickness.GetValue(fUnitLifetime);
	LTVector vThickness = vUp * (fThickness * 0.5f);

	//fill in the particle vertices
	pCurrOut[0].m_vPos = vFront + vThickness;
	pCurrOut[0].m_vUV.Init(fUMin, 0.0f);
	
	pCurrOut[1].m_vPos = vBack + vThickness;
	pCurrOut[1].m_vUV.Init(fUMax, 0.0f);
	
	pCurrOut[2].m_vPos = vBack - vThickness;
	pCurrOut[2].m_vUV.Init(fUMax, 1.0f);

	pCurrOut[3].m_vPos = vFront - vThickness;
	pCurrOut[3].m_vUV.Init(fUMin, 1.0f);

	//setup the remaining vertex components
	for(uint32 nCurrVert = 0; nCurrVert < 4; nCurrVert++)
	{
		pCurrOut[nCurrVert].m_nPackedColor	= nColor;
		pCurrOut[nCurrVert].m_vNormal		= vNormal;
		pCurrOut[nCurrVert].m_vTangent		= vUp;
		pCurrOut[nCurrVert].m_vBinormal		= m_vDirection;
	}

	//unlock and render the batch
	pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest);
	pInterface->RenderIndexed(	eCustomRenderPrimType_TriangleList, 
								0, 6, LockRequest.m_nStartIndex, 
								0, 4);
}
Esempio n. 13
0
bool CTracerFX::Init(const FX_BASEDATA *pBaseData, const CBaseFXProps *pProps)
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXTracer);

	//cleanup any old data
	Term();

	// Perform base class initialisation
	if( !CBaseFX::Init(pBaseData, pProps))
		return false;

	//determine our starting position and orientation
	LTVector vPos;
	LTRotation rRot;

	GetCurrentTransform(0.0f, vPos, rRot);	
	m_vStartPos = vPos;

	//determine what target position we want to use
	LTVector vTargetPos;

	//if we are using target data, just get the transform from this
	if(GetProps()->m_bUseTargetPos && pBaseData->m_bUseTargetData)
	{
		LTRigidTransform tTargetOffset(pBaseData->m_vTargetOffset, LTRotation::GetIdentity());
		LTRigidTransform tWS = GetWorldSpaceTransform(NULL, pBaseData->m_hTargetObject, INVALID_MODEL_NODE, INVALID_MODEL_SOCKET, tTargetOffset);

		LTVector vToTarget = tWS.m_vPos - vPos;
		m_fRayLength	= vToTarget.Mag();
		m_vDirection	= vToTarget / m_fRayLength;
		vTargetPos		= tWS.m_vPos;
	}
	else
	{
		//determine the end point where we want to stop testing
		m_vDirection	= rRot.Forward();
		m_fRayLength	= GetProps()->m_fMaxDistance;
		vTargetPos		= vPos + m_vDirection * m_fRayLength;
	}

	//handle intersection if we need to
	if(GetProps()->m_bBlockedByGeometry)
	{
		//we need to perform a ray cast and determine if we actually hit anything in the world. If not,
		//we just want to use the maximum tracer length
		IntersectQuery	iQuery;
		IntersectInfo	iInfo;

		iQuery.m_Flags		= INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID;
		iQuery.m_FilterFn	= TracerListFilterFn;
		iQuery.m_pUserData	= NULL;
		iQuery.m_From		= m_vStartPos;
		iQuery.m_To			= vTargetPos;

		//now find the point of intersection
		if( g_pLTClient->IntersectSegment( iQuery, &iInfo ) )
		{
			//we hit something, so use that as our ending position
			m_fRayLength = (iInfo.m_Point - m_vStartPos).Mag();
		}
	}

	//now determine our starting position (this is zero unless we start emitted, in which case
	//it is the length of the tracer)
	if(GetProps()->m_bStartEmitted)
	{
		//determine the length of this tracer
		m_fRayPosition = GetTracerLength();
	}
	
	// Combine the direction we would like to face with our parents rotation...
	ObjectCreateStruct ocs;
	
	//create a custom render object with the associated material
	ocs.m_Pos				= vPos;
	ocs.m_Rotation			= rRot;
	ocs.m_ObjectType		= OT_CUSTOMRENDER;
	
	if(!GetProps()->m_bSolid)
		ocs.m_Flags2 |= FLAG2_FORCETRANSLUCENT;

	if(!GetProps()->m_bTranslucentLight)
		ocs.m_Flags |= FLAG_NOLIGHT;
	
	m_hObject = g_pLTClient->CreateObject( &ocs );
	if( !m_hObject )
		return false;

	//setup our rendering layer
	if(GetProps()->m_bPlayerView)
		g_pLTClient->GetRenderer()->SetObjectDepthBiasTableIndex(m_hObject, eRenderLayer_Player);

	//setup the callback on the object so that it will render us
	g_pLTClient->GetCustomRender()->SetRenderingSpace(m_hObject, eRenderSpace_World);
	g_pLTClient->GetCustomRender()->SetRenderCallback(m_hObject, CustomRenderCallback);
	g_pLTClient->GetCustomRender()->SetCallbackUserData(m_hObject, this);

	//load up the material for this particle system, and assign it to the object
	HMATERIAL hMaterial = g_pLTClient->GetRenderer()->CreateMaterialInstance(GetProps()->m_pszMaterial);
	g_pLTClient->GetCustomRender()->SetMaterial(m_hObject, hMaterial);
	g_pLTClient->GetRenderer()->ReleaseMaterialInstance(hMaterial);

	//we don't setup the visibility for this object yet since when it starts out it is not visible

	//setup the dynamic light object if the user specified a radius
	if(GetProps()->m_fLightRadius > 0.1f)
	{
		ObjectCreateStruct LightOCS;
		LightOCS.m_Pos			= vPos;
		LightOCS.m_Rotation		= rRot;
		LightOCS.m_ObjectType	= OT_LIGHT;

		m_hTracerLight = g_pLTClient->CreateObject( &LightOCS );

		//setup the properties of the light
		g_pLTClient->SetLightRadius(m_hTracerLight, GetProps()->m_fLightRadius);
		g_pLTClient->SetObjectColor(m_hTracerLight, VEC4_EXPAND(GetProps()->m_vLightColor));
		g_pLTClient->SetLightType(m_hTracerLight, eEngineLight_Point);
		g_pLTClient->SetLightDetailSettings(m_hTracerLight, GetProps()->m_eLightLOD, GetProps()->m_eWorldShadowsLOD, GetProps()->m_eObjectShadowsLOD);
	}

	// Success !!
	return true;
}
Esempio n. 14
0
LTBOOL CAIMovementHelicopter::Update()
{
    LTFLOAT fTimeDelta = g_pLTServer->GetFrameTime();

	switch ( m_eState )
	{
		case eStateUnset:
		{

		}
		break;

		case eStateSet:
		{
			// Find our unit movement vector

			LTVector vMove = m_vDest - GetAI()->GetPosition();
//			vMove.y = 0.0f;

			// See if we'll overshoot our

			LTFLOAT fRemainingDist = vMove.Mag();
			LTFLOAT fMoveDist;

			fMoveDist = GetAI()->GetSpeed()*fTimeDelta;

			vMove.Norm();

			LTBOOL bCrossed = LTFALSE;

			// See if we crossed the dest plane

			if ( (vMove.Dot(m_vDestDir) < 0.0f) )
			{
				bCrossed = LTTRUE;
			}

			// If we'd overshoot our destination, just move us there

			if ( (fRemainingDist < fMoveDist) || bCrossed )
			{
				fMoveDist = fRemainingDist;
				m_eState = eStateDone;
			}

			// Scale based on our movement distance

			vMove *= fMoveDist;

			// Calculate our new position

			LTVector vNewPos = GetAI()->GetPosition() + vMove;

			// Move us - this is an expensive call

//			GetAI()->Move(vNewPos);

			// Face us in the right direction

			GetAI()->FacePos(vNewPos);
		}
		break;

		case eStateDone:
		{
		}
		break;
	}

	return LTTRUE;
}
Esempio n. 15
0
LTBOOL CSearchLightFX::Update()
{
    if (!m_pClientDE || !m_hServerObject || m_bWantRemove || !m_hBeam) return LTFALSE;

    uint32 dwFlags = 0;

	// Update the lens flare...

	m_LensFlare.Update();

	// Hide/show the fx if necessary...

	if (m_hServerObject)
	{
        uint32 dwUserFlags;
		m_pClientDE->GetObjectUserFlags(m_hServerObject, &dwUserFlags);

		if (!(dwUserFlags & USRFLG_VISIBLE))  // Hide fx
		{
			if (m_hBeam)
			{
				dwFlags = m_pClientDE->GetObjectFlags(m_hBeam);
				m_pClientDE->SetObjectFlags(m_hBeam, dwFlags & ~FLAG_VISIBLE);
			}
			if (m_hLight)
			{
				dwFlags = m_pClientDE->GetObjectFlags(m_hLight);
				m_pClientDE->SetObjectFlags(m_hLight, dwFlags & ~FLAG_VISIBLE);
			}

            return LTTRUE;
		}
		else  // Make all fx visible
		{
			if (m_hBeam)
			{
				dwFlags = m_pClientDE->GetObjectFlags(m_hBeam);
				m_pClientDE->SetObjectFlags(m_hBeam, dwFlags | FLAG_VISIBLE);
			}
			if (m_hLight)
			{
				dwFlags = m_pClientDE->GetObjectFlags(m_hLight);
				m_pClientDE->SetObjectFlags(m_hLight, dwFlags | FLAG_VISIBLE);
			}
		}
	}


	// Update the position/rotation of the beam...

    LTVector vPos;
	m_pClientDE->GetObjectPos(m_hServerObject, &vPos);

    LTRotation rRot;
	m_pClientDE->GetObjectRotation(m_hServerObject, &rRot);

    LTVector vU, vR, vF;
	m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);


	// See how long to make the beam...

    LTVector vDest = vPos + (vF * m_cs.fBeamLength);

	IntersectInfo iInfo;
	IntersectQuery qInfo;
	qInfo.m_Flags		= INTERSECT_OBJECTS | IGNORE_NONSOLID;
	qInfo.m_FilterFn	= AttackerLiquidFilterFn;
	qInfo.m_pUserData	= m_hServerObject;
	qInfo.m_From		= vPos;
	qInfo.m_To			= vDest;

    if (g_pLTClient->IntersectSegment(&qInfo, &iInfo))
	{
		vDest = iInfo.m_Point;
	}

    LTVector vDir = vDest - vPos;
    LTFLOAT fDistance = vDir.Mag();
	vDir.Norm();

    LTVector vNewPos = vPos + vDir * fDistance/2.0f;
	m_pClientDE->AlignRotation(&rRot, &vDir, NULL);

	if (m_cs.fBeamRotTime > 0.0f)
	{
		m_fBeamRotation += (360.0f/m_cs.fBeamRotTime * g_pGameClientShell->GetFrameTime());
		m_fBeamRotation = m_fBeamRotation > 360.0f ? m_fBeamRotation - 360.0f : m_fBeamRotation;
		m_pClientDE->RotateAroundAxis(&rRot, &vDir, DEG2RAD(m_fBeamRotation));
	}

	m_pClientDE->SetObjectRotation(m_hBeam, &rRot);
	m_pClientDE->SetObjectPos(m_hBeam, &vNewPos);

    LTVector vScale(m_cs.fBeamRadius, m_cs.fBeamRadius, fDistance);
	m_pClientDE->SetObjectScale(m_hBeam, &vScale);


	// Move the dynamic light...

	if (m_hLight)
	{
		vDest -= (vDir * 5.0f);
		m_pClientDE->SetObjectPos(m_hLight, &vDest);
	}

    return LTTRUE;
}
Esempio n. 16
0
void CAIMovement::AvoidDynamicObstacles(LTVector* pvNewPos, EnumAnimMovement eMovementType)
{
	LTFLOAT fRadius = 128.f;
	LTFLOAT fRadiusSqr = fRadius * fRadius;

	LTVector vMyPos = m_pAI->GetPosition();

	// Calculate the horizontal velocity.

	LTVector vVel = *pvNewPos - vMyPos;
	vVel.y = 0.f;

	// Bail if no velocity.

	if( ( vVel.x == 0.f ) && ( vVel.z == 0.f ) )
	{
		return;
	}

	LTFLOAT fMag = vVel.Mag();

	LTVector vTotalForce(0.f, 0.f, 0.f);
	LTVector vObstaclePos;
	LTFLOAT fDistSqr;
	LTFLOAT fForce;
	LTVector vForce;

	CTList<CCharacter*>* lstChars	= LTNULL;
	CCharacter** pCur				= LTNULL;

	// Iterate over all characters in the world.

	int cCharLists = g_pCharacterMgr->GetNumCharacterLists();
	for ( int iList = 0 ; iList < cCharLists ; ++iList )
	{
		lstChars = g_pCharacterMgr->GetCharacterList(iList);

		pCur = lstChars->GetItem(TLIT_FIRST);
		while( pCur )
		{
			CCharacter* pChar = (CCharacter*)*pCur;
			pCur = lstChars->GetItem(TLIT_NEXT);

			// Ignore myself.

			if( pChar == m_pAI )
			{
				continue;
			}

			// Ignore characters that are too close to our dest.
			// The pathfinding system requires AIs to reach waypoints.

			g_pLTServer->GetObjectPos( pChar->m_hObject, &vObstaclePos );
			if( vObstaclePos.DistSqr( m_vDest ) <= fRadiusSqr )
			{
				continue;
			}

			// Only characters within radius have forces that affect me.

			fDistSqr = vObstaclePos.DistSqr( vMyPos );
			if( fDistSqr >= fRadiusSqr )
			{
				continue;
			}

			// Calculate the force vector from the obstacle to myself.

			fForce = fRadius - (LTFLOAT)sqrt( fDistSqr );
			fForce /= fRadius;
			fForce *= fForce;
			fForce *= ( 2.f * fMag );

			vForce = vMyPos - vObstaclePos;
			vForce.y = 0.f;
			vForce.Normalize();
			vForce *= fForce;

			// Accumulate the total force from all obstacles.

			vTotalForce += vForce;			
		}
	}

	// Bail if no forces are affecting me.

	if( ( vTotalForce.x == 0.f ) && ( vTotalForce.z == 0.f ) )
	{
		return;
	}

	// Calculate a new velocity vector.

	LTVector vNewVel = vVel + vTotalForce;

	// Constrain velocity so that is never deviates more than 
	// 90 degrees in either direction.  This prevents AIs from ever
	// reversing their direction when the forces are stronger than
	// the initial velocity.

	if( vNewVel.Dot( vVel ) < 0.f )
	{
		vVel.Normalize();
		LTVector vUp( 0.f, 1.f, 0.f );
		LTVector vRight = vUp.Cross( vVel );

		if( vRight.Dot( vNewVel ) < 0.f )
		{
			vNewVel = -vRight;
		}
		else {
			vNewVel = vRight;
		}
	}

	// Keep magnitude of velocity constant.

	vNewVel.Normalize();
	vNewVel *= fMag;

	// Calculate new position.
	// Bail if new position is out of volumes.
	// Bail if new position is in wrong volume.

	LTVector vNewPos = vMyPos + vNewVel;
	if( !m_pDestVolume->Inside2d( vNewPos, m_pAI->GetRadius() ) )
	{
		return;
	}


	// Move toward new position.

	*pvNewPos = vNewPos;

	if( eMovementType == kAM_Encode_GB )
	{
		m_pAI->FacePosMoving( m_pAI->GetPosition() );
	}
	else {
		m_pAI->FacePosMoving( vNewPos );
	}
}
Esempio n. 17
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;
    }
}
Esempio n. 18
0
//function that handles the custom rendering
void CBaseSpriteFX::RenderSprite(ILTCustomRenderCallback* pInterface, const LTRigidTransform& tCamera)
{
	//setup our vertex declaration
	if(pInterface->SetVertexDeclaration(g_ClientFXVertexDecl.GetTexTangentSpaceDecl()) != LT_OK)
		return;

	//bind a quad index stream
	if(pInterface->BindQuadIndexStream() != LT_OK)
		return;

	//determine how many indices we are going to need
	uint32 nNumIndices  = (GetProps()->m_bTwoSided) ? 12 : 6;
	uint32 nNumVertices = (GetProps()->m_bTwoSided) ? 8 : 4;

	//sanity check to ensure that we can at least render a sprite
	LTASSERT(QUAD_RENDER_INDEX_STREAM_SIZE >= nNumIndices, "Error: Quad index list is too small to render a sprite");
	LTASSERT(DYNAMIC_RENDER_VERTEX_STREAM_SIZE / sizeof(STexTangentSpaceVert) >= nNumVertices, "Error: Dynamic vertex buffer size is too small to render a sprite");

	//determine the up and right vectors for the sprite
	LTVector vTangent, vBinormal;

	//get the position of this sprite
	LTRigidTransform tObjTransform;
	g_pLTClient->GetObjectTransform(m_hObject, &tObjTransform);

	//determine the center of this sprite
	LTVector vCenter = tObjTransform.m_vPos;

	//determine the orientation of the sprite based upon its facing
	if(GetProps()->m_bAlignToCamera)
	{
		//apply the to camera offset
		LTVector vToCamera = tCamera.m_vPos - vCenter;
		float fScale = GetProps()->m_fToCameraOffset / vToCamera.Mag();
		vCenter += vToCamera * fScale;

		//perform the rotation
		float fCosAng = LTCos(m_fCurrRotationRad);
		float fSinAng = LTSin(m_fCurrRotationRad);

		LTVector vRight = tCamera.m_rRot.Right();
		LTVector vUp = -tCamera.m_rRot.Up();

		vTangent	= fCosAng * vRight + fSinAng * vUp;
		vBinormal	= fCosAng * vUp - fSinAng * vRight;
	}
	else if(GetProps()->m_bAlignAroundZ)
	{
		//we want to orient around the Z axis and align to the camera

		//we need to determine our U vector, which is always our forward
		LTVector vU = tObjTransform.m_rRot.Forward();

		//and now we want to offset our center so that we are anchored on the right hand
		//side of the sprite to the point
		vCenter += vU * (m_fWidth * 0.5f);

		//determine the axis from our camera to our object
		LTVector vToCamera = tCamera.m_vPos - vCenter;

		//and now derive our V vector from the forward and the direction to the camera
		LTVector vV = vToCamera.Cross(vU);

		//detect degenerate cases
		if(vV == LTVector::GetIdentity())
		{
			//degenerate case, any orientation will work fine since the sprite won't
			//be visible anyway
			vV.Init(0.0f, 1.0f, 0.0f);
		}

		//and normalize our vector
		vV.Normalize();

		//now we can determine our tangent and binormal vectors
		vTangent	= -vU;
		vBinormal	= vV;
	}
	else
	{
		vTangent	= -tObjTransform.m_rRot.Right();
		vBinormal	= -tObjTransform.m_rRot.Up();
	}
	
	LTVector vNormal = vBinormal.Cross(vTangent);

	//scale the right and down values to be the appropriate size
	LTVector vRight	= vTangent * m_fWidth * -0.5f;
	LTVector vDown	= vBinormal * m_fWidth * GetProps()->m_fAspectRatio * 0.5f;


	//lock down our buffer for rendering
	SDynamicVertexBufferLockRequest LockRequest;
	if(pInterface->LockDynamicVertexBuffer(nNumVertices, LockRequest) != LT_OK)
		return;

	//fill in our sprite vertices
	STexTangentSpaceVert* pCurrOut = (STexTangentSpaceVert*)LockRequest.m_pData;

	uint32 nColor = SETRGBA(	(uint8)(m_vColor.x * 255.0f), 
								(uint8)(m_vColor.y * 255.0f), 
								(uint8)(m_vColor.z * 255.0f), 
								(uint8)(m_vColor.w * 255.0f));

	//fill in the particle vertices
	pCurrOut[0].m_vPos = vCenter + vRight - vDown;
	pCurrOut[0].m_vUV.Init(0.0f, 0.0f);
	
	pCurrOut[1].m_vPos = vCenter - vRight - vDown;
	pCurrOut[1].m_vUV.Init(1.0f, 0.0f);
	
	pCurrOut[2].m_vPos = vCenter - vRight + vDown;
	pCurrOut[2].m_vUV.Init(1.0f, 1.0f);

	pCurrOut[3].m_vPos = vCenter + vRight + vDown;
	pCurrOut[3].m_vUV.Init(0.0f, 1.0f);

	//setup the remaining vertex components
	for(uint32 nCurrVert = 0; nCurrVert < 4; nCurrVert++)
	{
		pCurrOut[nCurrVert].m_nPackedColor = nColor;
		pCurrOut[nCurrVert].m_vNormal = vNormal;
		pCurrOut[nCurrVert].m_vTangent = vTangent;
		pCurrOut[nCurrVert].m_vBinormal = vBinormal;
	}

	//and fill in the back side if appropriate
	if(GetProps()->m_bTwoSided)
	{
		pCurrOut[4].m_vPos = vCenter - vRight - vDown;
		pCurrOut[4].m_vUV.Init(1.0f, 0.0f);
		
		pCurrOut[5].m_vPos = vCenter + vRight - vDown;
		pCurrOut[5].m_vUV.Init(0.0f, 0.0f);
		
		pCurrOut[6].m_vPos = vCenter + vRight + vDown;
		pCurrOut[6].m_vUV.Init(0.0f, 1.0f);

		pCurrOut[7].m_vPos = vCenter - vRight + vDown;
		pCurrOut[7].m_vUV.Init(1.0f, 1.0f);

		//setup the remaining vertex components
		for(uint32 nCurrVert = 4; nCurrVert < 8; nCurrVert++)
		{
			pCurrOut[nCurrVert].m_nPackedColor = nColor;
			pCurrOut[nCurrVert].m_vNormal = -vNormal;
			pCurrOut[nCurrVert].m_vTangent = -vTangent;
			pCurrOut[nCurrVert].m_vBinormal = vBinormal;
		}
	}

	//unlock and render the batch
	pInterface->UnlockAndBindDynamicVertexBuffer(LockRequest);
	pInterface->RenderIndexed(	eCustomRenderPrimType_TriangleList, 
								0, nNumIndices, LockRequest.m_nStartIndex, 
								0, nNumVertices);
}
Esempio n. 19
0
void CPolygonDebrisFX::CreateDebris(int i, LTVector vPos)
{
	if (i < 0 || i >= m_ds.nNumDebris || i != m_nNumPolies || (m_Polies[i] != LTNULL)) return;

	// Create a poly debris object...

	PLFXCREATESTRUCT pls;

    LTVector vLength = (m_cs.vDir * GetRandom(m_cs.PolyDebrisFX.fMinLength, m_cs.PolyDebrisFX.fMaxLength)) / 2.0f;

    LTVector vMinC1 = m_cs.PolyDebrisFX.vMinColor1;
    LTVector vMaxC1 = m_cs.PolyDebrisFX.vMaxColor1;
    LTVector vMinC2 = m_cs.PolyDebrisFX.vMinColor2;
    LTVector vMaxC2 = m_cs.PolyDebrisFX.vMaxColor2;

	pls.pTexture			= m_cs.PolyDebrisFX.szTexture[0] ? m_cs.PolyDebrisFX.szTexture : LTNULL;
	pls.vStartPos			= vPos - vLength;
	pls.vEndPos				= vPos + vLength;
    pls.vInnerColorStart    = LTVector(GetRandom(vMinC1.x, vMaxC1.x), GetRandom(vMinC1.y, vMaxC1.y), GetRandom(vMinC1.z, vMaxC1.z));
    pls.vInnerColorEnd      = LTVector(GetRandom(vMinC2.x, vMaxC2.x), GetRandom(vMinC2.y, vMaxC2.y), GetRandom(vMinC2.z, vMaxC2.z));
	pls.vOuterColorStart	= pls.vInnerColorStart;
	pls.vOuterColorEnd		= pls.vInnerColorEnd;
	pls.fAlphaStart			= m_cs.PolyDebrisFX.fInitialAlpha;
	pls.fAlphaEnd			= m_cs.PolyDebrisFX.fFinalAlpha;
	pls.fMinWidth			= 0.0f;
	pls.fMaxWidth			= GetRandom(m_cs.PolyDebrisFX.fMinWidth, m_cs.PolyDebrisFX.fMaxWidth);
	pls.fLifeTime			= GetDebrisLife(i);
	pls.fAlphaLifeTime		= GetDebrisLife(i);
	pls.bAdditive			= m_cs.PolyDebrisFX.bAdditive;
	pls.bMultiply			= m_cs.PolyDebrisFX.bMultiply;
	pls.bDontFadeAlphaAtEdge= !m_cs.PolyDebrisFX.bAdditive;
	pls.nWidthStyle			= m_cs.PolyDebrisFX.nStyle > PLWS_CONSTANT ? GetRandom(PLWS_BIG_TO_SMALL, PLWS_CONSTANT) : m_cs.PolyDebrisFX.nStyle;
	pls.bUseObjectRotation	= !m_cs.PolyDebrisFX.bShowTrail;
	pls.bNoZ				= m_cs.PolyDebrisFX.bShowTrail;
	pls.nNumSegments		= 1;

	pls.fMinDistMult		= 1.0f;
	pls.fMaxDistMult		= 1.0f;
	pls.fPerturb			= 0.0f;

	// Scale the width based on the distance the camera is away from the
	// origin of the debris...
	
	HLOCALOBJ hCamera = g_pGameClientShell->GetCamera();
    if (hCamera)
	{
		LTVector vCamPos;
		g_pLTClient->GetObjectPos(hCamera, &vCamPos);

		vCamPos -= vPos;
		LTFLOAT fScaleVal = vCamPos.Mag() / g_cvarPolyDebrisScaleDist.GetFloat();

		fScaleVal = (fScaleVal < g_cvarPolyDebrisMinDistScale.GetFloat() ? g_cvarPolyDebrisMinDistScale.GetFloat() 
			: (fScaleVal > g_cvarPolyDebrisMaxDistScale.GetFloat() ? g_cvarPolyDebrisMaxDistScale.GetFloat() : fScaleVal));

		pls.fMaxWidth *= fScaleVal;
	}

	CPolyLineFX *pNewPoly = GetPolyLineFXBank()->New();

	if (!pNewPoly->Init(&pls) ||
		!pNewPoly->CreateObject(m_pClientDE))
	{
		GetPolyLineFXBank()->Delete(pNewPoly);
		return;
	}
	else
	{
		m_Polies[m_nNumPolies] = pNewPoly;
	}

	m_nNumPolies++;
}
Esempio n. 20
0
bool CAIWeaponAbstract::DefaultThrow(CAI* pAI)
{
	// Make sure the basic pointers are valid.
	ASSERT(m_pWeapon);
	ASSERT(pAI);
	if (!pAI || !m_pWeapon || !m_pAIWeaponRecord)
	{
		return false;
	}

	// Don't fire if AI has no target.

	if( !pAI->HasTarget( kTarget_Character | kTarget_Object ) )
	{
		return false;
	}

	HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject();

	// Throw at the last known position.

	LTVector vTargetPos;
	CAIWMFact factTargetQuery;
	factTargetQuery.SetFactType( kFact_Character );
	factTargetQuery.SetTargetObject( hTarget );
	CAIWMFact* pFact = pAI->GetAIWorkingMemory()->FindWMFact( factTargetQuery );
	if( pFact )
	{
		vTargetPos = pFact->GetPos();
	}
	else {
		g_pLTServer->GetObjectPos(hTarget, &vTargetPos);
	}


	// Offset the target pos a little so projectile lands in front of the target.

	LTVector vOffsetDir;
	vOffsetDir = pAI->GetPosition() - vTargetPos;
	vOffsetDir.y = 0.f;
	vOffsetDir.Normalize();
	vTargetPos += vOffsetDir * 384.f; 

	// Get our fire position

	LTVector vFirePos = GetFirePosition(pAI);

	// Velocity Vo

	LTVector vGravity;
	g_pPhysicsLT->GetGlobalForce( vGravity );

	// Vo = (S - R - 1/2*G*t^2) / t         
	// Vo = initial velocity
	// S = destination
	// R = origin
	// G = gravity
	// t = hangtime

	float fHangtime = 0.5f;
	LTVector vVelocity = ( vTargetPos - vFirePos - vGravity * .5f * fHangtime * fHangtime ) / fHangtime;
	float fVelocity = vVelocity.Mag();
	LTVector vDir( vVelocity / fVelocity );

	// Now fire the weapon

	WeaponFireInfo weaponFireInfo;
	static uint8 s_nCount = GetRandom( 0, 255 );
	s_nCount++;

	weaponFireInfo.hFiredFrom = pAI->GetHOBJECT();
	weaponFireInfo.vPath = vDir;
	weaponFireInfo.bOverrideVelocity = LTTRUE;
	weaponFireInfo.fOverrideVelocity = fVelocity;
	weaponFireInfo.vFirePos	= vFirePos;
	weaponFireInfo.vFlashPos = vFirePos;
	weaponFireInfo.hTestObj	= hTarget;
	weaponFireInfo.fPerturb = 1.0f * (1.0f - pAI->GetAccuracy() );
	weaponFireInfo.nSeed = (uint8)GetRandom( 2, 255 );
	weaponFireInfo.nPerturbCount = s_nCount;
	weaponFireInfo.nFireTimestamp = g_pLTServer->GetRealTimeMS( );

	m_pWeapon->ReloadClip( LTFALSE );

	if (m_pAIWeaponRecord->bAllowAmmoGeneration)
	{
		m_pWeapon->GetArsenal()->AddAmmo( m_pWeapon->GetAmmoRecord(), 999999 );
	}

	m_pWeapon->UpdateWeapon( weaponFireInfo, LTTRUE );

	return true;
}
Esempio n. 21
0
void CTargetMgr::CheckForIntersect(float &fDistAway)
{
	m_hTarget = NULL;
	m_ActivationData.Init();


	// Cast ray from the camera to see if there is an object to activate...

	LTRotation const& rRot = g_pPlayerMgr->GetPlayerCamera()->GetCameraRotation( );;
	LTVector const& vPos = g_pPlayerMgr->GetPlayerCamera()->GetCameraPos( );

 	m_ActivationData.m_vPos = vPos;
	m_ActivationData.m_rRot = rRot;

	IntersectQuery IQuery;
	IntersectInfo IInfo;

	IQuery.m_From = vPos;
	IQuery.m_To   = IQuery.m_From + (rRot.Forward() * kMaxDistance);

	// NOTE the use of the CHECK_FROM_POINT_INSIDE_OBJECTS flag.  This flag will
	// make sure that any objects that m_From is inside are considered
	IQuery.m_Flags = CHECK_FROM_POINT_INSIDE_OBJECTS | INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID;

	IQuery.m_FilterActualIntersectFn	= ActivateFilterFn;
	IQuery.m_pActualIntersectUserData	= (void*)&IQuery;
	IQuery.m_PolyFilterFn				= NULL;

	// [KLS 8/3/02] - ActivateFilterFn may save an object to use that may not be
	// the best activation choice (i.e., a fallback choice).  However, if a
	// better choice isn't found, the fallback choice should be used.  That
	// fallback choice is stored in g_adFallbackActivationObject so we clear
	// it here...
	g_adFallbackActivationObject.Init();

	if (g_pLTClient->IntersectSegment(IQuery, &IInfo))
	{
		m_ActivationData.m_vIntersect = IInfo.m_Point;

		bool bHitSky = false;

        if (IsMainWorld(IInfo.m_hObject))
		{
			if (IInfo.m_hPoly != INVALID_HPOLY)
			{
				SurfaceType eType = GetSurfaceType(IInfo.m_hPoly);
				HSURFACE hSurf = g_pSurfaceDB->GetSurface(eType);

				// See if the surface we tried to activate has an activation
				// sound...If so, the user can activate it...

				if (hSurf)
				{
					HRECORD hActSnd = g_pSurfaceDB->GetRecordLink(hSurf,SrfDB_Srf_rActivationSnd);
					if (hActSnd && g_pSoundDB->GetFloat(hActSnd,SndDB_fOuterRadius) > 0) 
					{
						m_hTarget = IInfo.m_hObject;
						m_ActivationData.m_hTarget = m_hTarget;
						m_ActivationData.m_nSurfaceType = eType;
						m_ActivationData.m_hActivateSnd = hActSnd;
					}

					bHitSky = (ST_SKY == eType);
				}
			}
		}
		else
		{
			LTVector vObjPos = m_ActivationData.m_vIntersect;
			vObjPos -= vPos;

			if (vObjPos.Mag() <= kMaxDistance)
			{
				m_hTarget = IInfo.m_hObject;
				m_ActivationData.m_hTarget = m_hTarget;
			}
		}

		// Calculate how far away the object is...

		LTVector vDist = m_ActivationData.m_vIntersect - vPos;
		if (bHitSky)
			fDistAway = kMaxDistance;
		else
			fDistAway = vDist.Mag();
	}
	
	// [KLS 8/3/02] - Use the fallback object if we have one and we didn't 
	// find another object more suitable object... 

	bool bCanUseFallback = (m_ActivationData.m_hTarget ? false : true);
	if (!bCanUseFallback)
	{
		// We can still use the fallback object if it isn't the world or a
		// world model...

		if (IsMainWorld(m_ActivationData.m_hTarget) || 
			OT_WORLDMODEL == GetObjectType(m_ActivationData.m_hTarget))
		{
			bCanUseFallback = true;
		}
	}

	if ( bCanUseFallback && g_adFallbackActivationObject.m_hTarget )
	{
		// Ok we hit the fallback object reset some of our target data
	
		LTVector vObjPos;
		g_pLTClient->GetObjectPos(g_adFallbackActivationObject.m_hTarget, &vObjPos);

		m_ActivationData.m_vIntersect = vObjPos;

		vObjPos -= vPos;

		if (vObjPos.Mag() <= kMaxDistance)
		{
			m_hTarget = g_adFallbackActivationObject.m_hTarget;
			m_ActivationData.m_hTarget = m_hTarget;
		}

		// Calculate how far away the object is...

		LTVector vDist = m_ActivationData.m_vIntersect - vPos;
		fDistAway = vDist.Mag();
	}
}
Esempio n. 22
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;
}
Esempio n. 23
0
void CTargetMgr::CheckForIntersect(float &fDistAway)
{
	m_hTarget = LTNULL;
	m_ActivationData.Init();

	uint32 dwUsrFlags = 0;
	const float fMaxDist = 100000.0f;

	// Cast ray from the camera to see if there is an object to activate...

    LTRotation rRot;
    LTVector vPos;

	HLOCALOBJ hCamera = g_pPlayerMgr->GetCamera();
	g_pLTClient->GetObjectPos(hCamera, &vPos);
	g_pLTClient->GetObjectRotation(hCamera, &rRot);

 	m_ActivationData.m_vPos = vPos;
	m_ActivationData.m_rRot = rRot;

	IntersectQuery IQuery;
	IntersectInfo IInfo;

	IQuery.m_From = vPos;
	IQuery.m_To   = IQuery.m_From + (rRot.Forward() * fMaxDist);

	// NOTE the use of the CHECK_FROM_POINT_INSIDE_OBJECTS flag.  This flag will
	// make sure that any objects that m_From is inside are considered
	IQuery.m_Flags = CHECK_FROM_POINT_INSIDE_OBJECTS | INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID;

	IQuery.m_FilterActualIntersectFn	= ActivateFilterFn;
	IQuery.m_pActualIntersectUserData	= (void*)&IQuery;
	IQuery.m_PolyFilterFn				= DoVectorPolyFilterFn;

	// [KLS 8/3/02] - ActivateFilterFn may save an object to use that may not be
	// the best activation choice (i.e., a fallback choice).  However, if a
	// better choice isn't found, the fallback choice should be used.  That
	// fallback choice is stored in g_adFallbackActivationObject so we clear
	// it here...
	g_adFallbackActivationObject.Init();

	if (g_pLTClient->IntersectSegment(&IQuery, &IInfo))
	{
		m_ActivationData.m_vIntersect = IInfo.m_Point;

        if (IsMainWorld(IInfo.m_hObject))
		{
			if (IInfo.m_hPoly != INVALID_HPOLY)
			{
				SurfaceType eType = GetSurfaceType(IInfo.m_hPoly);
				SURFACE *pSurf = g_pSurfaceMgr->GetSurface(eType);

				// See if the surface we tried to activate has an activation
				// sound...If so, the user can activate it...

				if (pSurf && pSurf->szActivationSnd[0] && pSurf->fActivationSndRadius > 0)
				{
					m_hTarget = IInfo.m_hObject;
					m_ActivationData.m_hTarget = m_hTarget;
					m_ActivationData.m_nSurfaceType = eType;
				}
			}
		}
		else
		{
			LTVector vObjPos = m_ActivationData.m_vIntersect;
			vObjPos -= vPos;

			if (vObjPos.Mag() <= fMaxDist)
			{
				m_hTarget = IInfo.m_hObject;
				m_ActivationData.m_hTarget = m_hTarget;
			}
		}

		// Calculate how far away the object is...

		LTVector vDist = m_ActivationData.m_vIntersect - vPos;
		fDistAway = vDist.Mag();
	}
	
	// [KLS 8/3/02] - Use the fallback object if we have one and we didn't 
	// find another object more suitable object... 

	bool bCanUseFallback = (m_ActivationData.m_hTarget ? false : true);
	if (!bCanUseFallback)
	{
		// We can still use the fallback object if it isn't the world or a
		// world model...

		if (IsMainWorld(m_ActivationData.m_hTarget) || 
			OT_WORLDMODEL == GetObjectType(m_ActivationData.m_hTarget))
		{
			bCanUseFallback = true;
		}
	}

	if ( bCanUseFallback && g_adFallbackActivationObject.m_hTarget )
	{
		// Ok we hit the fallback object reset some of our target data
	
		LTVector vObjPos;
		g_pLTClient->GetObjectPos(g_adFallbackActivationObject.m_hTarget, &vObjPos);

		m_ActivationData.m_vIntersect = vObjPos;

		vObjPos -= vPos;

		if (vObjPos.Mag() <= fMaxDist)
		{
			m_hTarget = g_adFallbackActivationObject.m_hTarget;
			m_ActivationData.m_hTarget = m_hTarget;
		}

		// Calculate how far away the object is...

		LTVector vDist = m_ActivationData.m_vIntersect - vPos;
		fDistAway = vDist.Mag();
	}
}
Esempio n. 24
0
bool CHUDSubtitles::Show(const char* szStringId, LTVector vSpeakerPos, float fRadius, float fDuration, bool bSubtitlePriority)
{

	// Only show subtitles if conversations in range...
	LTVector vListenerPos;
	bool bListenerInClient;
	LTRotation rRot;
	g_pLTClient->GetListener(&bListenerInClient, &vListenerPos, &rRot);

	LTVector vPos = vSpeakerPos - vListenerPos;
	float fAdjustedRadius = fRadius * g_vtAdjustedRadius.GetFloat();
	float fDist = vPos.Mag();
	if (vSpeakerPos == LTVector(0, 0, 0))
		fDist = 0.0f;

	//should we override what ever is already playing?
	if (m_bVisible)
	{

		//if the old one has priority, and the new doesn't, don't play the new
		if (m_bSubtitlePriority && !bSubtitlePriority)
		{
			return false;
		}

		//if they have the same priority, check distances
		if (m_bSubtitlePriority == bSubtitlePriority)
		{
			LTVector vOldPos = m_vSpeakerPos - vListenerPos;
			float fOldDist = vOldPos.Mag();
			if (m_vSpeakerPos == LTVector(0, 0, 0))
				fOldDist = 0.0f;

			
			if (fOldDist < fDist)
			{
				return false;
			}
		}

	}
	

	const wchar_t *pStr = LoadString(szStringId);
	
	
	if (LTStrEmpty(pStr))
	{
		DebugCPrint(2,"CHUDSubtitles::Show(%s) : No Text",szStringId);
		return false;
	}
		
	m_Text.SetText(pStr);

	m_bVisible = true;
	m_bSubtitlePriority = bSubtitlePriority;

	m_vSpeakerPos = vSpeakerPos;
	m_fRadius = fRadius;
	m_fDuration = fDuration;

	if (m_fDuration < 0.0f)
		m_fDuration = 0.04f * (float)LTStrLen(m_Text.GetText());


	LTVector2n pos = m_vBasePos;
	uint32	width = m_nWidth;

/*
	if( g_pPlayerMgr->GetPlayerCamera()->GetCameraMode() == CPlayerCamera::kCM_Cinematic )
	{
		pos = m_CinematicPos;
		width = m_nCinematicWidth;
	}
*/

	LTVector2 vfScale = g_pInterfaceResMgr->GetScreenScale();
	uint32 x = (uint32)((float)pos.x * vfScale.x);
	uint32 y = (uint32)((float)pos.y * vfScale.y);
	width = (uint32 )((float)width * vfScale.x);
	uint32 height = (2 + m_nMaxLines * m_sTextFont.m_nHeight) ;

	float fFontHeight =  (float)m_sTextFont.m_nHeight;

	m_Rect.Init(x,y,x+width,y+height);

	m_Text.WordWrap(m_Rect.GetWidth());
	float textX = (float)m_Rect.Left();
	float textY = (float)m_Rect.Top();

	LTRect2n rExt;
	m_Text.CreateTexture();
	m_Text.GetExtents(rExt);

	uint32 numLines = (uint32)(rExt.GetHeight() / fFontHeight);

	if (numLines > m_nMaxLines)
	{
		m_bOverflow = true;
		float fTimePerLine = m_fDuration / ((float)numLines + 1.0f);
		float fDelay = (float)m_nMaxLines * fTimePerLine;
		m_fScrollStartTime = fDelay;

		m_fScrollSpeed = fFontHeight / fTimePerLine;
		
		m_fMaxOffset = (float)(rExt.GetHeight() - m_Rect.GetHeight());
	}
	else
	{
		m_bOverflow = false;
		textX += (float)(m_Rect.GetWidth() - width) / 2.0f;
		m_fOffset = (float)(m_Rect.GetHeight() - height);
		
		textY += m_fOffset;
		m_fScrollSpeed = 0.0f;

	}

	m_fEndTime = m_fDuration;

	//reset our time to the beginning
	m_fElapsedTime = 0.0f;


	m_Text.SetPos(LTVector2(textX,textY));

	return true;

}
Esempio n. 25
0
LTBOOL CAIMovement::UpdateConstantVelocity( EnumAnimMovement eMovementType, LTVector* pvNewPos )
{
	// Find our unit movement vector

	LTVector vMove = m_vDest - m_pAI->GetPosition();

	// Set our speed based on our movement type

	switch( eMovementType )
	{
		case kAM_Set:
			vMove.y = 0.0f;
			m_pAI->SetSpeed( m_fSetSpeed );
			break;

		case kAM_Walk:
			vMove.y = 0.0f;
			m_pAI->Walk();
			break;

		case kAM_Run:
			vMove.y = 0.0f;
			m_pAI->Run();
			break;

		case kAM_Hover:
			m_bFaceDest = LTTRUE;
			vMove.y = 0.0f;
			m_pAI->Hover();
			break;

		case kAM_Swim:
			vMove.y = 0.0f;
			m_pAI->Swim();
			break;

		case kAM_Climb:
			vMove.x = 0.0f;
			vMove.z = 0.0f;
			m_pAI->Walk();

			// Turn off gravity
			m_pAI->SetCheapMovement(LTFALSE);
			m_bFaceDest = LTFALSE;
			break;

		case kAM_JumpOver:
			vMove.y = 0.0f;
			m_pAI->JumpOver();

			// Turn off gravity
			m_pAI->SetCheapMovement(LTFALSE);

			if( m_eLastMovementType != kAM_JumpOver )
			{
				SetupJump( eMovementType );
			}
			break;

		case kAM_JumpUp:
			m_pAI->Jump();
			m_bFaceDest = LTFALSE;

			// Turn off gravity
			m_pAI->SetCheapMovement(LTFALSE);

			if( m_eLastMovementType != kAM_JumpUp )
			{
				SetupJump( eMovementType );
				vMove = m_vDest - m_pAI->GetPosition();
			}
			break;

		case kAM_Fall:
			m_pAI->Fall();
			m_bFaceDest = LTFALSE;

			// Turn off gravity
			m_pAI->SetCheapMovement(LTFALSE);

			if( m_eLastMovementType != kAM_Fall )
			{
				SetupJump( eMovementType );
				vMove = m_vDest - m_pAI->GetPosition();
			}
			break;

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

	// See if we'll overshoot our dest.

	LTFLOAT fRemainingDist = vMove.Mag();
	if(fRemainingDist == 0.f)
	{
		Clear();
		m_eState = eStateDone;
		return LTFALSE;
	}

	LTFLOAT fMoveDist;
    LTFLOAT fTimeDelta = g_pLTServer->GetFrameTime();

	fMoveDist = m_pAI->GetSpeed()*fTimeDelta;

	// If we'd overshoot our destination, just move us there

	if ( fRemainingDist < fMoveDist )
	{
		*pvNewPos = m_vDest;

		// If the movement does not include any vertical, then
		// do not affect the elevation of the AI. Let CheapMovement
		// take care of putting the AI on the ground.

		if( vMove.y == 0.f )
		{
			pvNewPos->y = m_pAI->GetPosition().y;
		}

		Clear();
		m_eState = eStateDone;
		return LTTRUE;
	}

	// Scale based on our movement distance

	vMove.Normalize();
	vMove *= fMoveDist;

	// Calculate our new position

	*pvNewPos = m_pAI->GetPosition() + vMove;

	// Face us in the right direction

	if ( m_bFaceDest )
	{
		m_pAI->FacePosMoving( *pvNewPos );
	}

	return LTTRUE;
}
Esempio n. 26
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);
	}
}
Esempio n. 27
0
void CGrenade::HandleImpact(HOBJECT hObj)
{
	if (!g_vtGrenadeDampenPercent.IsInitted())
	{
        g_vtGrenadeDampenPercent.Init(g_pLTServer, "GrenadeDampenPercent", LTNULL, DEFAULT_GRENADE_DAMPEN_PERCENT);
	}

	if (!g_vtGrenadeMinVelMag.IsInitted())
	{
        g_vtGrenadeMinVelMag.Init(g_pLTServer, "GrenadeMinVelMag", LTNULL, DEFAULT_GRENADE_MIN_VELOCITY);
	}


    LTVector vVel;
    g_pLTServer->GetVelocity(m_hObject, &vVel);


	// See if we are impacting on liquid...

    LTBOOL bEnteringLiquid = LTFALSE;
    uint16 code;
    if (g_pLTServer->GetContainerCode(hObj, &code))
	{
		if (IsLiquid((ContainerCode)code))
		{
            bEnteringLiquid = LTTRUE;
		}
	}


	CollisionInfo info;
    g_pLTServer->GetLastCollision(&info);


	// Do the bounce, if the object we hit isn't liquid...

	if (!bEnteringLiquid)
	{
		vVel += (info.m_vStopVel * 2.0f);
	}


	// Dampen the grenade's new velocity based on the surface type...

    LTFLOAT fDampenPercent = g_vtGrenadeDampenPercent.GetFloat();

	m_eLastHitSurface = GetSurfaceType(info);
	SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface);
	if (pSurf)
	{
		// Play a bounce sound (based on the surface type) if one isn't
		// already playing...

		if ( ShouldPlayBounceSound(pSurf) )
		{
			// Only play one sound at a time...

			if (m_hBounceSnd)
			{
                g_pLTServer->KillSound(m_hBounceSnd);
                m_hBounceSnd = LTNULL;
			}

            uint32 dwFlags = PLAYSOUND_GETHANDLE | PLAYSOUND_TIME;

			int nVolume	= IsLiquid(m_eContainerCode) ? 50 : 100;

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

			m_hBounceSnd = g_pServerSoundMgr->PlaySoundFromPos(vPos, (char*)GetBounceSound(pSurf),
				pSurf->fGrenadeSndRadius, SOUNDPRIORITY_MISC_MEDIUM, dwFlags, nVolume);
		}

		fDampenPercent = (1.0f - pSurf->fHardness);
	}

	fDampenPercent = fDampenPercent > 1.0f ? 1.0f : (fDampenPercent < 0.0f ? 0.0f : fDampenPercent);

	vVel *= (1.0f - fDampenPercent);


	// See if we should come to a rest...

    LTVector vTest = vVel;
	vTest.y = 0.0f;

	if (vTest.Mag() < g_vtGrenadeMinVelMag.GetFloat())
	{
		// If we're on the ground (or an object), stop movement...

		CollisionInfo standingInfo;
        g_pLTServer->GetStandingOn(m_hObject, &standingInfo);

		CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info;

		if (pInfo->m_hObject)
		{
			// Don't stop on walls...

			if (pInfo->m_Plane.m_Normal.y > 0.75f)
			{
				vVel.Init();

				// Turn off gravity, solid, and touch notify....

                uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject);
				dwFlags &= ~(FLAG_GRAVITY | FLAG_TOUCH_NOTIFY | FLAG_SOLID);

                g_pLTServer->SetObjectFlags(m_hObject, dwFlags);

				// Rotate to rest...

				RotateToRest();
			}
		}
	}


	// Reset rotation velocities due to the bounce...

	ResetRotationVel(&vVel, pSurf);


	// We need to subtact this out because the engine will add it back in,
	// kind of a kludge but necessary...

	vVel -= info.m_vStopVel;


    g_pLTServer->SetVelocity(m_hObject, &vVel);

	m_cBounces++;
}