예제 #1
0
/*
===============
Set muzzle location relative to pivoting eye.
===============
*/
void G_CalcMuzzlePoint( gentity_t *self, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint )
{
	vec3_t normal;

	VectorCopy( self->client->ps.origin, muzzlePoint );
	BG_GetClientNormal( &self->client->ps, normal );
	VectorMA( muzzlePoint, self->client->ps.viewheight, normal, muzzlePoint );
	VectorMA( muzzlePoint, 1, forward, muzzlePoint );
	// snap to integer coordinates for more efficient network bandwidth usage
	SnapVector( muzzlePoint );
}
예제 #2
0
// this causes a compiler bug on mac MrC compiler
static void CG_StepOffset( void )
{
  float         steptime;
  int           timeDelta;
  vec3_t        normal;
  playerState_t *ps = &cg.predictedPlayerState;

  BG_GetClientNormal( ps, normal );

  steptime = BG_Class( ps->stats[ STAT_CLASS ] )->steptime;

  // smooth out stair climbing
  timeDelta = cg.time - cg.stepTime;
  if( timeDelta < steptime )
  {
    float stepChange = cg.stepChange
      * (steptime - timeDelta) / steptime;

    VectorMA( cg.refdef.vieworg, -stepChange, normal, cg.refdef.vieworg );
  }
}
예제 #3
0
// TODO: Use new vector math library for all calculations.
void ArmorComponent::HandleApplyDamageModifier(float& damage, Util::optional<Vec3> location,
Util::optional<Vec3> direction, int flags, meansOfDeath_t meansOfDeath) {
	vec3_t origin, bulletPath, bulletAngle, locationRelativeToFloor, floor, normal;

	// TODO: Remove dependency on client.
	assert(entity.oldEnt->client);

	// Use non-regional damage where appropriate.
	if (flags & DAMAGE_NO_LOCDAMAGE || !location) {
		// TODO: Move G_GetNonLocDamageMod to ArmorComponent.
		damage *= GetNonLocationalDamageMod();
		return;
	}

	// Get hit location relative to the floor beneath.
	if (g_unlagged.integer && entity.oldEnt->client->unlaggedCalc.used) {
		VectorCopy(entity.oldEnt->client->unlaggedCalc.origin, origin);
	} else {
		VectorCopy(entity.oldEnt->r.currentOrigin, origin);
	}
	BG_GetClientNormal(&entity.oldEnt->client->ps, normal);
	VectorMA(origin, entity.oldEnt->r.mins[2], normal, floor);
	VectorSubtract(location.value().Data(), floor, locationRelativeToFloor);

	// Get fraction of height where the hit landed.
	float height = entity.oldEnt->r.maxs[2] - entity.oldEnt->r.mins[2];
	if (!height) height = 1.0f;
	float hitRatio = Math::Clamp(DotProduct(normal, locationRelativeToFloor) / VectorLength(normal),
	                             0.0f, height) / height;

	// Get the yaw of the attack relative to the target's view yaw
	VectorSubtract(location.value().Data(), origin, bulletPath);
	vectoangles(bulletPath, bulletAngle);
	int hitRotation = AngleNormalize360(entity.oldEnt->client->ps.viewangles[YAW] - bulletAngle[YAW]);

	// Use regional modifier.
	// TODO: Move G_GetPointDamageMod to ArmorComponent.
	damage *= GetLocationalDamageMod(hitRotation, hitRatio);
}
예제 #4
0
/*
=============
CG_DrawDir

Draw dot marking the direction to an enemy
=============
*/
static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
  vec3_t  drawOrigin;
  vec3_t  noZOrigin;
  vec3_t  normal, antinormal, normalDiff;
  vec3_t  view, noZview;
  vec3_t  up  = { 0.0f, 0.0f,   1.0f };
  vec3_t  top = { 0.0f, -1.0f,  0.0f };
  float   angle;
  playerState_t *ps = &cg.snap->ps;

  BG_GetClientNormal( ps, normal );

  AngleVectors( entityPositions.vangles, view, NULL, NULL );

  ProjectPointOnPlane( noZOrigin, origin, normal );
  ProjectPointOnPlane( noZview, view, normal );
  VectorNormalize( noZOrigin );
  VectorNormalize( noZview );

  //calculate the angle between the images of the blip and the view
  angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
  CrossProduct( noZOrigin, noZview, antinormal );
  VectorNormalize( antinormal );

  //decide which way to rotate
  VectorSubtract( normal, antinormal, normalDiff );
  if( VectorLength( normalDiff ) < 1.0f )
    angle = 360.0f - angle;

  RotatePointAroundVector( drawOrigin, up, top, angle );

  trap_R_SetColor( colour );
  CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
              rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
              BLIPX2, BLIPY2, cgs.media.scannerBlipShader );
  trap_R_SetColor( NULL );
}
예제 #5
0
bool BotPathIsWalkable( gentity_t *self, botTarget_t target )
{
	vec3_t selfPos, targetPos;
	vec3_t viewNormal;
	botTrace_t trace;

	BG_GetClientNormal( &self->client->ps, viewNormal );
	VectorMA( self->s.origin, self->r.mins[2], viewNormal, selfPos );
	BotGetTargetPos( target, targetPos );

	if ( !trap_BotNavTrace( self->s.number, &trace, selfPos, targetPos ) )
	{
		return false;
	}

	if ( trace.frac >= 1.0f )
	{
		return true;
	}
	else
	{
		return false;
	}
}
예제 #6
0
/*
==================
PM_StepSlideMove
==================
*/
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
{
	vec3_t   start_o, start_v;
	vec3_t   down_o, down_v;
	trace_t  trace;
	vec3_t   normal;
	vec3_t   step_v, step_vNormal;
	vec3_t   up, down;
	float    stepSize;
	qboolean stepped = qfalse;

	BG_GetClientNormal( pm->ps, normal );

	VectorCopy( pm->ps->origin, start_o );
	VectorCopy( pm->ps->velocity, start_v );

	if ( PM_SlideMove( gravity ) == 0 )
	{
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		//we can step down
		if ( trace.fraction > 0.01f && trace.fraction < 1.0f &&
		     !trace.allsolid && pml.groundPlane != qfalse )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%d: step down\n", c_pmove );
			}

			stepped = qtrue;
		}
	}
	else
	{
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		// never step up when you still have up velocity
		if ( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
		     ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
		{
			return stepped;
		}

		VectorCopy( pm->ps->origin, down_o );
		VectorCopy( pm->ps->velocity, down_v );

		VectorCopy( start_o, up );
		VectorMA( up, STEPSIZE, normal, up );

		// test the player position if they were a stepheight higher
		pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );

		if ( trace.allsolid )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%i:bend can't step\n", c_pmove );
			}

			return stepped; // can't step up
		}

		VectorSubtract( trace.endpos, start_o, step_v );
		VectorCopy( step_v, step_vNormal );
		VectorNormalize( step_vNormal );

		stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
		// try slidemove from this position
		VectorCopy( trace.endpos, pm->ps->origin );
		VectorCopy( start_v, pm->ps->velocity );

		if ( PM_SlideMove( gravity ) == 0 )
		{
			if ( pm->debugLevel > 1 )
			{
				Com_Printf( "%d: step up\n", c_pmove );
			}

			stepped = qtrue;
		}

		// push down the final amount
		VectorCopy( pm->ps->origin, down );
		VectorMA( down, -stepSize, normal, down );
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );

		if ( !trace.allsolid )
		{
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction < 1.0f )
		{
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity );
		}
	}

	if ( !predictive && stepped )
	{
		PM_StepEvent( start_o, pm->ps->origin, normal );
	}

	return stepped;
}
예제 #7
0
/*
===============
CG_OffsetFirstPersonView

===============
*/
void CG_OffsetFirstPersonView( void )
{
  float         *origin;
  float         *angles;
  float         bob;
  float         ratio;
  float         delta;
  float         speed;
  float         f;
  vec3_t        predictedVelocity;
  int           timeDelta;
  float         bob2;
  vec3_t        normal, baseOrigin;
  playerState_t *ps = &cg.predictedPlayerState;

  BG_GetClientNormal( ps, normal );

  if( cg.snap->ps.pm_type == PM_INTERMISSION )
    return;

  origin = cg.refdef.vieworg;
  angles = cg.refdefViewAngles;

  VectorCopy( origin, baseOrigin );

  // if dead, fix the angle and don't add any kick
  if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
  {
    angles[ ROLL ] = 40;
    angles[ PITCH ] = -15;
    angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ];
    origin[ 2 ] += cg.predictedPlayerState.viewheight;
    return;
  }
  // camera shake effect
  else if( cg.snap->ps.stats[ STAT_SHAKE ] > 0 )
  {
    float fac;

    fac = (float) cg.snap->ps.stats[ STAT_SHAKE ] *
          cg_cameraShakeMagnitude.value * 0.15f;

    angles[ 0 ] += crandom() * fac;
    angles[ 1 ] += crandom() * fac;
    angles[ 2 ] += crandom() * fac;
  }

  // add angles based on damage kick
  if( cg.damageTime )
  {
    ratio = cg.time - cg.damageTime;
    if( ratio < DAMAGE_DEFLECT_TIME )
    {
      ratio /= DAMAGE_DEFLECT_TIME;
      angles[ PITCH ] += ratio * cg.v_dmg_pitch;
      angles[ ROLL ] += ratio * cg.v_dmg_roll;
    }
    else
    {
      ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
      if( ratio > 0 )
      {
        angles[ PITCH ] += ratio * cg.v_dmg_pitch;
        angles[ ROLL ] += ratio * cg.v_dmg_roll;
      }
    }
  }

  // add pitch based on fall kick
