//-----------------------------------------------------------------------------
// Purpose: Tell the vehicle physics system whenever we teleport, so it can fixup the wheels.
//-----------------------------------------------------------------------------
void CPropVehicle::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
	matrix3x4_t startMatrixInv;

	MatrixInvert( EntityToWorldTransform(), startMatrixInv );
	BaseClass::Teleport( newPosition, newAngles, newVelocity );

	// Calculate the relative transform of the teleport
	matrix3x4_t xform;
	ConcatTransforms( EntityToWorldTransform(), startMatrixInv, xform );
	m_VehiclePhysics.Teleport( xform );
}
//-----------------------------------------------------------------------------
// Returns the unperterbed view position for a particular role
//-----------------------------------------------------------------------------
bool CBaseTFVehicle::GetRoleViewPosition( int nRole, Vector *pVehicleEyeOrigin, QAngle *pVehicleEyeAngles )
{
	// Generate the view position in world space.
	Vector vAbsOrigin;
	QAngle vAbsAngle;
	bool bUsingThirdPersonCamera = GetRoleAbsViewPosition( nRole, &vAbsOrigin, &vAbsAngle );

	
	// Make a matrix for it.
	matrix3x4_t absMatrix;
	AngleMatrix( vAbsAngle, absMatrix );
	MatrixSetColumn( vAbsOrigin, 3, absMatrix );


	// Transform the matrix into local space.
	matrix3x4_t worldToEntity, local;
	MatrixInvert( EntityToWorldTransform(), worldToEntity );
	ConcatTransforms( worldToEntity, absMatrix, local ); 


	// Suck out the origin and angles.
	pVehicleEyeOrigin->Init( local[0][3], local[1][3], local[2][3] );
	MatrixAngles( local, *pVehicleEyeAngles );

	return bUsingThirdPersonCamera;
}
void CRagdollProp::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
{
	matrix3x4_t startMatrixInv;
	matrix3x4_t startMatrix;

	m_ragdoll.list[0].pObject->GetPositionMatrix( startMatrix );
	MatrixInvert( startMatrix, startMatrixInv );
	
	// object 0 MUST be the one to get teleported!
	VPhysicsSwapObject( m_ragdoll.list[0].pObject );
	BaseClass::Teleport( newPosition, newAngles, newVelocity );

	// Calculate the relative transform of the teleport
	matrix3x4_t xform;
	ConcatTransforms( EntityToWorldTransform(), startMatrixInv, xform );
	UpdateNetworkDataFromVPhysics( m_ragdoll.list[0].pObject, 0 );
	for ( int i = 1; i < m_ragdoll.listCount; i++ )
	{
		matrix3x4_t matrix, newMatrix;
		m_ragdoll.list[i].pObject->GetPositionMatrix( matrix );
		ConcatTransforms( xform, matrix, newMatrix );
		m_ragdoll.list[i].pObject->SetPositionMatrix( newMatrix, true );
		UpdateNetworkDataFromVPhysics( m_ragdoll.list[i].pObject, i );
	}
}
void CAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld )
{
	CStudioHdr *pStudioHdr = GetModelPtr( );

	if (!pStudioHdr)
	{
		Assert(!"CBaseAnimating::GetBoneTransform: model missing");
		return;
	}

	if (iBone < 0 || iBone >= pStudioHdr->numbones())
	{
		Assert(!"CBaseAnimating::GetBoneTransform: invalid bone index");
		return;
	}

	CBoneCache *pcache = GetBoneCache( );

	matrix3x4_t *pmatrix = pcache->GetCachedBone( iBone );

	if ( !pmatrix )
	{
		MatrixCopy( EntityToWorldTransform(), pBoneToWorld );
		return;
	}

	Assert( pmatrix );
	
	// FIXME
	MatrixCopy( *pmatrix, pBoneToWorld );
}
Beispiel #5
0
	virtual void ComputeWorldSpaceSurroundingBox( Vector *mins, Vector *maxs )
	{
		Assert( mins != NULL && maxs != NULL );
		if ( !mins || !maxs )
			return;

		// Take our saved collision bounds, and transform into world space
		TransformAABB( EntityToWorldTransform(), m_collisionMins, m_collisionMaxs, *mins, *maxs );
	}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPhysMagnet::DoMagnetSuck( CBaseEntity *pOther )
{
	if ( !HasSpawnFlags( SF_MAGNET_SUCK ) )
		return;

	if ( !m_bActive )
		return;

	// Don't repeatedly suck
	if ( m_flNextSuckTime > gpGlobals->curtime )
		return;
	
	// Look for physics objects underneath the magnet and suck them onto it
	Vector vecCheckPos, vecSuckPoint;
	VectorTransform( Vector(0,0,-96), EntityToWorldTransform(), vecCheckPos );
	VectorTransform( Vector(0,0,-64), EntityToWorldTransform(), vecSuckPoint );

	CBaseEntity *pEntities[20];
	int iNumEntities = UTIL_EntitiesInSphere( pEntities, 20, vecCheckPos, 80.0, 0 );
	for ( int i = 0; i < iNumEntities; i++ )
	{
		CBaseEntity *pEntity = pEntities[i];
		if ( !pEntity || pEntity == pOther )
			continue;

		IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
		if ( pPhys && pEntity->GetMoveType() == MOVETYPE_VPHYSICS && pPhys->GetMass() < 5000 )
		{
			// Do we have line of sight to it?
			trace_t tr;
			UTIL_TraceLine( GetAbsOrigin(), pEntity->GetAbsOrigin(), MASK_SHOT, this, 0, &tr );
			if ( tr.fraction == 1.0 || tr.m_pEnt == pEntity )
			{
				// Pull it towards the magnet
				Vector vecVelocity = (vecSuckPoint - pEntity->GetAbsOrigin());
				VectorNormalize(vecVelocity);
				vecVelocity *= 5 * pPhys->GetMass();
				pPhys->AddVelocity( &vecVelocity, NULL );
			}
		}
	}

	m_flNextSuckTime = gpGlobals->curtime + 2.0;
}
void CStickyBomb::Touch( CBaseEntity *pOther )
{
	// Don't stick if already stuck
	if ( GetMoveType() == MOVETYPE_FLYGRAVITY )
	{
		trace_t tr = GetTouchTrace();
		// stickies don't stick to each other or sky
		if ( FClassnameIs(pOther, "grenade_stickybomb") || (tr.surface.flags & SURF_SKY) )
		{
			// bounce
			Vector vecNewVelocity;
			PhysicsClipVelocity( GetAbsVelocity(), tr.plane.normal, vecNewVelocity, 1.0 );
			SetAbsVelocity( vecNewVelocity );
		}
		else 
		{
			SetAbsVelocity( vec3_origin );
			SetMoveType( MOVETYPE_NONE );
			if ( pOther->entindex() != 0 )
			{
				// set up notification if the parent is deleted before we explode
				g_pNotify->AddEntity( this, pOther );

				if ( (tr.surface.flags & SURF_HITBOX) && modelinfo->GetModelType( pOther->GetModel() ) == mod_studio )
				{
					CBaseAnimating *pOtherAnim = dynamic_cast<CBaseAnimating *>(pOther);
					if ( pOtherAnim )
					{
						matrix3x4_t bombWorldSpace;
						MatrixCopy( EntityToWorldTransform(), bombWorldSpace );

						// get the bone info so we can follow the bone
						FollowEntity( pOther );
						SetOwnerEntity( pOther );
						m_boneIndexAttached = pOtherAnim->GetHitboxBone( tr.hitbox );
						matrix3x4_t boneToWorld;
						pOtherAnim->GetBoneTransform( m_boneIndexAttached, boneToWorld );

						// transform my current position/orientation into the hit bone's space
						// UNDONE: Eventually we need to intersect with the mesh here
						// REVISIT: maybe do something like the decal code to find a spot on
						//			the mesh.
						matrix3x4_t worldToBone, localMatrix;
						MatrixInvert( boneToWorld, worldToBone );
						ConcatTransforms( worldToBone, bombWorldSpace, localMatrix );
						MatrixAngles( localMatrix, m_boneAngles.GetForModify(), m_bonePosition.GetForModify() );
						return;
					}
				}
				SetParent( pOther );
			}
		}
	}
}
Beispiel #8
0
void C_ServerRagdoll::GetRenderBounds( Vector& theMins, Vector& theMaxs )
{
    if( !CollisionProp()->IsBoundsDefinedInEntitySpace() )
    {
        IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs );
    }
    else
    {
        theMins = CollisionProp()->OBBMins();
        theMaxs = CollisionProp()->OBBMaxs();
    }
}
//-----------------------------------------------------------------------------
// Purpose: 
// Output : void SyncPoseToAimAngles
//-----------------------------------------------------------------------------
void CNPC_RocketTurret::SyncPoseToAimAngles ( void )
{
	QAngle localAngles = TransformAnglesToLocalSpace( m_vecCurrentAngles.Get(), EntityToWorldTransform() );

	// Update pitch
	SetPoseParameter( m_iPosePitch, localAngles.x );

	// Update yaw -- NOTE: This yaw movement is screwy for this model, we must invert the yaw delta and also skew an extra 90 deg to
	// get the 'forward face' of the turret to match up with the look direction. If the model and it's pose parameters change, this will be wrong.
	SetPoseParameter( m_iPoseYaw, AngleNormalize( -localAngles.y - 90 ) );

	InvalidateBoneCache();
}
void CBeam::SetAbsEndPos( const Vector &pos )
{
	if (!GetMoveParent())
	{
		SetEndPos( pos );
		return;
	}

	Vector vecLocalPos;
	matrix3x4_t worldToBeam;
	MatrixInvert( EntityToWorldTransform(), worldToBeam );
	VectorTransform( pos, worldToBeam, vecLocalPos );
	SetEndPos( vecLocalPos );
}
const Vector &C_Beam::GetAbsEndPos( void ) const
{
	static Vector vecEndAbsPosition;
	if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE ) 
	{
		if (ComputeBeamEntPosition( m_hAttachEntity[m_nNumBeamEnts-1], m_nAttachIndex[m_nNumBeamEnts-1], false, vecEndAbsPosition ))
			return vecEndAbsPosition;
	}

	if (!const_cast<C_Beam*>(this)->GetMoveParent())
		return m_vecEndPos.Get();

	// FIXME: Cache this off?
	VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecEndAbsPosition );
	return vecEndAbsPosition;
}
Beispiel #12
0
const Vector &CE_CBeam::GetAbsEndPos( void )
{
	CEntity *ent = GetEndEntity();
	if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE && ent ) 
	{
		return ent->GetAbsOrigin();
	}

	if (!const_cast<CE_CBeam*>(this)->GetMoveParent())
		return m_vecEndPos;

	// FIXME: Cache this off?
	static Vector vecAbsPos;
	VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecAbsPos );
	return vecAbsPos;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CAntlionGrub::Spawn( void )
{
	Precache();
	BaseClass::Spawn();

	SetModel( ANTLIONGRUB_MODEL );
	
	// FIXME: This is a big perf hit with the number of grubs we're using! - jdw
	CreateGlow();

	SetSolid( SOLID_BBOX );
	SetSolidFlags( FSOLID_TRIGGER );
	SetMoveType( MOVETYPE_NONE );
	SetCollisionGroup( COLLISION_GROUP_NONE );
	AddEffects( EF_NOSHADOW );

	CollisionProp()->UseTriggerBounds(true,1);

	SetTouch( &CAntlionGrub::GrubTouch );

	SetHealth( 1 );
	m_takedamage = DAMAGE_YES;

	// Stick to the nearest surface
	if ( HasSpawnFlags( SF_ANTLIONGRUB_NO_AUTO_PLACEMENT ) == false )
	{
		AttachToSurface();
	}

	// At this point, alter our bounds to make sure we're within them
	Vector vecMins, vecMaxs;
	RotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), vecMins, vecMaxs );

	UTIL_SetSize( this, vecMins, vecMaxs );

	// Start our idle activity
	SetSequence( SelectWeightedSequence( ACT_IDLE ) );
	SetCycle( random->RandomFloat( 0.0f, 1.0f ) );
	ResetSequenceInfo();

	m_State = GRUB_STATE_IDLE;

	// Reset
	m_flFlinchTime = 0.0f;
	m_flNextIdleSoundTime = gpGlobals->curtime + random->RandomFloat( 4.0f, 8.0f );
}
bool C_WalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld )
{
	//
	//
	// This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns.
	//
	//
	studiohdr_t *pStudioHdr = GetModelPtr( );
	if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->numattachments )
	{
		return false;
	}

	Vector vLocalPos( 0, 0, 0 );
	mstudioattachment_t *pAttachment = pStudioHdr->pAttachment( iAttachment-1 );
	if ( stricmp( pAttachment->pszName(), "build_point_left_gun" ) == 0 )
	{
		vLocalPos.y = sideDist;
	}
	else if ( stricmp( pAttachment->pszName(), "build_point_right_gun" ) == 0 )
	{
		vLocalPos.y = -sideDist;
	}
	else if ( stricmp( pAttachment->pszName(), "ThirdPersonCameraOrigin" ) == 0 )
	{
	}
	else
	{
		// Ok, it's not one of our magical attachments. Use the regular attachment setup stuff.
		return BaseClass::GetAttachment( iAttachment, attachmentToWorld );
	}

	if ( m_bCrouched )
	{
		vLocalPos.z += downDist;
	}

	// Now build the output matrix.
	matrix3x4_t localMatrix;
	SetIdentityMatrix( localMatrix );
	PositionMatrix( vLocalPos, localMatrix );

	ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld );
	return true;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask )
{
	BaseClass::StandardBlendingRules( pos, q, currentTime, boneMask );

	// Don't do anything while dead
	if ( !IsAlive() )
		return;

	studiohdr_t *hdr = GetModelPtr();
	if ( !hdr )
		return;

	int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" );

	Vector vecPrev = pos[firstBone-1];
	Vector vecCurr = vec3_origin;
	for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ )
	{
		// We double up the bones at the last node.
		Vector vecCurr;
		if ( i == BARNACLE_TONGUE_POINTS )
		{
			vecCurr = m_TonguePhysics.GetLastNode()->m_vPos;
		}
		else
		{
			vecCurr = m_TonguePhysics.GetNode(i)->m_vPos;
		}

		//debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 );

		// Fill out the positions in local space
		VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] );
		vecCurr = pos[firstBone+i];

		// Fill out the angles
		Vector vecForward = (vecCurr - vecPrev);
		VectorNormalize( vecForward );
		QAngle vecAngle;
		VectorAngles( vecForward, vecAngle );
		AngleQuaternion( vecAngle, q[firstBone+i] );

		vecPrev = vecCurr;
	}
}
const Vector &CBeam::GetAbsEndPos( void ) const
{
	if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE && GetEndEntity() ) 
	{
		edict_t *pent =  engine->PEntityOfEntIndex( GetEndEntity() );
		CBaseEntity *ent = CBaseEntity::Instance( pent );
		if ( ent )
			return ent->GetAbsOrigin();
	}

	if (!const_cast<CBeam*>(this)->GetMoveParent())
		return m_vecEndPos.Get();

	// FIXME: Cache this off?
	static Vector vecAbsPos;
	VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecAbsPos );
	return vecAbsPos;
}
void CFunc_LiquidPortal::ComputeLinkMatrix( void )
{
	CFunc_LiquidPortal *pLinkedPortal = m_hLinkedPortal.Get();
	if( pLinkedPortal )
	{
		VMatrix matLocalToWorld, matLocalToWorldInv, matRemoteToWorld;

		matLocalToWorld = EntityToWorldTransform();
		matRemoteToWorld = pLinkedPortal->EntityToWorldTransform();
		
		MatrixInverseTR( matLocalToWorld, matLocalToWorldInv );
		m_matrixThisToLinked = matRemoteToWorld * matLocalToWorldInv;

		MatrixInverseTR( m_matrixThisToLinked, pLinkedPortal->m_matrixThisToLinked );
	}
	else
	{
		m_matrixThisToLinked.Identity();
	}
}
//-----------------------------------------------------------------------------
// Purpose: Vehicles are permanently oriented off angle for vphysics.
//-----------------------------------------------------------------------------
void CPropCrane::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
{
	// This call is necessary to cause m_rgflCoordinateFrame to be recomputed
	const matrix3x4_t &entityToWorld = EntityToWorldTransform();

	if (pForward != NULL)
	{
		MatrixGetColumn( entityToWorld, 1, *pForward ); 
	}

	if (pRight != NULL)
	{
		MatrixGetColumn( entityToWorld, 0, *pRight ); 
	}

	if (pUp != NULL)
	{
		MatrixGetColumn( entityToWorld, 2, *pUp ); 
	}
}
Beispiel #19
0
void CKeeperBot::BotAdjustPos()
{
	float modifier = KEEPER_MID_COEFF;
	QAngle ang = m_oldcmd.viewangles;
	Vector target = GetTeam()->m_vGoalCenter;

	if (m_vBallVel.Length2D() > 750 && m_flAngToBallVel < 60)
	{
		float yDist = GetTeam()->m_vGoalCenter.GetY() - m_vBallPos.y;
		float vAng = acos(Sign(yDist) * m_vBallDir2D.y);
		float xDist = Sign(m_vBallDir2D.x) * abs(yDist) * tan(vAng);
		target.x = clamp(m_vBallPos.x + xDist, GetTeam()->m_vGoalCenter.GetX() - 150, GetTeam()->m_vGoalCenter.GetX() + 150);
	}

	if (m_pBall->State_Get() == BALL_STATE_KEEPERHANDS && m_pBall->GetCurrentPlayer() == this)
	{
		if (ShotButtonsReleased())
		{
			modifier = KEEPER_CLOSE_COEFF;
			//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
			m_cmd.buttons |= IN_ALT1;
			CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true);
			if (!pPl && SDKGameRules()->IsIntermissionState())
				pPl = FindClosestPlayerToSelf(false, true);

			if (pPl)
			{
				VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang);
				ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
				//m_flBotNextShot = gpGlobals->curtime + 1;
			}
			else
			{
				VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
				ang[YAW] += g_IOSRand.RandomFloat(-45, 45);
				ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
				//m_flBotNextShot = gpGlobals->curtime + 1;
			}
		}
	}
	else// if (gpGlobals->curtime >= m_flBotNextShot)
	{
		VectorAngles(m_vDirToBall, ang);
		float ballDistToGoal = (m_vBallPos - GetTeam()->m_vGoalCenter).Length2D();
		CSDKPlayer *pClosest = FindClosestPlayerToBall();
		m_cmd.buttons |= IN_ATTACK;

		if (ballDistToGoal < 750 && m_vDirToBall.Length2D() < 200 && m_vDirToBall.z < 200 && (m_vDirToBall.z < 80 || m_vBallVel.z <= 0))
		{
			modifier = KEEPER_CLOSE_COEFF;// max(0.15f, 1 - ballDistToGoal / 750);
			VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
			bool diving = false;

			if (m_flAngToBallVel < 60 && m_flAngToBallVel > 15)
			{
				if (abs(m_vDirToBall.x) > 50 && abs(m_vDirToBall.x) < 200 && m_vDirToBall.z < 150 && abs(m_vDirToBall.x) < 150 && m_vBallVel.Length() > 200)
				{
					m_cmd.buttons |= IN_JUMP;
					m_cmd.buttons |= Sign(m_vDirToBall.x) == GetTeam()->m_nRight ? IN_MOVERIGHT : IN_MOVELEFT;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
				else if (m_vDirToBall.z > 100 && m_vDirToBall.z < 150 && m_vDirToBall.Length2D() < 100)
				{
					m_cmd.buttons |= IN_JUMP;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
				else if (abs(m_vDirToBall.y) > 50 && abs(m_vDirToBall.y) < 200 && m_vDirToBall.z < 100 && abs(m_vDirToBall.x) < 50 && m_vBallVel.Length() < 200 && pClosest != this)
				{
					m_cmd.buttons |= IN_JUMP;
					m_cmd.buttons |= Sign(m_vLocalDirToBall.x) == GetTeam()->m_nForward ? IN_FORWARD : IN_BACK;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
			}

			if (!diving)
			{
				if (m_vDirToBall.Length2D() < 50)
				{
					modifier = KEEPER_CLOSE_COEFF;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true);
					if (!pPl && SDKGameRules()->IsIntermissionState())
						pPl = FindClosestPlayerToSelf(false, true);

					if (pPl)
					{
						VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang);
						ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
						//m_flBotNextShot = gpGlobals->curtime + 1;
					}
					else
					{
						VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
						ang[YAW] += g_IOSRand.RandomFloat(-45, 45);
						ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
						//m_flBotNextShot = gpGlobals->curtime + 1;
					}
				}
				else
					modifier = KEEPER_CLOSE_COEFF;
			}
		}
		else if (ballDistToGoal < 1250 && m_flAngToBallVel < 60 && m_vBallVel.Length2D() > 300 && (m_vBallVel.z > 100 || m_vDirToBall.z > 100))
		{
			modifier = KEEPER_FAR_COEFF;
		}
		else if (ballDistToGoal < 1000 && m_vDirToBall.z < 80 && m_vBallVel.Length2D() < 300 && m_vBallVel.z < 100)
		{
			if (pClosest == this)
				modifier = KEEPER_CLOSE_COEFF;
			else
				modifier = max(KEEPER_FAR_COEFF, 1 - pow(min(1, ballDistToGoal / 750.0f), 2));
		}
		else
		{
			modifier = KEEPER_MID_COEFF;
		}

		m_cmd.viewangles = ang;
		m_LastAngles = m_cmd.viewangles;
		SetLocalAngles(m_cmd.viewangles);
		SnapEyeAngles(ang);

		Vector targetPosDir = target + modifier * (m_vBallPos - target) - GetLocalOrigin();
		targetPosDir.z = 0;
		float dist = targetPosDir.Length2D();
		VectorNormalizeFast(targetPosDir);
		Vector localDir;
		VectorIRotate(targetPosDir, EntityToWorldTransform(), localDir);
		//float speed;
		//if (dist < 10)
		//	speed = 0;
		//else if (dist < 100)
		//	speed = mp_runspeed.GetInt();
		//else
		//	speed = mp_sprintspeed.GetInt();
		//float speed = clamp(dist - 10, 0, mp_runspeed.GetInt());
		float speed = 0;

		if (dist > 30)
			speed = clamp(5 * dist, 0, mp_sprintspeed.GetInt() * (mp_botkeeperskill.GetInt() / 100.0f));

		if (speed > mp_runspeed.GetInt())
			m_cmd.buttons |= IN_SPEED;

		m_cmd.forwardmove = localDir.x * speed;
		m_cmd.sidemove = -localDir.y * speed;

		if (m_cmd.forwardmove > 0)
			m_cmd.buttons |= IN_FORWARD;
		else if (m_cmd.forwardmove < 0)
			m_cmd.buttons |= IN_BACK;

		if (m_cmd.sidemove > 0)
			m_cmd.buttons |= IN_RIGHT;
		else if (m_cmd.sidemove < 0)
			m_cmd.buttons |= IN_MOVELEFT;
	}

	m_cmd.viewangles = ang;
}
bool CStatueProp::CreateVPhysicsFromHitBoxes( CBaseAnimating *pInitBaseAnimating )
{
	if ( !pInitBaseAnimating )
		return false;

	// Use the current animation sequence and cycle
	CopyAnimationDataFrom( pInitBaseAnimating );

	// Copy over any render color
	color24 colorRender = pInitBaseAnimating->GetRenderColor();
	SetRenderColor( colorRender.r, colorRender.g, colorRender.b );
	SetRenderAlpha( pInitBaseAnimating->GetRenderAlpha() );

	// Get hitbox data
	CStudioHdr *pStudioHdr = GetModelPtr();
	if ( !pStudioHdr )
		return false;

	mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
	if ( !set )
		return false;

	Vector position;
	QAngle angles;

	// Make enough pointers to convexes for each hitbox
	CPhysConvex **ppConvex = new (CPhysConvex*[ set->numhitboxes ]);

	float flTotalVolume = 0.0f;
	float flTotalSurfaceArea = 0.0f;

	for ( int i = 0; i < set->numhitboxes; i++ )
	{
		// Get the hitbox info
		mstudiobbox_t *pbox = set->pHitbox( i );
		GetBonePosition( pbox->bone, position, angles );

		// Accumulate volume and area
		Vector flDimentions = pbox->bbmax - pbox->bbmin;
		flTotalVolume += flDimentions.x * flDimentions.y * flDimentions.z;
		flTotalSurfaceArea += 2.0f * ( flDimentions.x * flDimentions.y + flDimentions.x * flDimentions.z + flDimentions.y * flDimentions.z );

		// Get angled min and max extents
		Vector vecMins, vecMaxs;
		VectorRotate( pbox->bbmin, angles, vecMins );
		VectorRotate( pbox->bbmax, angles, vecMaxs );

		// Get the corners in world space
		Vector vecMinCorner = position + vecMins;
		Vector vecMaxCorner = position + vecMaxs;

		// Get the normals of the hitbox in world space
		Vector vecForward, vecRight, vecUp;
		AngleVectors( angles, &vecForward, &vecRight, &vecUp );
		vecRight = -vecRight;

		// Convert corners and normals to local space
		Vector vecCornerLocal[ 2 ];
		Vector vecNormalLocal[ 3 ];

		matrix3x4_t matToWorld = EntityToWorldTransform();
		VectorITransform( vecMaxCorner, matToWorld, vecCornerLocal[ 0 ] );
		VectorITransform( vecMinCorner, matToWorld, vecCornerLocal[ 1 ] );
		VectorIRotate( vecForward, matToWorld, vecNormalLocal[ 0 ] );
		VectorIRotate( vecRight, matToWorld, vecNormalLocal[ 1 ] );
		VectorIRotate( vecUp, matToWorld, vecNormalLocal[ 2 ] );

		// Create 6 planes from the local oriented hit box data
		float pPlanes[ 4 * 6 ];

		for ( int iPlane = 0; iPlane < 6; ++iPlane )
		{
			int iPlaneMod2 = iPlane % 2;
			int iPlaneDiv2 = iPlane / 2;
			bool bOdd = ( iPlaneMod2 == 1 );

			// Plane Normal
			pPlanes[ iPlane * 4 + 0 ] = vecNormalLocal[ iPlaneDiv2 ].x * ( bOdd ? -1.0f : 1.0f );
			pPlanes[ iPlane * 4 + 1 ] = vecNormalLocal[ iPlaneDiv2 ].y * ( bOdd ? -1.0f : 1.0f );
			pPlanes[ iPlane * 4 + 2 ] = vecNormalLocal[ iPlaneDiv2 ].z * ( bOdd ? -1.0f : 1.0f );

			// Plane D
			pPlanes[ iPlane * 4 + 3 ] = ( vecCornerLocal[ iPlaneMod2 ].x * vecNormalLocal[ iPlaneDiv2 ].x + 
				vecCornerLocal[ iPlaneMod2 ].y * vecNormalLocal[ iPlaneDiv2 ].y + 
				vecCornerLocal[ iPlaneMod2 ].z * vecNormalLocal[ iPlaneDiv2 ].z ) * ( bOdd ? -1.0f : 1.0f );
		}

		// Create convex from the intersection of these planes
		ppConvex[ i ] = physcollision->ConvexFromPlanes( pPlanes, 6, 0.0f );
	}

	// Make a single collide out of the group of convex boxes
	CPhysCollide *pPhysCollide = physcollision->ConvertConvexToCollide( ppConvex, set->numhitboxes );

	delete[] ppConvex;

	// Create the physics object
	objectparams_t params = g_PhysDefaultObjectParams;
	params.pGameData = static_cast<void *>( this );

	int nMaterialIndex = physprops->GetSurfaceIndex( "ice" );	// use ice material

	IPhysicsObject* p = physenv->CreatePolyObject( pPhysCollide, nMaterialIndex, GetAbsOrigin(), GetAbsAngles(), &params );
	Assert( p != NULL );

	// Set velocity
	Vector vecInitialVelocity = pInitBaseAnimating->GetAbsVelocity();
	p->SetVelocity( &vecInitialVelocity, NULL );

	// Compute mass
	float flMass;
	float flDensity, flThickness;
	physprops->GetPhysicsProperties( nMaterialIndex, &flDensity, &flThickness, NULL, NULL );

	// Make it more hollow
	flThickness = MIN ( 1.0f, flThickness + 0.5f );

	if ( flThickness > 0.0f )
	{
		flMass = flTotalSurfaceArea * flThickness * CUBIC_METERS_PER_CUBIC_INCH * flDensity;
	}
	else
	{
		// density is in kg/m^3, volume is in in^3
		flMass = flTotalVolume * CUBIC_METERS_PER_CUBIC_INCH * flDensity;
	}

	// Mass is somewhere between the original and if it was all ice
	p->SetMass( flMass );

	// Yes, gravity
	p->EnableGravity( true );

	// Use this as our vphysics
	VPhysicsSetObject( p );

	SetSolid( SOLID_VPHYSICS );
	AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );

	SetMoveType( MOVETYPE_VPHYSICS );

	if ( pInitBaseAnimating != this )
	{
		// Transfer children from the init base animating
		TransferChildren( pInitBaseAnimating, this );

		CBaseEntity *pChild = FirstMoveChild();

		while ( pChild )
		{
			CEntityFreezing *pFreezing = dynamic_cast<CEntityFreezing*>( pChild );
			if ( pFreezing )
			{
				pFreezing->FinishFreezing();
			}

			pChild = pChild->NextMovePeer();
		}
	}

	return true;
}
bool CStatueProp::CreateVPhysicsFromOBBs( CBaseAnimating *pInitBaseAnimating )
{
	// Make enough pointers to convexes for each hitbox
	CPhysConvex **ppConvex = new (CPhysConvex*[ m_pInitOBBs->Count() ]);

	float flTotalVolume = 0.0f;
	float flTotalSurfaceArea = 0.0f;

	for ( int i = 0; i < m_pInitOBBs->Count(); i++ )
	{
		const outer_collision_obb_t *pOBB = &((*m_pInitOBBs)[ i ]);

		// Accumulate volume and area
		Vector flDimentions = pOBB->vecMaxs - pOBB->vecMins;
		flTotalVolume += flDimentions.x * flDimentions.y * flDimentions.z;
		flTotalSurfaceArea += 2.0f * ( flDimentions.x * flDimentions.y + flDimentions.x * flDimentions.z + flDimentions.y * flDimentions.z );

		// Get angled min and max extents
		Vector vecMins, vecMaxs;
		VectorRotate( pOBB->vecMins, pOBB->angAngles, vecMins );
		VectorRotate( pOBB->vecMaxs, pOBB->angAngles, vecMaxs );

		// Get the corners in world space
		Vector vecMinCorner = pOBB->vecPos + vecMins;
		Vector vecMaxCorner = pOBB->vecPos + vecMaxs;

		// Get the normals of the hitbox in world space
		Vector vecForward, vecRight, vecUp;
		AngleVectors( pOBB->angAngles, &vecForward, &vecRight, &vecUp );
		vecRight = -vecRight;

		// Convert corners and normals to local space
		Vector vecCornerLocal[ 2 ];
		Vector vecNormalLocal[ 3 ];

		matrix3x4_t matToWorld = EntityToWorldTransform();
		VectorITransform( vecMaxCorner, matToWorld, vecCornerLocal[ 0 ] );
		VectorITransform( vecMinCorner, matToWorld, vecCornerLocal[ 1 ] );
		VectorIRotate( vecForward, matToWorld, vecNormalLocal[ 0 ] );
		VectorIRotate( vecRight, matToWorld, vecNormalLocal[ 1 ] );
		VectorIRotate( vecUp, matToWorld, vecNormalLocal[ 2 ] );

		// Create 6 planes from the local oriented hit box data
		float pPlanes[ 4 * 6 ];

		for ( int iPlane = 0; iPlane < 6; ++iPlane )
		{
			int iPlaneMod2 = iPlane % 2;
			int iPlaneDiv2 = iPlane / 2;
			bool bOdd = ( iPlaneMod2 == 1 );

			// Plane Normal
			pPlanes[ iPlane * 4 + 0 ] = vecNormalLocal[ iPlaneDiv2 ].x * ( bOdd ? -1.0f : 1.0f );
			pPlanes[ iPlane * 4 + 1 ] = vecNormalLocal[ iPlaneDiv2 ].y * ( bOdd ? -1.0f : 1.0f );
			pPlanes[ iPlane * 4 + 2 ] = vecNormalLocal[ iPlaneDiv2 ].z * ( bOdd ? -1.0f : 1.0f );

			// Plane D
			pPlanes[ iPlane * 4 + 3 ] = ( vecCornerLocal[ iPlaneMod2 ].x * vecNormalLocal[ iPlaneDiv2 ].x + 
				vecCornerLocal[ iPlaneMod2 ].y * vecNormalLocal[ iPlaneDiv2 ].y + 
				vecCornerLocal[ iPlaneMod2 ].z * vecNormalLocal[ iPlaneDiv2 ].z ) * ( bOdd ? -1.0f : 1.0f );
		}

		// Create convex from the intersection of these planes
		ppConvex[ i ] = physcollision->ConvexFromPlanes( pPlanes, 6, 0.0f );
	}

	// Make a single collide out of the group of convex boxes
	CPhysCollide *pPhysCollide = physcollision->ConvertConvexToCollide( ppConvex, m_pInitOBBs->Count() );

	delete[] ppConvex;

	// Create the physics object
	objectparams_t params = g_PhysDefaultObjectParams;
	params.pGameData = static_cast<void *>( this );

	int nMaterialIndex = physprops->GetSurfaceIndex( "ice" );	// use ice material

	IPhysicsObject* p = physenv->CreatePolyObject( pPhysCollide, nMaterialIndex, GetAbsOrigin(), GetAbsAngles(), &params );
	Assert( p != NULL );

	// Set velocity
	Vector vecInitialVelocity = pInitBaseAnimating->GetAbsVelocity();
	p->SetVelocity( &vecInitialVelocity, NULL );

	// Compute mass
	float flMass;
	float flDensity, flThickness;
	physprops->GetPhysicsProperties( nMaterialIndex, &flDensity, &flThickness, NULL, NULL );

	// Make it more hollow
	flThickness = MIN ( 1.0f, flThickness + 0.5f );

	if ( flThickness > 0.0f )
	{
		flMass = flTotalSurfaceArea * flThickness * CUBIC_METERS_PER_CUBIC_INCH * flDensity;
	}
	else
	{
		// density is in kg/m^3, volume is in in^3
		flMass = flTotalVolume * CUBIC_METERS_PER_CUBIC_INCH * flDensity;
	}

	// Mass is somewhere between the original and if it was all ice
	p->SetMass( flMass );

	// Yes, gravity
	p->EnableGravity( true );

	// Use this as our vphysics
	VPhysicsSetObject( p );

	SetSolid( SOLID_VPHYSICS );
	AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );

	SetMoveType( MOVETYPE_VPHYSICS );

	m_pInitOBBs = NULL;

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Recompute my rendering box
//-----------------------------------------------------------------------------
void C_QUA_Strider::ClientThink()
{
	int i;
	Vector vecMins, vecMaxs;
	Vector vecAbsMins, vecAbsMaxs;
	matrix3x4_t worldToStrider, hitboxToStrider;
	Vector vecBoxMins, vecBoxMaxs;
	Vector vecBoxAbsMins, vecBoxAbsMaxs;
	mstudiohitboxset_t *set;
	CBoneCache *pCache = NULL;

	// The reason why this is here, as opposed to in SetObjectCollisionBox,
	// is because of IK. The code below recomputes bones so as to get at the hitboxes,
	// which causes IK to trigger, which causes raycasts against the other entities to occur,
	// which is illegal to do while in the Relink phase.

	studiohdr_t *pStudioHdr = GetModel()?modelinfo->GetStudiomodel( GetModel() ):NULL;
	if (!pStudioHdr)
		goto doneWithComputation;

	set = pStudioHdr->pHitboxSet( m_nHitboxSet );
	if ( !set || !set->numhitboxes )
		goto doneWithComputation;

	CStudioHdr *hdr = GetModelPtr();
	pCache = GetBoneCache( hdr );

	matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
	pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones );

