Пример #1
0
//copy of PM_CheckLadder in bg_pmove.c
bool BotOnLadder( gentity_t *self )
{
	vec3_t forward, end;
	vec3_t mins, maxs;
	trace_t trace;

	if ( !BG_ClassHasAbility( ( class_t ) self->client->ps.stats[ STAT_CLASS ], SCA_CANUSELADDERS ) )
	{
		return false;
	}

	AngleVectors( self->client->ps.viewangles, forward, nullptr, nullptr );

	forward[ 2 ] = 0.0f;
	BG_ClassBoundingBox( ( class_t ) self->client->ps.stats[ STAT_CLASS ], mins, maxs, nullptr, nullptr, nullptr );
	VectorMA( self->s.origin, 1.0f, forward, end );

	trap_Trace( &trace, self->s.origin, mins, maxs, end, self->s.number, MASK_PLAYERSOLID, 0 );

	if ( trace.fraction < 1.0f && trace.surfaceFlags & SURF_LADDER )
	{
		return true;
	}
	else
	{
		return false;
	}
}
Пример #2
0
/*
==============
CG_CalculateWeaponPosition
==============
*/
static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles )
{
  float scale;
  int   delta;
  float fracsin;
  float bob;

  VectorCopy( cg.refdef.vieworg, origin );
  VectorCopy( cg.refdefViewAngles, angles );

  // on odd legs, invert some angles
  if( cg.bobcycle & 1 )
    scale = -cg.xyspeed;
  else
    scale = cg.xyspeed;

  // gun angles from bobbing
  //TA: bob amount is class dependant
  bob = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );

  if( bob != 0 )
  {
    angles[ ROLL ] += scale * cg.bobfracsin * 0.005;
    angles[ YAW ] += scale * cg.bobfracsin * 0.01;
    angles[ PITCH ] += cg.xyspeed * cg.bobfracsin * 0.005;
  }

  // drop the weapon when landing
  if( !BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_NOWEAPONDRIFT ) )
  {
    delta = cg.time - cg.landTime;
    if( delta < LAND_DEFLECT_TIME )
      origin[ 2 ] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
    else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME )
      origin[ 2 ] += cg.landChange*0.25 *
        ( LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta ) / LAND_RETURN_TIME;

    // idle drift
    scale = cg.xyspeed + 40;
    fracsin = sin( cg.time * 0.001 );
    angles[ ROLL ] += scale * fracsin * 0.01;
    angles[ YAW ] += scale * fracsin * 0.01;
    angles[ PITCH ] += scale * fracsin * 0.01;
  }
}
Пример #3
0
static int CG_CalcFov( void )
{
  float     y;
  float     phase;
  float     v;
  int       contents;
  float     fov_x, fov_y;
  float     zoomFov;
  float     f;
  int       inwater;
  int       attribFov;
  usercmd_t cmd;
  usercmd_t oldcmd;
  int       cmdNum;

  cmdNum = trap_GetCurrentCmdNumber( );
  trap_GetUserCmd( cmdNum, &cmd );
  trap_GetUserCmd( cmdNum - 1, &oldcmd );

  // switch follow modes if necessary: cycle between free -> follow -> third-person follow
  if( cmd.buttons & BUTTON_USE_HOLDABLE && !( oldcmd.buttons & BUTTON_USE_HOLDABLE ) )
  {
    if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) 
    {
      if( !cg.chaseFollow )
        cg.chaseFollow = qtrue;
      else
      {
        cg.chaseFollow = qfalse;
        trap_SendClientCommand( "follow\n" );
      }
    }
    else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
      trap_SendClientCommand( "follow\n" );
  }

  if( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
      ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) || 
      ( cg.renderingThirdPerson ) )
  {
    // if in intermission or third person, use a fixed value
    fov_y = BASE_FOV_Y;
  }
  else
  {
    // don't lock the fov globally - we need to be able to change it
    attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov * 0.75f;
    fov_y = attribFov;

    if ( fov_y < 1.0f )
      fov_y = 1.0f;
    else if ( fov_y > MAX_FOV_Y )
      fov_y = MAX_FOV_Y;

    if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
        BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
    {
      float fraction = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;

      fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
    }

    // account for zooms
    zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;
    if ( zoomFov < 1.0f )
      zoomFov = 1.0f;
    else if ( zoomFov > attribFov )
      zoomFov = attribFov;

    // only do all the zoom stuff if the client CAN zoom
    // FIXME: zoom control is currently hard coded to BUTTON_ATTACK2
    if( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
    {
      if ( cg.zoomed )
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f > 1.0f )
          fov_y = zoomFov;
        else
          fov_y = fov_y + f * ( zoomFov - fov_y );

        // BUTTON_ATTACK2 isn't held so unzoom next time
        if( !( cmd.buttons & BUTTON_ATTACK2 ) )
        {
          cg.zoomed   = qfalse;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
      else
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f <= 1.0f )
          fov_y = zoomFov + f * ( fov_y - zoomFov );

        // BUTTON_ATTACK2 is held so zoom next time
        if( cmd.buttons & BUTTON_ATTACK2 )
        {
          cg.zoomed   = qtrue;
          cg.zoomTime = MIN( cg.time, 
              cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
        }
      }
    }
  }

  y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
  fov_x = atan2( cg.refdef.width, y );
  fov_x = 2.0f * RAD2DEG( fov_x );

  // warp if underwater
  contents = CG_PointContents( cg.refdef.vieworg, -1 );

  if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
  {
    phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
    v = WAVE_AMPLITUDE * sin( phase );
    fov_x += v;
    fov_y -= v;
    inwater = qtrue;
  }
  else
    inwater = qfalse;

  if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) &&
      ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) &&
      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    float scale = 1.0f - (float)( cg.time - cg.poisonedTime ) /
                  BG_PlayerPoisonCloudTime( &cg.predictedPlayerState );
      
    phase = ( cg.time - cg.poisonedTime ) / 1000.0f * PCLOUD_ZOOM_FREQUENCY * M_PI * 2.0f;
    v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ) * scale;
    fov_x += v;
    fov_y += v;
  }


  // set it
  cg.refdef.fov_x = fov_x;
  cg.refdef.fov_y = fov_y;

  if( !cg.zoomed )
    cg.zoomSensitivity = 1.0f;
  else
    cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;

  return inwater;
}
Пример #4
0
/*
===============
CG_CalcViewValues

Sets cg.refdef view values
===============
*/
static int CG_CalcViewValues( void )
{
  playerState_t *ps;

  memset( &cg.refdef, 0, sizeof( cg.refdef ) );

  // calculate size of 3D view
  CG_CalcVrect( );

  ps = &cg.predictedPlayerState;

  // intermission view
  if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_FREEZE ||
      ps->pm_type == PM_SPECTATOR )
  {
    VectorCopy( ps->origin, cg.refdef.vieworg );
    VectorCopy( ps->viewangles, cg.refdefViewAngles );
    AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

    return CG_CalcFov( );
  }

  cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
  cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
  cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] +
    ps->velocity[ 1 ] * ps->velocity[ 1 ] );

  // the bob velocity should't get too fast to avoid jerking
  if( cg.xyspeed > 300.0f )
    cg.xyspeed = 300.0f;

  VectorCopy( ps->origin, cg.refdef.vieworg );

  if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) )
    CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles );
  else if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
    CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles );
  else
    VectorCopy( ps->viewangles, cg.refdefViewAngles );

  //clumsy logic, but it needs to be this way round because the CS propogation
  //delay screws things up otherwise
  if( !BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
  {
    if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
      VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f );
  }

  // add error decay
  if( cg_errorDecay.value > 0 )
  {
    int   t;
    float f;

    t = cg.time - cg.predictedErrorTime;
    f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;

    if( f > 0 && f < 1 )
      VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
    else
      cg.predictedErrorTime = 0;
  }

  //shut off the poison cloud effect if it's still on the go
  if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
  {
    if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) )
      CG_DestroyParticleSystem( &cg.poisonCloudPS );
  }
  else
    cg.wasDeadLastFrame = qfalse;

  if( cg.renderingThirdPerson )
  {
    // back away from character
    CG_OffsetThirdPersonView( );
  }
  else
  {
    // offset for local bobbing and kicks
    CG_OffsetFirstPersonView( );
  }

  // position eye reletive to origin
  AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

  if( cg.hyperspace )
    cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;

  //draw the surface normal looking at
  if( cg_drawSurfNormal.integer )
    CG_DrawSurfNormal( );

  // field of view
  return CG_CalcFov( );
}
Пример #5
0
/*
==============
CG_EntityEvent

An entity has an event value
also called by CG_CheckPlayerstateEvents
==============
*/
void CG_EntityEvent( centity_t *cent, vec3_t position )
{
    entityState_t *es;
    int           event;
    vec3_t        dir;
    const char    *s;
    int           clientNum;
    clientInfo_t  *ci;
    int           steptime;

    if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
    {
        steptime = 200;
    }
    else
    {
        steptime = BG_Class( cg.snap->ps.stats[ STAT_CLASS ] )->steptime;
    }

    es = &cent->currentState;
    event = es->event & ~EV_EVENT_BITS;

    if ( cg_debugEvents.integer )
    {
        CG_Printf( "ent:%3i  event:%3i %s\n", es->number, event,
                   BG_EventName( event ) );
    }

    if ( !event )
    {
        return;
    }

    clientNum = es->clientNum;

    if ( clientNum < 0 || clientNum >= MAX_CLIENTS )
    {
        clientNum = 0;
    }

    ci = &cgs.clientinfo[ clientNum ];

    switch ( event )
    {
    case EV_FOOTSTEP:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            if ( ci->footsteps == FOOTSTEP_CUSTOM )
            {
                trap_S_StartSound( NULL, es->number, CHAN_BODY,
                                   ci->customFootsteps[ rand() & 3 ] );
            }
            else
            {
                trap_S_StartSound( NULL, es->number, CHAN_BODY,
                                   cgs.media.footsteps[ ci->footsteps ][ rand() & 3 ] );
            }
        }

        break;

    case EV_FOOTSTEP_METAL:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            if ( ci->footsteps == FOOTSTEP_CUSTOM )
            {
                trap_S_StartSound( NULL, es->number, CHAN_BODY,
                                   ci->customMetalFootsteps[ rand() & 3 ] );
            }
            else
            {
                trap_S_StartSound( NULL, es->number, CHAN_BODY,
                                   cgs.media.footsteps[ FOOTSTEP_METAL ][ rand() & 3 ] );
            }
        }

        break;

    case EV_FOOTSTEP_SQUELCH:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            trap_S_StartSound( NULL, es->number, CHAN_BODY,
                               cgs.media.footsteps[ FOOTSTEP_FLESH ][ rand() & 3 ] );
        }

        break;

    case EV_FOOTSPLASH:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            trap_S_StartSound( NULL, es->number, CHAN_BODY,
                               cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] );
        }

        break;

    case EV_FOOTWADE:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            trap_S_StartSound( NULL, es->number, CHAN_BODY,
                               cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] );
        }

        break;

    case EV_SWIM:
        if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
        {
            trap_S_StartSound( NULL, es->number, CHAN_BODY,
                               cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] );
        }

        break;

    case EV_FALL_SHORT:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound );

        if ( clientNum == cg.predictedPlayerState.clientNum )
        {
            // smooth landing z changes
            cg.landChange = -8;
            cg.landTime = cg.time;
        }

        break;

    case EV_FALL_MEDIUM:
        // use a general pain sound
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );

        if ( clientNum == cg.predictedPlayerState.clientNum )
        {
            // smooth landing z changes
            cg.landChange = -16;
            cg.landTime = cg.time;
        }

        break;

    case EV_FALL_FAR:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
        cent->pe.painTime = cg.time; // don't play a pain sound right after this

        if ( clientNum == cg.predictedPlayerState.clientNum )
        {
            // smooth landing z changes
            cg.landChange = -24;
            cg.landTime = cg.time;
        }

        break;

    case EV_FALLING:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*falling1.wav" ) );
        break;

    case EV_STEP_4:
    case EV_STEP_8:
    case EV_STEP_12:
    case EV_STEP_16: // smooth out step up transitions
    case EV_STEPDN_4:
    case EV_STEPDN_8:
    case EV_STEPDN_12:
    case EV_STEPDN_16: // smooth out step down transitions
    {
        float oldStep;
        int   delta;
        int   step;

        if ( clientNum != cg.predictedPlayerState.clientNum )
        {
            break;
        }

        // if we are interpolating, we don't need to smooth steps
        if ( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) ||
                cg_nopredict.integer || cg_synchronousClients.integer )
        {
            break;
        }

        // check for stepping up before a previous step is completed
        delta = cg.time - cg.stepTime;

        if ( delta < steptime )
        {
            oldStep = cg.stepChange * ( steptime - delta ) / steptime;
        }
        else
        {
            oldStep = 0;
        }

        // add this amount
        if ( event >= EV_STEPDN_4 )
        {
            step = 4 * ( event - EV_STEPDN_4 + 1 );
            cg.stepChange = oldStep - step;
        }
        else
        {
            step = 4 * ( event - EV_STEP_4 + 1 );
            cg.stepChange = oldStep + step;
        }

        if ( cg.stepChange > MAX_STEP_CHANGE )
        {
            cg.stepChange = MAX_STEP_CHANGE;
        }
        else if ( cg.stepChange < -MAX_STEP_CHANGE )
        {
            cg.stepChange = -MAX_STEP_CHANGE;
        }

        cg.stepTime = cg.time;
        break;
    }

    case EV_JUMP:
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );

        if ( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
        {
            vec3_t surfNormal, refNormal = { 0.0f, 0.0f, 1.0f };
            vec3_t rotAxis;

            if ( clientNum != cg.predictedPlayerState.clientNum )
            {
                break;
            }

            //set surfNormal
            VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal );

            //if we are moving from one surface to another smooth the transition
            if ( !VectorCompare( surfNormal, cg.lastNormal ) && surfNormal[ 2 ] != 1.0f )
            {
                CrossProduct( refNormal, surfNormal, rotAxis );
                VectorNormalize( rotAxis );

                //add the op
                CG_addSmoothOp( rotAxis, 15.0f, 1.0f );
            }

            //copy the current normal to the lastNormal
            VectorCopy( surfNormal, cg.lastNormal );
        }

        break;

    case EV_LEV1_GRAB:
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab );
        break;

    case EV_LEV4_TRAMPLE_PREPARE:
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare );
        break;

    case EV_LEV4_TRAMPLE_START:
        //FIXME: stop cgs.media.alienL4ChargePrepare playing here
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart );
        break;

    case EV_TAUNT:
        if ( !cg_noTaunt.integer )
        {
            trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
        }

        break;

    case EV_WATER_TOUCH:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
        break;

    case EV_WATER_LEAVE:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
        break;

    case EV_WATER_UNDER:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
        break;

    case EV_WATER_CLEAR:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
        break;

    case EV_JETPACK_ENABLE:
        // TODO: Trigger jetpack enable animation
        break;

    case EV_JETPACK_DISABLE:
        // TODO: Trigger jetpack disable animation
        break;

    case EV_JETPACK_START:
        // TODO: Start jetpack gfx/sfx
        break;

    case EV_JETPACK_STOP:
        // TODO: Stop jetpack gfx/sfx
        break;

    case EV_NOAMMO:
        trap_S_StartSound( NULL, es->number, CHAN_WEAPON, cgs.media.weaponEmptyClick );
        break;

    case EV_CHANGE_WEAPON:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
        break;

    case EV_FIRE_WEAPON:
        CG_HandleFireWeapon( cent, WPM_PRIMARY );
        break;

    case EV_FIRE_WEAPON2:
        CG_HandleFireWeapon( cent, WPM_SECONDARY );
        break;

    case EV_FIRE_WEAPON3:
        CG_HandleFireWeapon( cent, WPM_TERTIARY );
        break;

    case EV_WEAPON_RELOAD:
        if ( cg_weapons[ es->eventParm ].wim[ WPM_PRIMARY ].reloadSound )
        {
            trap_S_StartSound( NULL, es->number, CHAN_WEAPON, cg_weapons[ es->eventParm ].wim[ WPM_PRIMARY ].reloadSound );
        }
        break;

    case EV_PLAYER_TELEPORT_IN:
        //deprecated
        break;

    case EV_PLAYER_TELEPORT_OUT:
        CG_PlayerDisconnect( position );
        break;

    case EV_BUILD_CONSTRUCT:
        break;

    case EV_BUILD_DESTROY:
        break;

    case EV_AMMO_REFILL:
    case EV_CLIPS_REFILL:
    case EV_FUEL_REFILL:
        // TODO: Add different sounds for EV_AMMO_REFILL, EV_CLIPS_REFILL, EV_FUEL_REFILL
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound );
        break;

    case EV_GRENADE_BOUNCE:
        if ( rand() & 1 )
        {
            trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound1 );
        }
        else
        {
            trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound2 );
        }
        break;

    case EV_WEAPON_HIT_ENTITY:
        CG_HandleWeaponHitEntity( es, position );
        break;

    case EV_WEAPON_HIT_ENVIRONMENT:
        CG_HandleWeaponHitWall( es, position );
        break;

    case EV_MISSILE_HIT_ENTITY:
        CG_HandleMissileHitEntity( es, position );
        break;

    // currently there is no support for metal sounds
    case EV_MISSILE_HIT_ENVIRONMENT:
    case EV_MISSILE_HIT_METAL:
        CG_HandleMissileHitWall( es, position );
        break;

    case EV_SHOTGUN:
        CG_HandleFireShotgun( es );
        break;

    case EV_HUMAN_BUILDABLE_DYING:
        CG_HumanBuildableDying( (buildable_t) es->modelindex, position );
        break;

    case EV_HUMAN_BUILDABLE_EXPLOSION:
        ByteToDir( es->eventParm, dir );
        CG_HumanBuildableExplosion( (buildable_t) es->modelindex, position, dir );
        break;

    case EV_ALIEN_BUILDABLE_EXPLOSION:
        ByteToDir( es->eventParm, dir );
        CG_AlienBuildableExplosion( position, dir );
        break;

    case EV_TESLATRAIL:
        cent->currentState.weapon = WP_TESLAGEN;
        {
            centity_t *source = &cg_entities[ es->generic1 ];
            centity_t *target = &cg_entities[ es->clientNum ];
            vec3_t    sourceOffset = { 0.0f, 0.0f, 28.0f };

            if ( !CG_IsTrailSystemValid( &source->muzzleTS ) )
            {
                source->muzzleTS = CG_SpawnNewTrailSystem( cgs.media.teslaZapTS );

                if ( CG_IsTrailSystemValid( &source->muzzleTS ) )
                {
                    CG_SetAttachmentCent( &source->muzzleTS->frontAttachment, source );
                    CG_SetAttachmentCent( &source->muzzleTS->backAttachment, target );
                    CG_AttachToCent( &source->muzzleTS->frontAttachment );
                    CG_AttachToCent( &source->muzzleTS->backAttachment );
                    CG_SetAttachmentOffset( &source->muzzleTS->frontAttachment, sourceOffset );

                    source->muzzleTSDeathTime = cg.time + cg_teslaTrailTime.integer;
                }
            }
        }
        break;

    case EV_GENERAL_SOUND:
        if ( cgs.gameSounds[ es->eventParm ] )
        {
            trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
        }
        else
        {
            s = CG_ConfigString( CS_SOUNDS + es->eventParm );
            trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
        }

        break;

    case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
        if ( cgs.gameSounds[ es->eventParm ] )
        {
            trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
        }
        else
        {
            s = CG_ConfigString( CS_SOUNDS + es->eventParm );
            trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
        }

        break;

    case EV_PAIN:
        // local player sounds are triggered in CG_CheckLocalSounds,
        // so ignore events on the player
        if ( cent->currentState.number != cg.snap->ps.clientNum )
        {
            CG_PainEvent( cent, es->eventParm );
        }

        break;

    case EV_DEATH1:
    case EV_DEATH2:
    case EV_DEATH3:
        trap_S_StartSound( NULL, es->number, CHAN_VOICE,
                           CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) );
        break;

    case EV_OBITUARY:
        CG_Obituary( es );
        break;

    case EV_GIB_PLAYER:
        // no gibbing
        break;

    case EV_STOPLOOPINGSOUND:
        trap_S_StopLoopingSound( es->number );
        es->loopSound = 0;
        break;

    case EV_DEBUG_LINE:
        CG_Beam( cent );
        break;

    case EV_BUILD_DELAY:
        if ( clientNum == cg.predictedPlayerState.clientNum )
        {
            trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND );
            cg.lastBuildAttempt = cg.time;
        }

        break;

    case EV_BUILD_REPAIR:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound );
        break;

    case EV_BUILD_REPAIRED:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound );
        break;

    case EV_OVERMIND_ATTACK_1:
    case EV_OVERMIND_ATTACK_2:
        if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS )
        {
            trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER );
            CG_CenterPrint( va( "^%c%s", "31"[ event - EV_OVERMIND_ATTACK_1 ], _( "The Overmind is under attack!" ) ), 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_OVERMIND_DYING:
        if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS )
        {
            trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER );
            CG_CenterPrint( _( "^1The Overmind is dying!" ), 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_REACTOR_ATTACK_1:
    case EV_REACTOR_ATTACK_2:
        if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS )
        {
            CG_CenterPrint( va( "^%c%s", "31"[ event - EV_REACTOR_ATTACK_1 ], _( "The reactor is under attack!" ) ), 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_REACTOR_DYING:
        if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS )
        {
            CG_CenterPrint( _( "^1The reactor is about to explode!" ), 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_WARN_ATTACK:
        // if eventParm is non-zero, this is for humans and there's a nearby reactor or repeater, otherwise it's for aliens
        if ( es->eventParm >= MAX_CLIENTS && es->eventParm < MAX_GENTITIES )
        {
            const char *location;
            qboolean    base = cg_entities[ es->eventParm ].currentState.modelindex == BA_H_REACTOR;
            centity_t  *locent = CG_GetLocation( cg_entities[ es->eventParm ].currentState.origin );

            CG_CenterPrint( base ? _( "Our base is under attack!" ) : _( "A forward base is under attack!" ), 200, GIANTCHAR_WIDTH * 4 );

            if ( locent )
            {
                location = CG_ConfigString( CS_LOCATIONS + locent->currentState.generic1 );
            }
            else
            {
                location = CG_ConfigString( CS_LOCATIONS );
            }

            if ( location && *location )
            {
                Com_Printf( _( "%s Under attack – %s\n" ), base ? "[reactor]" : "[repeater]", location );
            }
            else
            {
                Com_Printf( _( "%s Under attack\n" ), base ? "[reactor]" : "[repeater]" );
            }
        }
        else // this is for aliens, and the overmind is in range
        {
            CG_CenterPrint( _( "Our base is under attack!" ), 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_MGTURRET_SPINUP:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.turretSpinupSound );
        break;

    case EV_OVERMIND_SPAWNS:
        if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS )
        {
            trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER );
            CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 );
        }

        break;

    case EV_ALIEN_EVOLVE:
        trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienEvolveSound );
        {
            particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienEvolvePS );

            if ( CG_IsParticleSystemValid( &ps ) )
            {
                CG_SetAttachmentCent( &ps->attachment, cent );
                CG_AttachToCent( &ps->attachment );
            }
        }

        if ( es->number == cg.clientNum )
        {
            CG_ResetPainBlend();
            cg.spawnTime = cg.time;
        }

        break;

    case EV_ALIEN_EVOLVE_FAILED:
        if ( clientNum == cg.predictedPlayerState.clientNum )
        {
            //FIXME: change to "negative" sound
            trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND );
            cg.lastEvolveAttempt = cg.time;
        }

        break;

    case EV_ALIEN_ACIDTUBE:
    {
        particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienAcidTubePS );

        if ( CG_IsParticleSystemValid( &ps ) )
        {
            CG_SetAttachmentCent( &ps->attachment, cent );
            ByteToDir( es->eventParm, dir );
            CG_SetParticleSystemNormal( ps, dir );
            CG_AttachToCent( &ps->attachment );
        }
    }
    break;

    case EV_MEDKIT_USED:
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound );
        break;

    case EV_PLAYER_RESPAWN:
        if ( es->number == cg.clientNum )
        {
            cg.spawnTime = cg.time;
        }

        break;

    case EV_LEV2_ZAP:
        CG_Level2Zap( es );
        break;

    case EV_HIT:
        cg.hitTime = cg.time;
        break;

    case EV_MOMENTUM:
        CG_Momentum( es );
        break;

    default:
        CG_Error( "Unknown event: %i", event );
    }
}
Пример #6
0
static int CG_CalcFov( void )
{
	float     y;
	float     phase;
	float     v;
	int       contents;
	float     fov_x, fov_y;
	float     zoomFov;
	float     f;
	int       inwater;
	int       attribFov;
	usercmd_t cmd;
	usercmd_t oldcmd;
	int       cmdNum;

	cmdNum = trap_GetCurrentCmdNumber();
	trap_GetUserCmd( cmdNum, &cmd );
	trap_GetUserCmd( cmdNum - 1, &oldcmd );

	// switch follow modes if necessary: cycle between free -> follow -> third-person follow
	if ( usercmdButtonPressed( cmd.buttons, BUTTON_USE_HOLDABLE ) && !usercmdButtonPressed( oldcmd.buttons, BUTTON_USE_HOLDABLE ) )
	{
		if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
		{
			if ( !cg.chaseFollow )
			{
				cg.chaseFollow = qtrue;
			}
			else
			{
				cg.chaseFollow = qfalse;
				trap_SendClientCommand( "follow\n" );
			}
		}
		else if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
		{
			trap_SendClientCommand( "follow\n" );
		}
	}

	if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
	     ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) ||
	     ( cg.renderingThirdPerson ) )
	{
		// if in intermission or third person, use a fixed value
		fov_y = BASE_FOV_Y;
	}
	else
	{
		// don't lock the fov globally - we need to be able to change it
		if ( ( attribFov = trap_Cvar_VariableIntegerValue( BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fovCvar ) ) )
		{
			if ( attribFov < 80 )
			{
				attribFov = 80;
			}
			else if ( attribFov >= 140 )
			{
				attribFov = 140;
			}
		}
		else
		{
			attribFov = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->fov;
		}
		attribFov *= 0.75;
		fov_y = attribFov;

		if ( fov_y < 1.0f )
		{
			fov_y = 1.0f;
		}
		else if ( fov_y > MAX_FOV_Y )
		{
			fov_y = MAX_FOV_Y;
		}

		if ( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
		     BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_FOVWARPS ) )
		{
			float fraction = ( float )( cg.time - cg.spawnTime ) / FOVWARPTIME;

			fov_y = MAX_FOV_WARP_Y - ( ( MAX_FOV_WARP_Y - fov_y ) * fraction );
		}

		// account for zooms
		zoomFov = BG_Weapon( cg.predictedPlayerState.weapon )->zoomFov * 0.75f;

		if ( zoomFov < 1.0f )
		{
			zoomFov = 1.0f;
		}
		else if ( zoomFov > attribFov )
		{
			zoomFov = attribFov;
		}

		// only do all the zoom stuff if the client CAN zoom
		// FIXME: zoom control is currently hard coded to WBUTTON_ATTACK2
		if ( BG_Weapon( cg.predictedPlayerState.weapon )->canZoom )
		{
			if ( cg.zoomed )
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f > 1.0f )
				{
					fov_y = zoomFov;
				}
				else
				{
					fov_y = fov_y + f * ( zoomFov - fov_y );
				}

				// WBUTTON_ATTACK2 isn't held so unzoom next time
				if ( !usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) || cg.snap->ps.weaponstate == WEAPON_RELOADING )
				{
					cg.zoomed = qfalse;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
			else
			{
				f = ( cg.time - cg.zoomTime ) / ( float ) ZOOM_TIME;

				if ( f < 1.0f )
				{
					fov_y = zoomFov + f * ( fov_y - zoomFov );
				}

				// WBUTTON_ATTACK2 is held so zoom next time
				if ( usercmdButtonPressed( cmd.buttons, BUTTON_ATTACK2 ) && cg.snap->ps.weaponstate != WEAPON_RELOADING )
				{
					cg.zoomed = qtrue;
					cg.zoomTime = MIN( cg.time,
					                   cg.time + cg.time - cg.zoomTime - ZOOM_TIME );
				}
			}
		}
		else if ( cg.zoomed )
		{
			cg.zoomed = qfalse;
		}
	}

	y = cg.refdef.height / tan( 0.5f * DEG2RAD( fov_y ) );
	fov_x = atan2( cg.refdef.width, y );
	fov_x = 2.0f * RAD2DEG( fov_x );

	// warp if underwater
	contents = CG_PointContents( cg.refdef.vieworg, -1 );

	if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
	{
		phase = cg.time / 1000.0f * WAVE_FREQUENCY * M_PI * 2.0f;
		v = WAVE_AMPLITUDE * sin( phase );
		fov_x += v;
		fov_y -= v;
		inwater = qtrue;
	}
	else
	{
		inwater = qfalse;
	}

	// set it
	cg.refdef.fov_x = fov_x;
	cg.refdef.fov_y = fov_y;

	if ( !cg.zoomed )
	{
		cg.zoomSensitivity = 1.0f;
	}
	else
	{
		cg.zoomSensitivity = cg.refdef.fov_y / 75.0f;
	}

	return inwater;
}
Пример #7
0
/*
===============
CG_CalcViewValues

Sets cg.refdef view values
===============
*/
static int CG_CalcViewValues( void )
{
	playerState_t *ps;

	memset( &cg.refdef, 0, sizeof( cg.refdef ) );

	// calculate size of 3D view
	CG_CalcVrect();

	ps = &cg.predictedPlayerState;

	CG_CalcColorGradingForPoint( ps->origin );
	CG_AddColorGradingEffects( ps );

	CG_AddReverbEffects( ps->origin );

	// intermission view
	if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_FREEZE ||
	     ps->pm_type == PM_SPECTATOR )
	{
		VectorCopy( ps->origin, cg.refdef.vieworg );
		VectorCopy( ps->viewangles, cg.refdefViewAngles );
		AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

		return CG_CalcFov();
	}

	cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
	cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
	cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] +
	                   ps->velocity[ 1 ] * ps->velocity[ 1 ] );

	// to avoid jerking, the bob velocity shouldn't be too high
	if ( cg.xyspeed > 300.0f )
	{
		cg.xyspeed = 300.0f;
	}

	VectorCopy( ps->origin, cg.refdef.vieworg );

	if ( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) )
	{
		CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles );
	}
	else if ( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
	{
		CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles );
	}
	else
	{
		VectorCopy( ps->viewangles, cg.refdefViewAngles );
	}

	//clumsy logic, but it needs to be this way around because the CS propagation
	//delay screws things up otherwise
	if ( !BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
	{
		if ( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
		{
			VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f );
		}
	}

	// add error decay
	if ( cg_errorDecay.value > 0 )
	{
		int   t;
		float f;

		t = cg.time - cg.predictedErrorTime;
		f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;

		if ( f > 0 && f < 1 )
		{
			VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
		}
		else
		{
			cg.predictedErrorTime = 0;
		}
	}

	//shut off the poison cloud effect if it's still on the go
	if ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 )
	{
		cg.wasDeadLastFrame = qfalse;
	}

	if ( cg.renderingThirdPerson )
	{
		// back away from character
		CG_OffsetThirdPersonView();
	}
	else
	{
		float speed;

		// offset for local bobbing and kicks
		CG_OffsetFirstPersonView();

		// Compute motion blur vector
		speed = VectorNormalize2( cg.snap->ps.velocity, cg.refdef.blurVec );

		speed = (speed - cg_motionblurMinSpeed.value);
		if( speed < 0.0f ) speed = 0.0f;

		VectorScale( cg.refdef.blurVec, speed * cg_motionblur.value,
			     cg.refdef.blurVec );

	}

	// position eye relative to origin
	AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

	if ( cg.hyperspace )
	{
		cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;
	}

	//draw the surface normal looking at
	if ( cg_drawSurfNormal.integer )
	{
		CG_DrawSurfNormal();
	}

	// field of view
	return CG_CalcFov();
}
Пример #8
0
/*
==============
CG_EntityEvent

An entity has an event value
also called by CG_CheckPlayerstateEvents
==============
*/
void CG_EntityEvent( centity_t *cent, vec3_t position )
{
  entityState_t *es;
  int           event;
  vec3_t        dir;
  const char    *s;
  int           clientNum;
  clientInfo_t  *ci;
  int           steptime;

  if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT )
    steptime = 200;
  else
    steptime = BG_Class( cg.snap->ps.stats[ STAT_CLASS ] )->steptime;

  es = &cent->currentState;
  event = es->event & ~EV_EVENT_BITS;

  if( cg_debugEvents.integer )
    CG_Printf( "ent:%3i  event:%3i %s\n", es->number, event,
               BG_EventName( event ) );

  if( !event )
    return;

  clientNum = es->clientNum;
  if( clientNum < 0 || clientNum >= MAX_CLIENTS )
    clientNum = 0;

  ci = &cgs.clientinfo[ clientNum ];

  switch( event )
  {
    //
    // movement generated events
    //
    case EV_FOOTSTEP:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        if( ci->footsteps == FOOTSTEP_CUSTOM )
          trap_S_StartSound( NULL, es->number, CHAN_BODY,
            ci->customFootsteps[ rand( ) & 3 ] );
        else
          trap_S_StartSound( NULL, es->number, CHAN_BODY,
            cgs.media.footsteps[ ci->footsteps ][ rand( ) & 3 ] );
      }
      break;

    case EV_FOOTSTEP_METAL:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        if( ci->footsteps == FOOTSTEP_CUSTOM )
          trap_S_StartSound( NULL, es->number, CHAN_BODY,
            ci->customMetalFootsteps[ rand( ) & 3 ] );
        else
          trap_S_StartSound( NULL, es->number, CHAN_BODY,
            cgs.media.footsteps[ FOOTSTEP_METAL ][ rand( ) & 3 ] );
      }
      break;

    case EV_FOOTSTEP_SQUELCH:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        trap_S_StartSound( NULL, es->number, CHAN_BODY,
          cgs.media.footsteps[ FOOTSTEP_FLESH ][ rand( ) & 3 ] );
      }
      break;

    case EV_FOOTSPLASH:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        trap_S_StartSound( NULL, es->number, CHAN_BODY,
          cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] );
      }
      break;

    case EV_FOOTWADE:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        trap_S_StartSound( NULL, es->number, CHAN_BODY,
          cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] );
      }
      break;

    case EV_SWIM:
      if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE )
      {
        trap_S_StartSound( NULL, es->number, CHAN_BODY,
          cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] );
      }
      break;


    case EV_FALL_SHORT:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound );

      if( clientNum == cg.predictedPlayerState.clientNum )
      {
        // smooth landing z changes
        cg.landChange = -8;
        cg.landTime = cg.time;
      }
      break;

    case EV_FALL_MEDIUM:
      // use normal pain sound
      trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );

      if( clientNum == cg.predictedPlayerState.clientNum )
      {
        // smooth landing z changes
        cg.landChange = -16;
        cg.landTime = cg.time;
      }
      break;

    case EV_FALL_FAR:
      trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
      cent->pe.painTime = cg.time;  // don't play a pain sound right after this

      if( clientNum == cg.predictedPlayerState.clientNum )
      {
        // smooth landing z changes
        cg.landChange = -24;
        cg.landTime = cg.time;
      }
      break;

    case EV_FALLING:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*falling1.wav" ) );
      break;

    case EV_STEP_4:
    case EV_STEP_8:
    case EV_STEP_12:
    case EV_STEP_16:    // smooth out step up transitions
    case EV_STEPDN_4:
    case EV_STEPDN_8:
    case EV_STEPDN_12:
    case EV_STEPDN_16:    // smooth out step down transitions
      {
        float  oldStep;
        int    delta;
        int    step;

        if( clientNum != cg.predictedPlayerState.clientNum )
          break;

        // if we are interpolating, we don't need to smooth steps
        if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) ||
            cg_nopredict.integer || cg_synchronousClients.integer )
          break;

        // check for stepping up before a previous step is completed
        delta = cg.time - cg.stepTime;

        if( delta < steptime )
          oldStep = cg.stepChange * ( steptime - delta ) / steptime;
        else
          oldStep = 0;

        // add this amount
        if( event >= EV_STEPDN_4 )
        {
          step = 4 * ( event - EV_STEPDN_4 + 1 );
          cg.stepChange = oldStep - step;
        }
        else
        {
          step = 4 * ( event - EV_STEP_4 + 1 );
          cg.stepChange = oldStep + step;
        }

        if( cg.stepChange > MAX_STEP_CHANGE )
          cg.stepChange = MAX_STEP_CHANGE;
        else if( cg.stepChange < -MAX_STEP_CHANGE )
          cg.stepChange = -MAX_STEP_CHANGE;

        cg.stepTime = cg.time;
        break;
      }

    case EV_JUMP:
      trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );

      if( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_WALLJUMPER ) )
      {
        vec3_t  surfNormal, refNormal = { 0.0f, 0.0f, 1.0f };
        vec3_t  rotAxis;

        if( clientNum != cg.predictedPlayerState.clientNum )
          break;

        //set surfNormal
        VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal );

        //if we are moving from one surface to another smooth the transition
        if( !VectorCompare( surfNormal, cg.lastNormal ) && surfNormal[ 2 ] != 1.0f )
        {
          CrossProduct( refNormal, surfNormal, rotAxis );
          VectorNormalize( rotAxis );

          //add the op
          CG_addSmoothOp( rotAxis, 15.0f, 1.0f );
        }

        //copy the current normal to the lastNormal
        VectorCopy( surfNormal, cg.lastNormal );
      }

      break;

    case EV_LEV1_GRAB:
      trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab );
      break;

    case EV_LEV4_TRAMPLE_PREPARE:
      trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare );
      break;

    case EV_LEV4_TRAMPLE_START:
      //FIXME: stop cgs.media.alienL4ChargePrepare playing here
      trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart );
      break;

    case EV_TAUNT:
      if( !cg_noTaunt.integer )
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
      break;

    case EV_WATER_TOUCH:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
      break;

    case EV_WATER_LEAVE:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
      break;

    case EV_WATER_UNDER:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
      break;

    case EV_WATER_CLEAR:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
      break;

    //
    // weapon events
    //
    case EV_NOAMMO:
      trap_S_StartSound( NULL, es->number, CHAN_WEAPON,
                         cgs.media.weaponEmptyClick );
      break;

    case EV_CHANGE_WEAPON:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
      break;

    case EV_FIRE_WEAPON:
      CG_FireWeapon( cent, WPM_PRIMARY );
      break;

    case EV_FIRE_WEAPON2:
      CG_FireWeapon( cent, WPM_SECONDARY );
      break;

    case EV_FIRE_WEAPON3:
      CG_FireWeapon( cent, WPM_TERTIARY );
      break;

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

    //
    // other events
    //
    case EV_PLAYER_TELEPORT_IN:
      //deprecated
      break;

    case EV_PLAYER_TELEPORT_OUT:
      CG_PlayerDisconnect( position );
      break;

    case EV_BUILD_CONSTRUCT:
      //do something useful here
      break;

    case EV_BUILD_DESTROY:
      //do something useful here
      break;

    case EV_RPTUSE_SOUND:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound );
      break;

    case EV_GRENADE_BOUNCE:
      if( rand( ) & 1 )
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound1 );
      else
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound2 );
      break;

    //ROTAXfun
    case EV_ACIDBOMB_BOUNCE:
      if( rand( ) & 1 )
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.acidBombBounceSound1 );
      else
        trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.acidBombBounceSound2 );
      break;

    //
    // missile impacts
    //
    case EV_MISSILE_HIT:
      ByteToDir( es->eventParm, dir );
      CG_MissileHitEntity( es->weapon, es->generic1, position, dir, es->otherEntityNum, es->torsoAnim );
      break;

    case EV_MISSILE_MISS:
      ByteToDir( es->eventParm, dir );
      CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT, es->torsoAnim );
      break;

    case EV_MISSILE_MISS_METAL:
      ByteToDir( es->eventParm, dir );
      CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL, es->torsoAnim );
      break;

    case EV_HUMAN_BUILDABLE_EXPLOSION:
      ByteToDir( es->eventParm, dir );
      CG_HumanBuildableExplosion( position, dir, es->modelindex );//ROTAXfun
      break;

    case EV_ALIEN_BUILDABLE_EXPLOSION:
      ByteToDir( es->eventParm, dir );
      CG_AlienBuildableExplosion( position, dir, es->modelindex );//ROTAXfun
      
      if ( es->modelindex == BA_A_BUSH )
        CG_AlienBushExplosion( position, dir );
      break;

    case EV_TESLATRAIL:
      cent->currentState.weapon = WP_TESLAGEN;
      {
        centity_t *source = &cg_entities[ es->generic1 ];
        centity_t *target = &cg_entities[ es->clientNum ];
        vec3_t    sourceOffset = { 0.0f, 0.0f, 28.0f };

        if( !CG_IsTrailSystemValid( &source->muzzleTS ) )
        {
          source->muzzleTS = CG_SpawnNewTrailSystem( cgs.media.teslaZapTS );

          if( CG_IsTrailSystemValid( &source->muzzleTS ) )
          {
            CG_SetAttachmentCent( &source->muzzleTS->frontAttachment, source );
            CG_SetAttachmentCent( &source->muzzleTS->backAttachment, target );
            CG_AttachToCent( &source->muzzleTS->frontAttachment );
            CG_AttachToCent( &source->muzzleTS->backAttachment );
            CG_SetAttachmentOffset( &source->muzzleTS->frontAttachment, sourceOffset );

            source->muzzleTSDeathTime = cg.time + cg_teslaTrailTime.integer;
          }
        }
      }
      break;

    case EV_BULLET_HIT_WALL:
      ByteToDir( es->eventParm, dir );
      CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
      break;

    case EV_BULLET_HIT_FLESH:
      CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
      break;

    case EV_SHOTGUN:
      CG_ShotgunFire( es );
      break;

    case EV_GENERAL_SOUND:
      if( cgs.gameSounds[ es->eventParm ] )
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
      else
      {
        s = CG_ConfigString( CS_SOUNDS + es->eventParm );
        trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
      }
      break;

    case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
      if( cgs.gameSounds[ es->eventParm ] )
        trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
      else
      {
        s = CG_ConfigString( CS_SOUNDS + es->eventParm );
        trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
      }
      break;

    case EV_PAIN:
      // local player sounds are triggered in CG_CheckLocalSounds,
      // so ignore events on the player
      if( cent->currentState.number != cg.snap->ps.clientNum )
        CG_PainEvent( cent, es->eventParm );
      break;

    case EV_DEATH1:
    case EV_DEATH2:
    case EV_DEATH3:
      trap_S_StartSound( NULL, es->number, CHAN_VOICE,
          CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) );
      break;

    case EV_OBITUARY:
      CG_Obituary( es );
      break;

    case EV_GIB_PLAYER:
      // no gibbing
      break;

    case EV_STOPLOOPINGSOUND:
      trap_S_StopLoopingSound( es->number );
      es->loopSound = 0;
      break;

    case EV_DEBUG_LINE:
      CG_Beam( cent );
      break;

    case EV_BUILD_DELAY:
      if( clientNum == cg.predictedPlayerState.clientNum )
      {
        trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND );
        cg.lastBuildAttempt = cg.time;
      }
      break;

    case EV_BUILD_REPAIR:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound );
      break;

    case EV_BUILD_REPAIRED:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound );
      break;

    case EV_OVERMIND_ATTACK:
      if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
      {
        trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER );
        CG_CenterPrint( "The Overmind is under attack!", 200, GIANTCHAR_WIDTH * 4 );
      }
      break;

    case EV_OVERMIND_DYING:
      if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
      {
        trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER );
        CG_CenterPrint( "The Overmind is dying!", 200, GIANTCHAR_WIDTH * 4 );
      }
      break;

    case EV_DCC_ATTACK:
      if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS )
      {
        //trap_S_StartLocalSound( cgs.media.humanDCCAttack, CHAN_ANNOUNCER );
        CG_CenterPrint( "Our base is under attack!", 200, GIANTCHAR_WIDTH * 4 );
      }
      break;

    case EV_MGTURRET_SPINUP:
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.turretSpinupSound );
      break;

    case EV_OVERMIND_SPAWNS:
      if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS )
      {
        trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER );
        CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 );
      }
      break;

    case EV_ALIEN_EVOLVE:
      trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienEvolveSound );
      {
        particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienEvolvePS );

        if( CG_IsParticleSystemValid( &ps ) )
        {
          CG_SetAttachmentCent( &ps->attachment, cent );
          CG_AttachToCent( &ps->attachment );
        }
      }

      if( es->number == cg.clientNum )
      {
        CG_ResetPainBlend( );
        cg.spawnTime = cg.time;
      }
      break;

    case EV_ALIEN_EVOLVE_FAILED:
      if( clientNum == cg.predictedPlayerState.clientNum )
      {
        //FIXME: change to "negative" sound
        trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND );
        cg.lastEvolveAttempt = cg.time;
      }
      break;

    case EV_ALIEN_ACIDTUBE:
      {
        particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienAcidTubePS );

        if( CG_IsParticleSystemValid( &ps ) )
        {
          CG_SetAttachmentCent( &ps->attachment, cent );
          ByteToDir( es->eventParm, dir );
          CG_SetParticleSystemNormal( ps, dir );
          CG_AttachToCent( &ps->attachment );
        }
      }
      break;

    case EV_MEDKIT_USED:
      // the parameter is the healer's entity number
      {
        const int   healerNum = es->eventParm;
        const char  *configstring;
        const char  *name;

        if( healerNum != clientNum )
        {
          if( healerNum == cg.clientNum )
          {
            configstring = CG_ConfigString( clientNum + CS_PLAYERS );
            // isolate the player's name
            name = Info_ValueForKey( configstring, "n" );

            CG_Printf( S_COLOR_CYAN "You bandaged " S_COLOR_WHITE "%s" S_COLOR_CYAN "'s wounds.\n", name );
          } else if( clientNum == cg.clientNum )
          {
            configstring = CG_ConfigString( healerNum + CS_PLAYERS );
            // isolate the player's name
            name = Info_ValueForKey( configstring, "n" );

            CG_Printf( S_COLOR_WHITE "%s" S_COLOR_CYAN " bandaged your wounds.\n", name );
          }
        }
      }
      trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound );
      break;

    case EV_PLAYER_RESPAWN:
      if( es->number == cg.clientNum )
        cg.spawnTime = cg.time;
      break;

    case EV_LEV2_ZAP:
      CG_Level2Zap( es );
      break;

    default:
      CG_Error( "Unknown event: %i", event );
      break;
  }
}
Пример #9
0
static int CG_CalcFov( void )
{
  float x;
  float phase;
  float v;
  int   contents;
  float fov_x, fov_y;
  float zoomFov;
  float f;
  int   inwater;
  int   attribFov;

  if( cg.predictedPlayerState.pm_type == PM_INTERMISSION )
  {
    // if in intermission, use a fixed value
    fov_x = 90;
  }
  else
  {
    //TA: don't lock the fov globally - we need to be able to change it
    attribFov = BG_FindFovForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );
    fov_x = attribFov;

    if ( fov_x < 1 )
      fov_x = 1;
    else if ( fov_x > 160 )
      fov_x = 160;

    if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
        BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_FOVWARPS ) )
    {
      float temp, temp2;

      temp = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;
      temp2 = ( 170 - fov_x ) * temp;

      //Com_Printf( "%f %f\n", temp*100, temp2*100 );

      fov_x = 170 - temp2;
    }

    // account for zooms
    //zoomFov = BG_FindZoomFovForWeapon( cg.predictedPlayerState.weapon );
    zoomFov = cg_zoomFov.value;
    if ( zoomFov < 1 )
      zoomFov = 1;
    else if ( zoomFov > attribFov )
      zoomFov = attribFov;

    //TA: only do all the zoom stuff if the client CAN zoom
    if ( cg.zoomed )
    {
      f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

      if ( f > 1.0 )
        fov_x = zoomFov;
      else
        fov_x = fov_x + f * ( zoomFov - fov_x );
    }
    else
    {
      f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

      if ( f > 1.0 )
        fov_x = fov_x;
      else
        fov_x = zoomFov + f * ( fov_x - zoomFov );
    }
  }

  x = cg.refdef.width / tan( fov_x / 360 * M_PI );
  fov_y = atan2( cg.refdef.height, x );
  fov_y = fov_y * 360 / M_PI;

  // warp if underwater
  contents = CG_PointContents( cg.refdef.vieworg, -1 );

  if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
  {
    phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
    v = WAVE_AMPLITUDE * sin( phase );
    fov_x += v;
    fov_y -= v;
    inwater = qtrue;
  }
  else
    inwater = qfalse;

  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2;
    v = PCLOUD_ZOOM_AMPLITUDE * sin( phase );
    v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
    fov_x += v;
    fov_y += v;
  }


  // set it
  cg.refdef.fov_x = fov_x;
  cg.refdef.fov_y = fov_y;

  if( !cg.zoomed )
    cg.zoomSensitivity = 1;
  else
    cg.zoomSensitivity = cg.refdef.fov_y / 75.0;

  return inwater;
}
Пример #10
0
//@Jkent: Is there a way to get access to R_customheight/width and/or r_height/width? (Get the newer height-dependant FOV rather than width-dependant as 1.1 widescreens actually have smaller FOVs)
static int CG_CalcFov( void )
{
  float     x;
  float     phase;
  float     v;
  int       contents;
  float     fov_x, fov_y;
  float     zoomFov;
  float     f;
  int       inwater;
  int       attribFov;
  usercmd_t cmd;
  int       cmdNum;

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

  if( cg.predictedPlayerState.pm_type == PM_INTERMISSION ||
      ( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) )
  {
    // if in intermission, use a fixed value
    fov_x = 90;
  }
  else
  {
    // don't lock the fov globally - we need to be able to change it
    attribFov = BG_FindFovForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );
    fov_x = attribFov;

    if ( fov_x < 1 )
      fov_x = 1;
    else if ( fov_x > 160 )
      fov_x = 160;

    if( cg.spawnTime > ( cg.time - FOVWARPTIME ) &&
        BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_FOVWARPS ) )
    {
      float temp, temp2;

      temp = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME;
      temp2 = ( 170 - fov_x ) * temp;

      //Com_Printf( "%f %f\n", temp*100, temp2*100 );

      fov_x = 170 - temp2;
    }

    // account for zooms
    zoomFov = BG_FindZoomFovForWeapon( cg.predictedPlayerState.weapon );
    if ( zoomFov < 1 )
      zoomFov = 1;
    else if ( zoomFov > attribFov )
      zoomFov = attribFov;

    // only do all the zoom stuff if the client CAN zoom
    // FIXME: zoom control is currently hard coded to BUTTON_ATTACK2
    if( BG_WeaponCanZoom( cg.predictedPlayerState.weapon ) )
    {
      if ( cg.zoomed )
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f > 1.0 )
          fov_x = zoomFov;
        else
          fov_x = fov_x + f * ( zoomFov - fov_x );

        // BUTTON_ATTACK2 isn't held so unzoom next time
        if( !( cmd.buttons & BUTTON_ATTACK2 ) )
        {
          cg.zoomed   = qfalse;
          cg.zoomTime = cg.time;
        }
      }
      else
      {
        f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME;

        if ( f > 1.0 )
          fov_x = fov_x;
        else
          fov_x = zoomFov + f * ( fov_x - zoomFov );

        // BUTTON_ATTACK2 is held so zoom next time
        if( cmd.buttons & BUTTON_ATTACK2 )
        {
          cg.zoomed   = qtrue;
          cg.zoomTime = cg.time;
        }
      }
    }
  }

  x = cg.refdef.width / tan( fov_x / 360 * M_PI );
  fov_y = atan2( cg.refdef.height, x );
  fov_y = fov_y * 360 / M_PI;

  // warp if underwater
  contents = CG_PointContents( cg.refdef.vieworg, -1 );

  if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) )
  {
    phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
    v = WAVE_AMPLITUDE * sin( phase );
    fov_x += v;
    fov_y -= v;
    inwater = qtrue;
  }
  else
    inwater = qfalse;

  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
      cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2;
    v = PCLOUD_ZOOM_AMPLITUDE * sin( phase );
    v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
    fov_x += v;
    fov_y += v;
  }


  // set it
  cg.refdef.fov_x = fov_x;
  cg.refdef.fov_y = fov_y;

  if( !cg.zoomed )
    cg.zoomSensitivity = (7 + (90/cg.refdef.fov_y))/8;//1;
  else
    cg.zoomSensitivity = cg.refdef.fov_y / 75.0;

  return inwater;
}