#if 0
  ratio = ( cg.time - cg.landTime) / FALL_TIME;
  if (ratio < 0)
    ratio = 0;
  angles[PITCH] += ratio * cg.fall_value;
#endif

  // add angles based on velocity
  VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );

  delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] );
  angles[ PITCH ] += delta * cg_runpitch.value;

  delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] );
  angles[ ROLL ] -= delta * cg_runroll.value;

  // add angles based on bob
  // bob amount is class dependant

  if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
    bob2 = 0.0f;
  else
    bob2 = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob;


#define LEVEL4_FEEDBACK  10.0f

  //give a charging player some feedback
  if( ps->weapon == WP_ALEVEL4 )
  {
    if( ps->stats[ STAT_MISC ] > 0 )
    {
      float fraction = (float)ps->stats[ STAT_MISC ] /
                       LEVEL4_TRAMPLE_CHARGE_MAX;

      if( fraction > 1.0f )
        fraction = 1.0f;

      bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK );
    }
  }

  if( bob2 != 0.0f )
  {
    // make sure the bob is visible even at low speeds
    speed = cg.xyspeed > 200 ? cg.xyspeed : 200;

    delta = cg.bobfracsin * ( bob2 ) * speed;
    if( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
      delta *= 3;   // crouching

    angles[ PITCH ] += delta;
    delta = cg.bobfracsin * ( bob2 ) * speed;
    if( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
      delta *= 3;   // crouching accentuates roll

    if( cg.bobcycle & 1 )
      delta = -delta;

    angles[ ROLL ] += delta;
  }

#define LEVEL3_FEEDBACK  20.0f

  //provide some feedback for pouncing
  if( ( cg.predictedPlayerState.weapon == WP_ALEVEL3 ||
        cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) &&
      cg.predictedPlayerState.stats[ STAT_MISC ] > 0 )
  {
    float fraction1, fraction2;
    vec3_t forward;

    AngleVectors( angles, forward, NULL, NULL );
    VectorNormalize( forward );

    fraction1 = (float)cg.predictedPlayerState.stats[ STAT_MISC ] /
                LEVEL3_POUNCE_TIME_UPG;
    if( fraction1 > 1.0f )
      fraction1 = 1.0f;

    fraction2 = -sin( fraction1 * M_PI / 2 );

    VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin );
  }

#define STRUGGLE_DIST 5.0f
#define STRUGGLE_TIME 250

  //allow the player to struggle a little whilst grabbed
  if( cg.predictedPlayerState.pm_type == PM_GRABBED )
  {
    vec3_t    forward, right, up;
    usercmd_t cmd;
    int       cmdNum;
    float     fFraction, rFraction, uFraction;
    float     fFraction2, rFraction2, uFraction2;

    cmdNum = trap_GetCurrentCmdNumber();
    trap_GetUserCmd( cmdNum, &cmd );

    AngleVectors( angles, forward, right, up );

    fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME;
    rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME;
    uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME;

    if( fFraction > 1.0f )
      fFraction = 1.0f;
    if( rFraction > 1.0f )
      rFraction = 1.0f;
    if( uFraction > 1.0f )
      uFraction = 1.0f;

    fFraction2 = -sin( fFraction * M_PI / 2 );
    rFraction2 = -sin( rFraction * M_PI / 2 );
    uFraction2 = -sin( uFraction * M_PI / 2 );

    if( cmd.forwardmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin );
    else if( cmd.forwardmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin );
    else
      cg.forwardMoveTime = cg.time;

    if( cmd.rightmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin );
    else if( cmd.rightmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin );
    else
      cg.rightMoveTime = cg.time;

    if( cmd.upmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin );
    else if( cmd.upmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin );
    else
      cg.upMoveTime = cg.time;
  }

  if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
      ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    float scale, fraction, pitchFraction;
    
    scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
            BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
    if( scale < 0.0f )
      scale = 0.0f;

    fraction = sin( ( cg.time - cg.poisonedTime ) / 500.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) *
               scale;
    pitchFraction = sin( ( cg.time - cg.poisonedTime ) / 200.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) *
                    scale;

    angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE;
    angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE;
    angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f;
  }

  // this *feels* more realisitic for humans
  if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS &&
      ( cg.predictedPlayerState.pm_type == PM_NORMAL ||
        cg.predictedPlayerState.pm_type == PM_JETPACK ) )
  {
    angles[PITCH] += cg.bobfracsin * bob2 * 0.5;

    // heavy breathing effects //FIXME: sound
    if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < STAMINA_BREATHING_LEVEL )
    {
      float deltaBreath = ( cg.predictedPlayerState.stats[ STAT_STAMINA ] -
                            STAMINA_BREATHING_LEVEL ) / -250.0;
      float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath;

      deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5;

      angles[ PITCH ] -= deltaAngle;
    }
  }