//	// Compute a box in world space that surrounds this entity
	m_vecRenderMins.Init( FLT_MAX, FLT_MAX, FLT_MAX );
	m_vecRenderMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
//
	MatrixInvert( EntityToWorldTransform(), worldToStrider );
//
	for ( i = 0; i < set->numhitboxes; i++ )
	{
		mstudiobbox_t *pbox = set->pHitbox(i);
		ConcatTransforms( worldToStrider, *hitboxbones[pbox->bone], hitboxToStrider );

		TransformAABB( hitboxToStrider, pbox->bbmin, pbox->bbmax, vecBoxMins, vecBoxMaxs );
		VectorMin( m_vecRenderMins, vecBoxMins, m_vecRenderMins );
		VectorMax( m_vecRenderMaxs, vecBoxMaxs, m_vecRenderMaxs );
	}
//	// Deberiamos poner aqui lo de la vista??
//
//	// UNDONE: Disabled this until we can get closer to a final map and tune
//#if 0
//	// Cut ropes.
//	if ( gpGlobals->curtime >= m_flNextRopeCutTime )
//	{
//		// Blow the bbox out a little.
//		Vector vExtendedMins = vecMins - Vector( 50, 50, 50 );
//		Vector vExtendedMaxs = vecMaxs + Vector( 50, 50, 50 );
//
//		C_RopeKeyframe *ropes[512];
//		int nRopes = C_RopeKeyframe::GetRopesIntersectingAABB( ropes, ARRAYSIZE( ropes ), GetAbsOrigin() + vExtendedMins, GetAbsOrigin() + vExtendedMaxs );
//		for ( int i=0; i < nRopes; i++ )
//		{
//			C_RopeKeyframe *pRope = ropes[i];
//
//			if ( pRope->GetEndEntity() )
//			{
//				Vector vPos;
//				if ( pRope->GetEndPointPos( 1, vPos ) )
//				{
//					// Detach the endpoint.
//					pRope->SetEndEntity( NULL );
//					
//					// Make some spark effect here..
//					g_pEffects->Sparks( vPos );
//				}				
//			}
//		}
//
//		m_flNextRopeCutTime = gpGlobals->curtime + 0.5;
//	}
//#endif

doneWithComputation:	
	// True argument because the origin may have stayed the same, but the size is expected to always change
	g_pClientShadowMgr->AddToDirtyShadowList( this, true );
}