Example #1
0
/*
===============
CG_smoothWJTransitions
===============
*/
static void CG_smoothWJTransitions( playerState_t *ps, const vec3_t in, vec3_t out )
{
	int      i;
	float    stLocal, sFraction;
	qboolean performed = qfalse;
	vec3_t   inAxis[ 3 ], outAxis[ 3 ];

	Q_UNUSED(ps);

	if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
	{
		VectorCopy( in, out );
		return;
	}

	AnglesToAxis( in, inAxis );

	//iterate through ops
	for ( i = MAXSMOOTHS - 1; i >= 0; i-- )
	{
		//if this op has time remaining, perform it
		if ( cg.time < cg.sList[ i ].time + cg_wwSmoothTime.integer )
		{
			stLocal = ( ( cg.sList[ i ].time + cg_wwSmoothTime.integer ) - cg.time ) / cg_wwSmoothTime.integer;
			sFraction = 1.0f - ( ( cos( stLocal * M_PI * 2.0f ) + 1.0f ) / 2.0f );

			RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle );
			RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle );
			RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle );

			AxisCopy( outAxis, inAxis );
			performed = qtrue;
		}
	}

	//if we performed any ops then return the smoothed angles
	//otherwise simply return the in angles
	if ( performed )
	{
		AxisToAngles( outAxis, out );
	}
	else
	{
		VectorCopy( in, out );
	}
}
Example #2
0
bool HoldableItemExplosive::findPlaceToSet( Vector &newOrigin, Vector &newAngles )
{
	Player *player;
	trace_t viewTrace;
	Vector forward;
	Vector left;
	Vector up;
	float axis[3][3];
	vec3_t newAnglesVec;

	if ( !_owner || !_owner->isSubclassOf( Player ) )
		return false;

	player = (Player *)_owner;
		
	memset( &viewTrace, 0, sizeof(trace_t) );

	player->GetViewTrace( viewTrace, MASK_SHOT, 16.0f * 7.0f );

	if ( ( viewTrace.fraction < 1.0f ) && ( viewTrace.ent && viewTrace.entityNum == ENTITYNUM_WORLD ) )
	{
		newOrigin = viewTrace.endpos;

		up = viewTrace.plane.normal;
		PerpendicularVector( forward, viewTrace.plane.normal );
		left.CrossProduct( up, forward );

		forward.copyTo( axis[ AXIS_FORWARD_VECTOR ] );
		left.copyTo( axis[ AXIS_RIGHT_VECTOR ] );
		up.copyTo( axis[ AXIS_UP_VECTOR ] );

		AxisToAngles( axis, newAnglesVec );

		newAngles = newAnglesVec;

		return true;
	}

	return false;
}
Example #3
0
/*
=============
PhysicsEntitySetTransform
=============
*/
static void PhysicsEntitySetTransform ( const NewtonBody* body, const dFloat* matrix, int threadIndex ) {
	if(com_sv_running->integer) {
		sharedEntity_t *ent = (sharedEntity_t*)NewtonBodyGetUserData (body);
		vec3_t newPosition, angles, axis[3];
		
		SV_UnlinkEntity (ent);        
		
		newPosition[0] = matrix[12];
		newPosition[1] = matrix[13];
		newPosition[2] = matrix[14];
		
		// update the origin.
		VectorScale (newPosition, METRES_PER_UNIT, newPosition);
		VectorCopy (newPosition, ent->s.pos.trBase);
		VectorCopy (newPosition, ent->r.currentOrigin);
		VectorCopy (newPosition, ent->s.origin);
		
		axis[0][0] = matrix[0];
		axis[0][1] = matrix[1];
		axis[0][2] = matrix[2];
		axis[1][0] = matrix[4];
		axis[1][1] = matrix[5];
		axis[1][2] = matrix[6];
		axis[2][0] = matrix[8];
		axis[2][1] = matrix[9];
		axis[2][2] = matrix[10];
		AxisToAngles (axis, angles);

		VectorCopy (angles, ent->s.apos.trBase);
		VectorCopy (angles, ent->r.currentAngles);
		VectorCopy (angles, ent->s.angles);

		SV_LinkEntity (ent);

#if defined(_DEBUG)
		Com_Printf ("PHYSICS: updating %d new position %s\n", ent->s.number, vtos (newPosition));
#endif
    }
}
Example #4
0
/*
===============
CG_OffsetShoulderView

===============
*/
void CG_OffsetShoulderView( void )
{
  int            i;
  int            cmdNum;
  usercmd_t      cmd, oldCmd;
  vec3_t         rotationAngles;
  vec3_t         axis[ 3 ], rotaxis[ 3 ];
  float          deltaMousePitch;
  static float   mousePitch;
  vec3_t         forward, right, up;
  classConfig_t* classConfig;

  // Ignore following pitch; it's too jerky otherwise.
  if( !cg_thirdPersonPitchFollow.integer ) 
    cg.refdefViewAngles[ PITCH ] = 0.0f;
    
  AngleVectors( cg.refdefViewAngles, forward, right, up );

  classConfig = BG_ClassConfig( cg.snap->ps.stats[ STAT_CLASS ] );
  VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 0 ], forward, cg.refdef.vieworg );
  VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 1 ], right, cg.refdef.vieworg );
  VectorMA( cg.refdef.vieworg, classConfig->shoulderOffsets[ 2 ], up, cg.refdef.vieworg );

  // If someone is playing like this, the rest is already taken care of
  // so just get the firstperson effects and leave.
  if( !cg.demoPlayback && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    CG_OffsetFirstPersonView();
    return;
  }

  // Get mouse input for camera rotation. 
  cmdNum = trap_GetCurrentCmdNumber();
  trap_GetUserCmd( cmdNum, &cmd );
  trap_GetUserCmd( cmdNum - 1, &oldCmd );

  // Prevent pitch from wrapping and clamp it within a [30, -50] range.
  // Cgame has no access to ps.delta_angles[] here, so we need to reproduce
  // it ourselves here.
  deltaMousePitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] );
  if( fabs(deltaMousePitch) < 200.0f )
    mousePitch += deltaMousePitch;

  // Handle pitch.
  rotationAngles[ PITCH ] = mousePitch;

  rotationAngles[ PITCH ] = AngleNormalize180( rotationAngles[ PITCH ] + AngleNormalize180( cg.refdefViewAngles[ PITCH ] ) );
  if( rotationAngles [ PITCH ] < -90.0f ) rotationAngles [ PITCH ] = -90.0f;
  if( rotationAngles [ PITCH ] > 90.0f ) rotationAngles [ PITCH ] = 90.0f;

  // Yaw and Roll are much easier.
  rotationAngles[ YAW ] = SHORT2ANGLE( cmd.angles[ YAW ] ) + cg.refdefViewAngles[ YAW ];
  rotationAngles[ ROLL ] = 0.0f;

  // Perform the rotations.
  AnglesToAxis( rotationAngles, axis );
  if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
      !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse,
                      cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) )
    AxisCopy( axis, rotaxis );

  AxisToAngles( rotaxis, rotationAngles );

  // Actually set the viewangles.
  for( i = 0; i < 3; i++ )
    cg.refdefViewAngles[ i ] = rotationAngles[ i ];

  // Now run the first person stuff so we get various effects added.
  CG_OffsetFirstPersonView( );
}
Example #5
0
/*
===============
CG_OffsetThirdPersonView

===============
*/
void CG_OffsetThirdPersonView( void )
{
  int i;
  vec3_t        forward, right, up;
  vec3_t        view;
  trace_t       trace;
  static vec3_t mins = { -8, -8, -8 };
  static vec3_t maxs = { 8, 8, 8 };
  vec3_t        focusPoint;
  vec3_t        surfNormal;
  int           cmdNum;
  usercmd_t     cmd, oldCmd;
  float         range;
  vec3_t        mouseInputAngles;
  vec3_t        rotationAngles;
  vec3_t        axis[ 3 ], rotaxis[ 3 ];
  float         deltaPitch;
  static float  pitch;
  static vec3_t killerPos = { 0, 0, 0 };

  // If cg_thirdpersonShoulderViewMode == 2, do shoulder view instead
  // If cg_thirdpersonShoulderViewMode == 1, do shoulder view when chasing
  //   a wallwalker because it's really erratic to watch
  if( ( cg_thirdPersonShoulderViewMode.integer == 2 ) ||
      ( ( cg_thirdPersonShoulderViewMode.integer == 1 ) &&
        ( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) &&
        ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) ) )
  {
    CG_OffsetShoulderView( );
    return;
  }

  BG_GetClientNormal( &cg.predictedPlayerState, surfNormal );
  // Set the view origin to the class's view height
  VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg );

  // Set the focus point where the camera will look (at the player's vieworg)
  VectorCopy( cg.refdef.vieworg, focusPoint );

  // If player is dead, we want the player to be between us and the killer
  // so pretend that the player was looking at the killer, then place cam behind them.
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
  {
    int killerEntNum = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];

    // already looking at ourself
    if( killerEntNum != cg.snap->ps.clientNum )
    {
      vec3_t lookDirection;
      if( cg.wasDeadLastFrame == qfalse || !cg_staticDeathCam.integer )
      {
        VectorCopy( cg_entities[ killerEntNum ].lerpOrigin, killerPos );
        cg.wasDeadLastFrame = qtrue;
      }
      VectorSubtract( killerPos, cg.refdef.vieworg, lookDirection );
      vectoangles( lookDirection, cg.refdefViewAngles );
    }
  }

  // get and rangecheck cg_thirdPersonRange
  range = cg_thirdPersonRange.value;
  if( range > 150.0f ) range = 150.0f;
  if( range < 30.0f ) range = 30.0f;

  // Calculate the angle of the camera's position around the player.
  // Unless in demo, PLAYING in third person, or in dead-third-person cam, allow the player 
  // to control camera position offsets using the mouse position.
  if( cg.demoPlayback || 
    ( ( cg.snap->ps.pm_flags & PMF_FOLLOW ) && 
      ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 ) ) )
  {
    // Collect our input values from the mouse.
    cmdNum = trap_GetCurrentCmdNumber();
    trap_GetUserCmd( cmdNum, &cmd );
    trap_GetUserCmd( cmdNum - 1, &oldCmd );

    // Prevent pitch from wrapping and clamp it within a [-75, 90] range.
    // Cgame has no access to ps.delta_angles[] here, so we need to reproduce
    // it ourselves.
    deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] );
    if( fabs(deltaPitch) < 200.0f )
    {
      pitch += deltaPitch;
    }

    mouseInputAngles[ PITCH ] = pitch;
    mouseInputAngles[ YAW ] = -1.0f * SHORT2ANGLE( cmd.angles[ YAW ] ); // yaw is inverted
    mouseInputAngles[ ROLL ] = 0.0f;

    for( i = 0; i < 3; i++ )
      mouseInputAngles[ i ] = AngleNormalize180( mouseInputAngles[ i ] );

    // Set the rotation angles to be the view angles offset by the mouse input
    // Ignore the original pitch though; it's too jerky otherwise
    if( !cg_thirdPersonPitchFollow.integer ) 
      cg.refdefViewAngles[ PITCH ] = 0.0f;

    for( i = 0; i < 3; i++ )
    {
      rotationAngles[ i ] = AngleNormalize180(cg.refdefViewAngles[ i ]) + mouseInputAngles[ i ];
      AngleNormalize180( rotationAngles[ i ] );
    }

    // Don't let pitch go too high/too low or the camera flips around and
    // that's really annoying.
    // However, when we're not on the floor or ceiling (wallwalk) pitch 
    // may not be pitch, so just let it go.
    if( surfNormal[ 2 ] > 0.5f || surfNormal[ 2 ] < -0.5f ) 
    {
      if( rotationAngles[ PITCH ] > 85.0f )
        rotationAngles[ PITCH ] = 85.0f;
      else if( rotationAngles[ PITCH ] < -85.0f )
        rotationAngles[ PITCH ] = -85.0f;
    }

    // Perform the rotations specified by rotationAngles.
    AnglesToAxis( rotationAngles, axis );
    if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) ||
        !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse,
                        cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) )
      AxisCopy( axis, rotaxis );

    // Convert the new axis back to angles.
    AxisToAngles( rotaxis, rotationAngles );
  }
  else 
  {
    if( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
    {
      // If we're playing the game in third person, the viewangles already
      // take care of our mouselook, so just use them.
      for( i = 0; i < 3; i++ )
        rotationAngles[ i ] = cg.refdefViewAngles[ i ];
    }
    else // dead
    {
      rotationAngles[ PITCH ] = 20.0f;
      rotationAngles[ YAW ] = cg.refdefViewAngles[ YAW ];
    }
  }

  rotationAngles[ YAW ] -= cg_thirdPersonAngle.value;

  // Move the camera range distance back.
  AngleVectors( rotationAngles, forward, right, up );
  VectorCopy( cg.refdef.vieworg, view );
  VectorMA( view, -range, forward, view );

  // Ensure that the current camera position isn't out of bounds and that there
  // is nothing between the camera and the player.
  if( !cg_cameraMode.integer )
  {
    // Trace a ray from the origin to the viewpoint to make sure the view isn't
    // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything
    CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

    if( trace.fraction != 1.0f )
    {
      VectorCopy( trace.endpos, view );
      view[ 2 ] += ( 1.0f - trace.fraction ) * 32;
      // Try another trace to this position, because a tunnel may have the ceiling
      // close enogh that this is poking out.

      CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
      VectorCopy( trace.endpos, view );
    }
  }

  // Set the camera position to what we calculated.
  VectorCopy( view, cg.refdef.vieworg );

  // The above checks may have moved the camera such that the existing viewangles
  // may not still face the player. Recalculate them to do so.
  // but if we're dead, don't bother because we'd rather see what killed us
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 )
  {
    VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
    vectoangles( focusPoint, cg.refdefViewAngles );
  }
}
Example #6
0
/*
===============
CG_smoothWWTransitions
===============
*/
static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t out )
{
  vec3_t    surfNormal, rotAxis, temp;
  vec3_t    refNormal     = { 0.0f, 0.0f,  1.0f };
  vec3_t    ceilingNormal = { 0.0f, 0.0f, -1.0f };
  int       i;
  float     stLocal, sFraction, rotAngle;
  float     smoothTime, timeMod;
  qboolean  performed = qfalse;
  vec3_t    inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ];

  if( cg.snap->ps.pm_flags & PMF_FOLLOW )
  {
    VectorCopy( in, out );
    return;
  }

  //set surfNormal
  BG_GetClientNormal( ps, surfNormal );

  AnglesToAxis( in, inAxis );

  //if we are moving from one surface to another smooth the transition
  if( !VectorCompare( surfNormal, cg.lastNormal ) )
  {
    //if we moving from the ceiling to the floor special case
    //( x product of colinear vectors is undefined)
    if( VectorCompare( ceilingNormal, cg.lastNormal ) &&
        VectorCompare( refNormal,     surfNormal ) )
    {
      AngleVectors( in, temp, NULL, NULL );
      ProjectPointOnPlane( rotAxis, temp, refNormal );
      VectorNormalize( rotAxis );
      rotAngle = 180.0f;
      timeMod = 1.5f;
    }
    else
    {
      AnglesToAxis( cg.lastVangles, lastAxis );
      rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) +
                 DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) +
                 DotProduct( inAxis[ 2 ], lastAxis[ 2 ] );

      rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) );

      CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp );
      VectorCopy( temp, rotAxis );
      CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp );
      VectorAdd( rotAxis, temp, rotAxis );
      CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp );
      VectorAdd( rotAxis, temp, rotAxis );

      VectorNormalize( rotAxis );

      timeMod = 1.0f;
    }

    //add the op
    CG_addSmoothOp( rotAxis, rotAngle, timeMod );
  }

  //iterate through ops
  for( i = MAXSMOOTHS - 1; i >= 0; i-- )
  {
    smoothTime = (int)( cg_wwSmoothTime.integer * cg.sList[ i ].timeMod );

    //if this op has time remaining, perform it
    if( cg.time < cg.sList[ i ].time + smoothTime )
    {
      stLocal = 1.0f - ( ( ( cg.sList[ i ].time + smoothTime ) - cg.time ) / smoothTime );
      sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f;

      RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis,
        inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle );
      RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis,
        inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle );
      RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis,
        inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle );

      AxisCopy( outAxis, inAxis );
      performed = qtrue;
    }
  }

  //if we performed any ops then return the smoothed angles
  //otherwise simply return the in angles
  if( performed )
    AxisToAngles( outAxis, out );
  else
    VectorCopy( in, out );

  //copy the current normal to the lastNormal
  VectorCopy( in, cg.lastVangles );
  VectorCopy( surfNormal, cg.lastNormal );
}
Example #7
0
void CG_GibPlayer(centity_t *cent, vec3_t playerOrigin, vec3_t gdir)
{
	int            i, count = 0, tagIndex, gibIndex;
	vec3_t         origin, velocity, dir;
	trace_t        trace;
	qboolean       foundtag;
	clientInfo_t   *ci;
	int            clientNum;
	bg_character_t *character;
	vec4_t         projection, color;

	// Rafael
	// BloodCloud
	qboolean newjunction[MAXJUNCTIONS];
	vec3_t   junctionOrigin[MAXJUNCTIONS];
	int      junction;
	int      j;
	vec3_t   axis[3], angles;

	char *JunctiongibTags[] =
	{
		// leg tag
		"tag_footright",
		"tag_footleft",
		"tag_legright",
		"tag_legleft",

		// torsotags
		"tag_armright",
		"tag_armleft",

		"tag_torso",
		"tag_chest"
	};

	char *ConnectTags[] =
	{
		// legs tags
		"tag_legright",
		"tag_legleft",
		"tag_torso",
		"tag_torso",

		// torso tags
		"tag_chest",
		"tag_chest",

		"tag_chest",
		"tag_torso",
	};

	char *gibTags[] =
	{
		// tags in the legs
		"tag_footright",
		"tag_footleft",
		"tag_legright",
		"tag_legleft",
		"tag_torso",

		// tags in the torso
		"tag_chest",
		"tag_armright",
		"tag_armleft",
		"tag_head",
		NULL
	};

	if (cg_blood.integer)
	{
		// Rafael
		for (i = 0; i < MAXJUNCTIONS; i++)
			newjunction[i] = qfalse;

		clientNum = cent->currentState.clientNum;
		if (clientNum < 0 || clientNum >= MAX_CLIENTS)
		{
			CG_Error("Bad clientNum on player entity");
		}
		ci        = &cgs.clientinfo[clientNum];
		character = CG_CharacterForClientinfo(ci, cent);

		// Ridah, fetch the various positions of the tag_gib*'s
		// and spawn the gibs from the correct places (especially the head)
		for (gibIndex = 0, count = 0, foundtag = qtrue; foundtag && gibIndex < MAX_GIB_MODELS && gibTags[gibIndex]; gibIndex++)
		{

			refEntity_t *re = 0;

			foundtag = qfalse;

			if (!character->gibModels[gibIndex])
			{
				continue;
			}

			re = &cent->pe.bodyRefEnt;

			for (tagIndex = 0; (tagIndex = CG_GetOriginForTag(cent, re, gibTags[gibIndex], tagIndex, origin, axis)) >= 0; count++, tagIndex++)
			{

				foundtag = qtrue;

				VectorSubtract(origin, re->origin, dir);
				VectorNormalize(dir);

				// spawn a gib
				velocity[0] = dir[0] * (0.5 + random()) * GIB_VELOCITY * 0.3;
				velocity[1] = dir[1] * (0.5 + random()) * GIB_VELOCITY * 0.3;
				velocity[2] = GIB_JUMP + dir[2] * (0.5 + random()) * GIB_VELOCITY * 0.5;

				VectorMA(velocity, GIB_VELOCITY, gdir, velocity);
				AxisToAngles(axis, angles);

				CG_LaunchGib(cent, origin, angles, velocity, character->gibModels[gibIndex], 1.0, 0);

				for (junction = 0; junction < MAXJUNCTIONS; junction++)
				{
					if (!Q_stricmp(gibTags[gibIndex], JunctiongibTags[junction]))
					{
						VectorCopy(origin, junctionOrigin[junction]);
						newjunction[junction] = qtrue;
					}
				}
			}
		}

		for (i = 0; i < MAXJUNCTIONS; i++)
		{
			if (newjunction[i] == qtrue)
			{
				for (j = 0; j < MAXJUNCTIONS; j++)
				{
					if (!Q_stricmp(JunctiongibTags[j], ConnectTags[i]))
					{
						if (newjunction[j] == qtrue)
						{
							// spawn a blood cloud somewhere on the vec from
							VectorSubtract(junctionOrigin[i], junctionOrigin[j], dir);
							CG_ParticleBloodCloud(cent, junctionOrigin[i], dir);
						}
					}
				}
			}
		}

		// Ridah, spawn a bunch of blood dots around the place
		#define GIB_BLOOD_DOTS  3
		for (i = 0, count = 0; i < GIB_BLOOD_DOTS * 2; i++)
		{
			// TTimo: unused
			//static vec3_t mins = {-10,-10,-10};
			//static vec3_t maxs = { 10, 10, 10};

			if (i > 0)
			{
				velocity[0] = ((i % 2) * 2 - 1) * (40 + 40 * random());
				velocity[1] = (((i / 2) % 2) * 2 - 1) * (40 + 40 * random());
				velocity[2] = (((i < GIB_BLOOD_DOTS) * 2) - 1) * 40;
			}
			else
			{
				VectorClear(velocity);
				velocity[2] = -64;
			}

			VectorAdd(playerOrigin, velocity, origin);

			CG_Trace(&trace, playerOrigin, NULL, NULL, origin, -1, CONTENTS_SOLID);
			if (trace.fraction < 1.0)
			{
				//%	BG_GetMarkDir( velocity, trace.plane.normal, velocity );
				//%	CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace.endpos, velocity, random()*360,
				//%		1,1,1,1, qtrue, 30, qfalse, cg_bloodTime.integer * 1000 );
				#if 0
				BG_GetMarkDir(velocity, trace.plane.normal, projection);
				VectorSubtract(vec3_origin, projection, projection);
				projection[3] = 64;
				VectorMA(trace.endpos, -8.0f, projection, markOrigin);
				CG_ImpactMark(cgs.media.bloodDotShaders[rand() % 5], markOrigin, projection, 30.0f, random() * 360.0f, 1.0f, 1.0f, 1.0f, 1.0f, cg_bloodTime.integer * 1000);
				#else
				VectorSet(projection, 0, 0, -1);
				projection[3] = 30.0f;
				Vector4Set(color, 1.0f, 1.0f, 1.0f, 1.0f);
				trap_R_ProjectDecal(cgs.media.bloodDotShaders[rand() % 5], 1, (vec3_t *) trace.endpos, projection, color,
				                    cg_bloodTime.integer * 1000, (cg_bloodTime.integer * 1000) >> 4);
				#endif

				if (count++ > GIB_BLOOD_DOTS)
				{
					break;
				}
			}
		}
	}