//===================================

  // add view height
  VectorMA( origin, ps->viewheight, normal, origin );

  // smooth out duck height changes
  timeDelta = cg.time - cg.duckTime;
  if( timeDelta < DUCK_TIME)
  {
    cg.refdef.vieworg[ 2 ] -= cg.duckChange
      * ( DUCK_TIME - timeDelta ) / DUCK_TIME;
  }

  // add bob height
  bob = cg.bobfracsin * cg.xyspeed * bob2;

  if( bob > 6 )
    bob = 6;

  VectorMA( origin, bob, normal, origin );

  // add fall height
  delta = cg.time - cg.landTime;

  if( delta < LAND_DEFLECT_TIME )
  {
    f = delta / LAND_DEFLECT_TIME;
    cg.refdef.vieworg[ 2 ] += cg.landChange * f;
  }
  else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME )
  {
    delta -= LAND_DEFLECT_TIME;
    f = 1.0 - ( delta / LAND_RETURN_TIME );
    cg.refdef.vieworg[ 2 ] += cg.landChange * f;
  }

  // add step offset
  CG_StepOffset( );
}
예제 #8
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 );
  }
}
예제 #9
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 );
}
예제 #10
0
static float CalcDamageModifier( vec3_t point, gentity_t *target, class_t pcl, int damageFlags )
{
	vec3_t targOrigin, bulletPath, bulletAngle, pMINUSfloor, floor, normal;
	float  clientHeight, hitRelative, hitRatio, modifier;
	int    hitRotation;

	// handle nonlocational damage
	if ( damageFlags & DAMAGE_NO_LOCDAMAGE )
	{
		return G_GetNonLocDamageMod( pcl );
	}

	// need a valid point for point damage
	if ( point == NULL )
	{
		return 1.0f;
	}

	// Get the point location relative to the floor under the target
	if ( g_unlagged.integer && target->client && target->client->unlaggedCalc.used )
	{
		VectorCopy( target->client->unlaggedCalc.origin, targOrigin );
	}
	else
	{
		VectorCopy( target->r.currentOrigin, targOrigin );
	}

	BG_GetClientNormal( &target->client->ps, normal );
	VectorMA( targOrigin, target->r.mins[ 2 ], normal, floor );
	VectorSubtract( point, floor, pMINUSfloor );

	// Get the proportion of the target height where the hit landed
	clientHeight = target->r.maxs[ 2 ] - target->r.mins[ 2 ];

	if ( !clientHeight )
	{
		clientHeight = 1.0f;
	}

	hitRelative = DotProduct( normal, pMINUSfloor ) / VectorLength( normal );

	if ( hitRelative < 0.0f )
	{
		hitRelative = 0.0f;
	}

	if ( hitRelative > clientHeight )
	{
		hitRelative = clientHeight;
	}

	hitRatio = hitRelative / clientHeight;

	// Get the yaw of the attack relative to the target's view yaw
	VectorSubtract( point, targOrigin, bulletPath );
	vectoangles( bulletPath, bulletAngle );
	hitRotation = AngleNormalize360( target->client->ps.viewangles[ YAW ] - bulletAngle[ YAW ] );

	// Get damage region modifier
	modifier = G_GetPointDamageMod( target, pcl, hitRotation, hitRatio );

	return modifier;
}
예제 #11
0
/*
===============
CG_OffsetFirstPersonView

===============
*/
void CG_OffsetFirstPersonView( void )
{
	float         *origin;
	float         *angles;
	float         bob;
	float         ratio;
	float         delta;
	float         speed;
	float         f;
	vec3_t        predictedVelocity;
	int           timeDelta;
	float         bob2;
	vec3_t        normal, baseOrigin;
	playerState_t *ps = &cg.predictedPlayerState;

	BG_GetClientNormal( ps, normal );

	if ( cg.snap->ps.pm_type == PM_INTERMISSION )
	{
		return;
	}

	origin = cg.refdef.vieworg;
	angles = cg.refdefViewAngles;

	VectorCopy( origin, baseOrigin );

	// if dead, fix the angle and don't add any kick
	if ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
	{
		angles[ ROLL ] = 40;
		angles[ PITCH ] = -15;
		angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ];
		origin[ 2 ] += cg.predictedPlayerState.viewheight;
		return;
	}

	// add angles based on damage kick
	if ( cg.damageTime )
	{
		ratio = cg.time - cg.damageTime;

		if ( ratio < DAMAGE_DEFLECT_TIME )
		{
			ratio /= DAMAGE_DEFLECT_TIME;
			angles[ PITCH ] += ratio * cg.v_dmg_pitch;
			angles[ ROLL ] += ratio * cg.v_dmg_roll;
		}
		else
		{
			ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;

			if ( ratio > 0 )
			{
				angles[ PITCH ] += ratio * cg.v_dmg_pitch;
				angles[ ROLL ] += ratio * cg.v_dmg_roll;
			}
		}
	}

	// add pitch based on fall kick
#if 0
	ratio = ( cg.time - cg.landTime ) / FALL_TIME;

	if ( ratio < 0 )
	{
		ratio = 0;
	}

	angles[ PITCH ] += ratio * cg.fall_value;
#endif

	// add angles based on velocity
	VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );

	delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] );
	angles[ PITCH ] += delta * cg_runpitch.value;

	delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] );
	angles[ ROLL ] -= delta * cg_runroll.value;

	// add angles based on bob
	// bob amount is class-dependent

	if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
	{
		bob2 = 0.0f;
	}
	else
	{
		bob2 = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob;
	}

#define LEVEL4_FEEDBACK 10.0f

	//give a charging player some feedback
	if ( ps->weapon == WP_ALEVEL4 )
	{
		if ( ps->stats[ STAT_MISC ] > 0 )
		{
			float fraction = ( float ) ps->stats[ STAT_MISC ] /
			                 LEVEL4_TRAMPLE_CHARGE_MAX;

			if ( fraction > 1.0f )
			{
				fraction = 1.0f;
			}

			bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK );
		}
	}

	if ( bob2 != 0.0f )
	{
		// make sure the bob is visible even at low speeds
		speed = cg.xyspeed > 200 ? cg.xyspeed : 200;

		delta = cg.bobfracsin * ( bob2 ) * speed;

		if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
		{
			delta *= 3; // crouching
		}

		angles[ PITCH ] += delta;
		delta = cg.bobfracsin * ( bob2 ) * speed;

		if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
		{
			delta *= 3; // crouching accentuates roll
		}

		if ( cg.bobcycle & 1 )
		{
			delta = -delta;
		}

		angles[ ROLL ] += delta;
	}

#define LEVEL3_FEEDBACK 20.0f

	//provide some feedback for pouncing
	if ( ( cg.predictedPlayerState.weapon == WP_ALEVEL3 ||
	       cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) &&
	     cg.predictedPlayerState.stats[ STAT_MISC ] > 0 )
	{
		float  fraction1, fraction2;
		vec3_t forward;

		AngleVectors( angles, forward, NULL, NULL );
		VectorNormalize( forward );

		fraction1 = ( float ) cg.predictedPlayerState.stats[ STAT_MISC ] /
		            LEVEL3_POUNCE_TIME_UPG;

		if ( fraction1 > 1.0f )
		{
			fraction1 = 1.0f;
		}

		fraction2 = -sin( fraction1 * M_PI / 2 );

		VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin );
	}

#define STRUGGLE_DIST 5.0f
#define STRUGGLE_TIME 250

	//allow the player to struggle a little whilst grabbed
	if ( cg.predictedPlayerState.pm_type == PM_GRABBED )
	{
		vec3_t    forward, right, up;
		usercmd_t cmd;
		int       cmdNum;
		float     fFraction, rFraction, uFraction;

		cmdNum = trap_GetCurrentCmdNumber();
		trap_GetUserCmd( cmdNum, &cmd );

		AngleVectors( angles, forward, right, up );

		fFraction = ( float )( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME;
		rFraction = ( float )( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME;
		uFraction = ( float )( cg.time - cg.upMoveTime ) / STRUGGLE_TIME;

		if ( fFraction > 1.0f )
		{
			fFraction = 1.0f;
		}

		if ( rFraction > 1.0f )
		{
			rFraction = 1.0f;
		}

		if ( uFraction > 1.0f )
		{
			uFraction = 1.0f;
		}

		if ( cmd.forwardmove > 0 )
		{
			VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin );
		}
		else if ( cmd.forwardmove < 0 )
		{
			VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin );
		}
		else
		{
			cg.forwardMoveTime = cg.time;
		}

		if ( cmd.rightmove > 0 )
		{
			VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin );
		}
		else if ( cmd.rightmove < 0 )
		{
			VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin );
		}
		else
		{
			cg.rightMoveTime = cg.time;
		}

		if ( cmd.upmove > 0 )
		{
			VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin );
		}
		else if ( cmd.upmove < 0 )
		{
			VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin );
		}
		else
		{
			cg.upMoveTime = cg.time;
		}
	}

	// this *feels* more realisitic for humans <- this comment feels very descriptive
	if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS &&
	     cg.predictedPlayerState.pm_type == PM_NORMAL )
	{
		angles[ PITCH ] += cg.bobfracsin * bob2 * 0.5;
	}

	// add view height
	VectorMA( origin, ps->viewheight, normal, origin );

	// smooth out duck height changes
	timeDelta = cg.time - cg.duckTime;

	if ( timeDelta < DUCK_TIME )
	{
		cg.refdef.vieworg[ 2 ] -= cg.duckChange
		                          * ( DUCK_TIME - timeDelta ) / DUCK_TIME;
	}

	// add bob height
	bob = cg.bobfracsin * cg.xyspeed * bob2;

	if ( bob > 6 )
	{
		bob = 6;
	}

	VectorMA( origin, bob, normal, origin );

	// add fall height
	delta = cg.time - cg.landTime;

	if ( delta < LAND_DEFLECT_TIME )
	{
		f = delta / LAND_DEFLECT_TIME;
		cg.refdef.vieworg[ 2 ] += cg.landChange * f;
	}
	else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME )
	{
		delta -= LAND_DEFLECT_TIME;
		f = 1.0 - ( delta / LAND_RETURN_TIME );
		cg.refdef.vieworg[ 2 ] += cg.landChange * f;
	}

	// add step offset
	CG_StepOffset();
}
예제 #12
0
/*
==================
PM_StepSlideMove
==================
*/
bool PM_StepSlideMove( bool gravity, bool predictive )
{
	vec3_t   start_o, start_v;
#ifndef UNREALARENA
	vec3_t   down_o, down_v;
#endif
	trace_t  trace;
#ifndef UNREALARENA
	vec3_t   normal;
	vec3_t   step_v, step_vNormal;
#endif
	vec3_t   up, down;
	float    stepSize;
	bool stepped = false;

#ifndef UNREALARENA
	BG_GetClientNormal( pm->ps, normal );
#endif

	VectorCopy( pm->ps->origin, start_o );
	VectorCopy( pm->ps->velocity, start_v );

	if ( !PM_SlideMove( gravity ) )
	{
#ifdef UNREALARENA
		return stepped; // we got exactly where we wanted to go first try
#else
		VectorCopy( start_o, down );
		VectorMA( down, -STEPSIZE, normal, down );
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, 0 );

		//we can step down
		if ( trace.fraction > 0.01f && trace.fraction < 1.0f &&
		     !trace.allsolid && pml.groundPlane )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%d: step down\n", c_pmove );
			}

			stepped = true;
		}
#endif
	}
	else
	{
		VectorCopy( start_o, down );
#ifdef UNREALARENA
		down[ 2 ] -= STEPSIZE;
#else
		VectorMA( down, -STEPSIZE, normal, down );
#endif
		pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, 0 );
#ifdef UNREALARENA
		VectorSet( up, 0.0f, 0.0f, 1.0f );
#endif

		// never step up when you still have up velocity
#ifdef UNREALARENA
		if ( pm->ps->velocity[ 2 ] > 0.0f && ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, up ) < 0.7f ) )
#else
		if ( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
		     ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
#endif
		{
			return stepped;
		}

#ifndef UNREALARENA
		// never step up when flying upwards with the jetpack
		if ( pm->ps->velocity[ 2 ] > 0.0f && ( pm->ps->stats[ STAT_STATE2 ] & SS2_JETPACK_ACTIVE ) )
		{
			return stepped;
		}

		VectorCopy( pm->ps->origin, down_o );
		VectorCopy( pm->ps->velocity, down_v );
#endif

		VectorCopy( start_o, up );
#ifdef UNREALARENA
		up[ 2 ] += STEPSIZE;
#else
		VectorMA( up, STEPSIZE, normal, up );
#endif

		// test the player position if they were a stepheight higher
		pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, 0 );

		if ( trace.allsolid )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%i:bend can't step\n", c_pmove );
			}

			return stepped; // can't step up
		}

#ifdef UNREALARENA
		stepSize = trace.endpos[ 2 ] - start_o[ 2 ];

		// if the new position is falling then do nothing
		if ( PM_CheckFallingFromLedge( trace.endpos ) )
		{
			VectorCopy( start_o, pm->ps->origin );

			return stepped;
		}
#else
		VectorSubtract( trace.endpos, start_o, step_v );
		VectorCopy( step_v, step_vNormal );
		VectorNormalize( step_vNormal );

		stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
#endif
		// try slidemove from this position
		VectorCopy( trace.endpos, pm->ps->origin );
		VectorCopy( start_v, pm->ps->velocity );

#ifdef UNREALARENA
		PM_SlideMove( gravity, stepSize );
#else
		if ( PM_SlideMove( gravity ) == 0 )
		{
			if ( pm->debugLevel > 1 )
			{
				Log::Notice( "%d: step up\n", c_pmove );
			}

			stepped = true;
		}
#endif

		// push down the final amount
		VectorCopy( pm->ps->origin, down );
#ifdef UNREALARENA
		down[ 2 ] -= stepSize;
#else
		VectorMA( down, -stepSize, normal, down );
#endif
		pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum,
		           pm->tracemask, 0 );

		if ( !trace.allsolid )
		{
#ifdef UNREALARENA
			// if the new position is falling then do nothing
			if ( PM_CheckFallingFromLedge( trace.endpos ) )
			{
				VectorCopy( start_o, pm->ps->origin );

				return stepped;
			}
#endif
			VectorCopy( trace.endpos, pm->ps->origin );
		}

		if ( trace.fraction < 1.0f )
		{
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity );
		}
	}

#ifdef UNREALARENA
	if ( !predictive )
	{
		stepped = true;

		// use the step move
		float	delta;

		delta = pm->ps->origin[ 2 ] - start_o[ 2 ];

		if ( delta > 2.0f )
		{
			if ( delta < 7.0f )
			{
				PM_AddEvent( EV_STEP_4 );
			}
			else if ( delta < 11.0f )
			{
				PM_AddEvent( EV_STEP_8 );
			}
			else if ( delta < 15.0f )
			{
				PM_AddEvent( EV_STEP_12 );
			}
			else
			{
				PM_AddEvent( EV_STEP_16 );
			}
		}

		if ( pm->debugLevel > 1 )
		{
			Log::Notice( "%i:stepped\n", c_pmove );
		}
	}
#else
	if ( !predictive && stepped )
	{
		PM_StepEvent( start_o, pm->ps->origin, normal );
	}
#endif

	return stepped;
}