示例#1
0
文件: main.c 项目: icanhas/yantar
/*
 * BotUpdateInput
 */
void
BotUpdateInput(bot_state_t *bs, int time, int elapsed_time)
{
	bot_input_t bi;
	int j;

	/* add the delta angles to the bot's current view angles */
	for(j = 0; j < 3; j++)
		bs->viewangles[j] =
			modeuler(bs->viewangles[j] +
				SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
	/* change the bot view angles */
	BotChangeViewAngles(bs, (float)elapsed_time / 1000);
	/* retrieve the bot input */
	trap_EA_GetInput(bs->client, (float)time / 1000, &bi);
	/* respawn hack */
	if(bi.actionflags & ACTION_RESPAWN)
		if(bs->lastucmd.buttons & BUTTON_PRIATTACK) bi.actionflags &=
				~(ACTION_RESPAWN|ACTION_ATTACK);
	/* convert the bot input to a usercmd */
	BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
	/* subtract the delta angles */
	for(j = 0; j < 3; j++)
		bs->viewangles[j] =
			modeuler(bs->viewangles[j] -
				SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
}
示例#2
0
/*
==============
BotUpdateInput
==============
*/
void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time)
{
    bot_input_t bi;
    int j;

    //add the delta angles to the bot's current view angles
    for (j = 0; j < 3; j++)
    {
        bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
    }
    //change the bot view angles
    BotChangeViewAngles(bs, (float) elapsed_time / 1000);
    //retrieve the bot input
    botlib_export->ea.EA_GetInput(bs->client, (float) time / 1000, &bi);
    //respawn hack
    if (bi.actionflags & ACTION_RESPAWN)
    {
        if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
    }
    //convert the bot input to a usercmd
    BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
    //subtract the delta angles
    for (j = 0; j < 3; j++)
    {
        bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
    }
}
示例#3
0
/*
===================
MoveCmdToViewAngles

Given a movement command, computes the
floating point view angles requested by
that command, given the inputted delta
angles for that entity.  The computed angles
are stored in "view"

NOTE: Remember that the deltas (ps->delta_angles)
have the same type as the command angles-- they are
stored as integers, not floating points.

NOTE: This code is based on PM_UpdateViewAngles()
in bg_pmove.c.
===================
*/
void MoveCmdToViewAngles(usercmd_t *cmd, int *delta, vec3_t view)
{
	int short_angle;

	// The pitch angle has extra boundary checks
	short_angle = cmd->angles[PITCH] + delta[PITCH];
	if (short_angle > 16000)
		short_angle = 16000;
	else if (short_angle < -16000)
		short_angle = -16000;
	view[PITCH] = SHORT2ANGLE(short_angle);

	// Translate the yaw and roll angles from shorts to floats
	view[YAW ] = SHORT2ANGLE(cmd->angles[YAW ] + delta[YAW ]);
	view[ROLL] = SHORT2ANGLE(cmd->angles[ROLL] + delta[ROLL]);

	// Make sure the angles are bounded in the standard manner
	//
	// NOTE: If the rest of the code is written well, this shouldn't
	// matter.  Bounding in [0,360) should be just as good as [-180,+180).
	// But better safe than sorry.
	view[PITCH] = AngleNormalize180(view[PITCH]);
	view[YAW  ] = AngleNormalize180(view[YAW  ]);
	view[ROLL ] = AngleNormalize180(view[ROLL ]);
}
示例#4
0
void PM_ScaleUcmd( playerState_t *ps, usercmd_t *cmd, gentity_t *gent )
{
	if ( ps->vehicleModel != 0 )
	{//driving a vehicle
		//clamp the turn rate
		int maxPitchSpeed = MAX_PITCHSPEED_X_WING;//switch, eventually?  Or read from file?
		int diff = AngleNormalize180(SHORT2ANGLE((cmd->angles[PITCH]+ps->delta_angles[PITCH]))) - floor(ps->viewangles[PITCH]);
	
		if ( diff > maxPitchSpeed )
		{
			cmd->angles[PITCH] = ANGLE2SHORT( ps->viewangles[PITCH] + maxPitchSpeed ) - ps->delta_angles[PITCH];
		}
		else if ( diff < -maxPitchSpeed )
		{
			cmd->angles[PITCH] = ANGLE2SHORT( ps->viewangles[PITCH] - maxPitchSpeed ) - ps->delta_angles[PITCH];
		}

		//Um, WTF?  When I turn in a certain direction, I start going backwards?  Or strafing?
		int maxYawSpeed = MAX_YAWSPEED_X_WING;//switch, eventually?  Or read from file?
		diff = AngleNormalize180(SHORT2ANGLE(cmd->angles[YAW]+ps->delta_angles[YAW]) - floor(ps->viewangles[YAW]));

		//clamp the turn rate
		if ( diff > maxYawSpeed )
		{
			cmd->angles[YAW] = ANGLE2SHORT( ps->viewangles[YAW] + maxYawSpeed ) - ps->delta_angles[YAW];
		}
		else if ( diff < -maxYawSpeed )
		{
			cmd->angles[YAW] = ANGLE2SHORT( ps->viewangles[YAW] - maxYawSpeed ) - ps->delta_angles[YAW];
		}
	}
}
示例#5
0
/*
==============
BotUpdateInput
==============
*/
void BotUpdateInput( bot_state_t *bs, int time ) {
	bot_input_t bi;
	int j;

	//add the delta angles to the bot's current view angles
	for ( j = 0; j < 3; j++ ) {
		bs->viewangles[j] = AngleMod( bs->viewangles[j] + SHORT2ANGLE( bs->cur_ps.delta_angles[j] ) );
	}
	//
	BotChangeViewAngles( bs, (float) time / 1000 );
	trap_EA_GetInput( bs->client, (float) time / 1000, &bi );
	//respawn hack
	if ( bi.actionflags & ACTION_RESPAWN ) {
		if ( bs->lastucmd.buttons & BUTTON_ATTACK ) {
			bi.actionflags &= ~( ACTION_RESPAWN | ACTION_ATTACK );
		}
	}
	//
	BotInputToUserCommand( &bi, &bs->lastucmd, bs->cur_ps.delta_angles, time );
	bs->lastucmd.serverTime = time;
	//subtract the delta angles
	for ( j = 0; j < 3; j++ ) {
		bs->viewangles[j] = AngleMod( bs->viewangles[j] - SHORT2ANGLE( bs->cur_ps.delta_angles[j] ) );
	}
}
示例#6
0
void PM_ClampAngles (void)
{
	short	temp;
	int		i;

	if (pm->s.pm_flags & PMF_TIME_TELEPORT)
	{
		pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
		pm->viewangles[PITCH] = 0;
		pm->viewangles[ROLL] = 0;
	}

	else
	{
		/* circularly clamp the angles with deltas */
		for (i=0 ; i<3 ; i++)
		{
			temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
			pm->viewangles[i] = SHORT2ANGLE(temp);
		}

		/* don't let the player look up or down more than 90 degrees */
		if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
			pm->viewangles[PITCH] = 89;

		else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
			pm->viewangles[PITCH] = 271;
	}

	AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
}
示例#7
0
void demoMoveUpdateAngles(void) {
	float oldAngle, newAngle;int i;
	for (i=0;i<3;i++) {
		oldAngle = SHORT2ANGLE( demo.oldcmd.angles[i] );
		newAngle = SHORT2ANGLE( demo.cmd.angles[i] );
		demo.cmdDeltaAngles[i] = AngleNormalize180( newAngle - oldAngle );
	}
}
示例#8
0
文件: NPC_utils.c 项目: jwginge/ojpa
qboolean NPC_FacePosition( vec3_t position, qboolean doPitch )
{
	vec3_t		muzzle;
	vec3_t		angles;
	float		yawDelta;
	qboolean	facing = qtrue;

	//Get the positions
	if ( NPC->client && (NPC->client->NPC_class == CLASS_RANCOR || NPC->client->NPC_class == CLASS_WAMPA) )// || NPC->client->NPC_class == CLASS_SAND_CREATURE) )
	{
		CalcEntitySpot( NPC, SPOT_ORIGIN, muzzle );
		muzzle[2] += NPC->r.maxs[2] * 0.75f;
	}
	else if ( NPC->client && NPC->client->NPC_class == CLASS_GALAKMECH )
	{
		CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
	}
	else
	{
		CalcEntitySpot( NPC, SPOT_HEAD_LEAN, muzzle );//SPOT_HEAD
	}

	//Find the desired angles
	GetAnglesForDirection( muzzle, position, angles );

	NPCInfo->desiredYaw		= AngleNormalize360( angles[YAW] );
	NPCInfo->desiredPitch	= AngleNormalize360( angles[PITCH] );

	if ( NPC->enemy && NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_ATST )
	{
		// FIXME: this is kind of dumb, but it was the easiest way to get it to look sort of ok
		NPCInfo->desiredYaw	+= flrand( -5, 5 ) + sin( level.time * 0.004f ) * 7;
		NPCInfo->desiredPitch += flrand( -2, 2 );
	}
	//Face that yaw
	NPC_UpdateAngles( qtrue, qtrue );

	//Find the delta between our goal and our current facing
	yawDelta = AngleNormalize360( NPCInfo->desiredYaw - ( SHORT2ANGLE( ucmd.angles[YAW] + client->ps.delta_angles[YAW] ) ) );
	
	//See if we are facing properly
	if ( fabs( yawDelta ) > VALID_ATTACK_CONE )
		facing = qfalse;

	if ( doPitch )
	{
		//Find the delta between our goal and our current facing
		float currentAngles = ( SHORT2ANGLE( ucmd.angles[PITCH] + client->ps.delta_angles[PITCH] ) );
		float pitchDelta = NPCInfo->desiredPitch - currentAngles;
		
		//See if we are facing properly
		if ( fabs( pitchDelta ) > VALID_ATTACK_CONE )
			facing = qfalse;
	}

	return facing;
}
示例#9
0
/*
* CG_DemoCam_FreeFly
*/
int CG_DemoCam_FreeFly( void )
{
	usercmd_t cmd;
	const float SPEED = 500;

	if( cgs.demoPlaying && CamIsFree )
	{
		vec3_t wishvel, wishdir, forward, right, up, moveangles;
		float fmove, smove, upmove, wishspeed, maxspeed;
		int i;

		maxspeed = 250;

		// run frame
		trap_NET_GetUserCmd( trap_NET_GetCurrentUserCmdNum() - 1, &cmd );
		cmd.msec = cg.realFrameTime * 1000;
		cmd.forwardfrac = ( (float)cmd.forwardmove/(float)cmd.msec );
		cmd.sidefrac = ( (float)cmd.sidemove/(float)cmd.msec );
		cmd.upfrac = ( (float)cmd.upmove/(float)cmd.msec );

		for( i = 0; i < 3; i++ )
			moveangles[i] = SHORT2ANGLE( cmd.angles[i] ) + SHORT2ANGLE( freecam_delta_angles[i] );
		
		AngleVectors( moveangles, forward, right, up );
		VectorCopy( moveangles, cam_angles );

		fmove = cmd.forwardfrac * SPEED;
		smove = cmd.sidefrac * SPEED;
		upmove = cmd.upfrac * SPEED;
		if( cmd.buttons & BUTTON_SPECIAL )
			maxspeed *= 2;

		for( i = 0; i < 3; i++ )
			wishvel[i] = forward[i] * fmove + right[i] * smove;
		wishvel[2] += upmove;

		wishspeed = VectorNormalize2( wishvel, wishdir );
		if( wishspeed > maxspeed )
		{
			wishspeed = maxspeed/wishspeed;
			VectorScale( wishvel, wishspeed, wishvel );
			wishspeed = maxspeed;
		}
		
		VectorMA( cam_origin, cg.realFrameTime, wishvel, cam_origin );

		cam_POVent = 0;
		cam_3dPerson = false;
		return VIEWDEF_CAMERA;
	}

	return VIEWDEF_PLAYERVIEW;
}
示例#10
0
/*
================
PM_UpdateViewAngles

This can be used as another entry point when only the viewangles
are being updated isntead of a full move
================
*/
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
	short		temp;
	int		i;

	if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
		return;		// no view changes at all
	}

	if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
		return;		// no view changes at all
	}

	// circularly clamp the angles with deltas
	for (i=0 ; i<3 ; i++) {
		temp = cmd->angles[i] + ps->delta_angles[i];
		if ( i == PITCH ) {
			// don't let the player look up or down more than 90 degrees
			if ( temp > 16000 ) {
				ps->delta_angles[i] = 16000 - cmd->angles[i];
				temp = 16000;
			} else if ( temp < -16000 ) {
				ps->delta_angles[i] = -16000 - cmd->angles[i];
				temp = -16000;
			}
		}
		ps->viewangles[i] = SHORT2ANGLE(temp);
	}

}
示例#11
0
文件: cl_pred.c 项目: darkshade9/aq2w
/*
 * Cl_PredictMovement
 *
 * Run the latest movement command through the player movement code locally,
 * using the resulting origin and angles to reduce perceived latency.
 */
void Cl_PredictMovement(void) {
	int i, ack, current;
	pm_move_t pm;
	float step;

	if (cls.state != CL_ACTIVE)
		return;

	if (!cl_predict->value || (cl.frame.ps.pmove.pm_flags & PMF_NO_PREDICTION)) {
		for (i = 0; i < 3; i++) { // just set angles
			cl.predicted_angles[i] = cl.angles[i]
					+ SHORT2ANGLE(cl.frame.ps.pmove.delta_angles[i]);
		}
		return;
	}

	ack = cls.netchan.incoming_acknowledged;
	current = cls.netchan.outgoing_sequence;

	// if we are too far out of date, just freeze
	if (current - ack >= CMD_BACKUP) {
		Com_Warn("Cl_PredictMovement: Exceeded CMD_BACKUP.\n");
		return;
	}

	// copy current state to pmove
	memset(&pm, 0, sizeof(pm));
	pm.Trace = Cl_Trace;
	pm.PointContents = Cl_Pointcontents;
	pm.s = cl.frame.ps.pmove;
	pm.s.gravity = cl_gravity;

	// run frames
	while (++ack <= current) {
		const int frame = ack & CMD_MASK;
		const user_cmd_t *cmd = &cl.cmds[frame];

		if (!cmd->msec)
			continue;

		pm.cmd = *cmd;
		Pmove(&pm);

		// save for debug checking
		VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
	}

	step = pm.s.origin[2] * 0.125 - cl.predicted_origin[2];

	if ((pm.s.pm_flags & PMF_ON_STAIRS) && step > 4.0) { // save for stair lerping
		cl.predicted_step_time = cls.real_time;
		cl.predicted_step = step;
	}

	// copy results out for rendering
	VectorScale(pm.s.origin, 0.125, cl.predicted_origin);
	VectorCopy(pm.angles, cl.predicted_angles);

	cl.underwater = pm.water_level > 2;
}
示例#12
0
void CL_ClampPitch(void)
{
  float pitch;

  pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);

  if (pitch > 180) {
    pitch -= 360;
  }

  if (cl.viewangles[PITCH] + pitch < -360) {
    cl.viewangles[PITCH] += 360; /* wrapped */
  }

  if (cl.viewangles[PITCH] + pitch > 360) {
    cl.viewangles[PITCH] -= 360; /* wrapped */
  }

  if (cl.viewangles[PITCH] + pitch > 89) {
    cl.viewangles[PITCH] = 89 - pitch;
  }

  if (cl.viewangles[PITCH] + pitch < -89) {
    cl.viewangles[PITCH] = -89 - pitch;
  }
}
示例#13
0
文件: cl_input.cpp 项目: DaTa-/cnq3x
static void IN_MLookUp()
{
	in_mlooking = qfalse;
	if ( !cl_freelook->integer ) {
		cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
	}
}
示例#14
0
void Player::Think()
{
	speed *= player_speed.GetFloat();
	orgin.x += _usercmd.forwardmove * speed.x;
	orgin.y += _usercmd.forwardmove * speed.y;

	orgin.x += _usercmd.rightmove * speed.y;
	orgin.y += -_usercmd.rightmove * speed.x;
	orgin.z += _usercmd.upmove * player_speed.GetFloat();

	for (int i = 0; i < 3; i++ ) {
		cmdAngles[i] = SHORT2ANGLE( _usercmd.angles[i] );
		viewAngles[i] = idMath::AngleNormalize180( SHORT2ANGLE( _usercmd.angles[i]));
	}

	CalculateRenderView();
}
示例#15
0
void IN_CenterView( void ) {
	qboolean ok = qtrue;
	if ( cgvm ) {
		ok = VM_Call( cgvm, CG_CHECKCENTERVIEW );
	}
	if ( ok ) {
		cl.viewangles[PITCH] = -SHORT2ANGLE( cl.snap.ps.delta_angles[PITCH] );
	}
}
示例#16
0
文件: cl_input.c 项目: tenght/qfusion
/*
* IN_CenterView
*/
void IN_CenterView( void )
{
	if( cl.currentSnapNum > 0 )
	{
		player_state_t *playerState;
		playerState = &cl.snapShots[cl.currentSnapNum & UPDATE_MASK].playerState;
		cl.viewangles[PITCH] = -SHORT2ANGLE( playerState->pmove.delta_angles[PITCH] );
	}
}
示例#17
0
void sdVehicleInput::SetPlayer( idPlayer* player ) {
	data.player		= player;
	if ( data.player != NULL ) {
		data.usercmd	= gameLocal.usercmds[ player->entityNumber ];
	}

	for ( int i = 0; i < 3; i++ ) {
		data.cmdAngles[ i ] = SHORT2ANGLE( data.usercmd.angles[ i ] );
	}
}
示例#18
0
void IN_CenterView( int localPlayerNum ) {
	playerState_t *ps;

	if ( !cg.snap || cg.snap->playerNums[localPlayerNum] == -1 ) {
		return;
	}

	ps = &cg.snap->pss[localPlayerNum];

	cg.localPlayers[localPlayerNum].viewangles[PITCH] = -SHORT2ANGLE(ps->delta_angles[PITCH]);
}
示例#19
0
/*
==============
sdDeployMenu::UsercommandCallback
==============
*/
void sdDeployMenu::UsercommandCallback( usercmd_t& cmd ) {
	if ( modeToggle ) {
		cmd.forwardmove = 0;
		cmd.rightmove = 0;
		cmd.upmove = 0;

		for ( int i = 0; i < 3; i++ ) {
			if ( !gameLocal.IsPaused() ) {
				rotation += SHORT2ANGLE( cmd.angles[ i ] - lockedAngles[ i ] );
			}
			cmd.angles[ i ] = lockedAngles[ i ];
		}
	}
}
示例#20
0
文件: cl_input.c 项目: Bad-ptr/q2pro
static void CL_ClampPitch( void ) {
    float pitch;

    pitch = SHORT2ANGLE( cl.frame.ps.pmove.delta_angles[PITCH] );
    if (pitch > 180)
        pitch -= 360;

    if (cl.viewangles[PITCH] + pitch < -360)
        cl.viewangles[PITCH] += 360; // wrapped
    if (cl.viewangles[PITCH] + pitch > 360)
        cl.viewangles[PITCH] -= 360; // wrapped

    if (cl.viewangles[PITCH] + pitch > 89)
        cl.viewangles[PITCH] = 89 - pitch;
    if (cl.viewangles[PITCH] + pitch < -89)
        cl.viewangles[PITCH] = -89 - pitch;
}
示例#21
0
/*
===============
CG_OffsetShoulderView

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

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

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

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

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

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

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

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

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

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

  AxisToAngles( rotaxis, rotationAngles );

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

  // Now run the first person stuff so we get various effects added.
  CG_OffsetFirstPersonView( );
}
示例#22
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 );
  }
}
示例#23
0
文件: cl_input.c 项目: qrealka/ioq3
void IN_CenterView (void) {
	cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
}
示例#24
0
/*
==============
BotAI
==============
*/
int BotAI(int playernum, float thinktime) {
	bot_state_t *bs;
	char buf[1024], *args;
	int j;

	EA_ResetInput(playernum);
	//
	bs = botstates[playernum];
	if (!bs || !bs->inuse) {
		BotAI_Print(PRT_FATAL, "BotAI: player %d is not setup\n", playernum);
		return qfalse;
	}

	//retrieve the current player state
	if (!BotAI_GetPlayerState( playernum, &bs->cur_ps )) {
		BotAI_Print(PRT_FATAL, "BotAI: failed to get player state for player %d\n", playernum);
		return qfalse;
	}

	//retrieve any waiting server commands
	while( trap_BotGetServerCommand(playernum, buf, sizeof(buf)) ) {
		//have buf point to the command and args to the command arguments
		args = strchr( buf, ' ');
		if (!args) continue;
		*args++ = '\0';

		//remove color espace sequences from the arguments
		RemoveColorEscapeSequences( args );

		if (!Q_stricmp(buf, "cp "))
			{ /*CenterPrintf*/ }
		else if (!Q_stricmp(buf, "cs"))
			{ /*ConfigStringModified*/ }
		else if (!Q_stricmp(buf, "print")) {
			//remove first and last quote from the chat message
			memmove(args, args+1, strlen(args));
			args[strlen(args)-1] = '\0';
			BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);
		}
		else if (!Q_stricmp(buf, "chat") || !Q_stricmp(buf, "tell")) {
			//remove first and last quote from the chat message
			memmove(args, args+1, strlen(args));
			args[strlen(args)-1] = '\0';
			BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
		}
		else if (!Q_stricmp(buf, "tchat")) {
			//remove first and last quote from the chat message
			memmove(args, args+1, strlen(args));
			args[strlen(args)-1] = '\0';
			BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
		}
#ifdef MISSIONPACK
		else if (!Q_stricmp(buf, "vchat")) {
			BotVoiceChatCommand(bs, SAY_ALL, args);
		}
		else if (!Q_stricmp(buf, "vtchat")) {
			BotVoiceChatCommand(bs, SAY_TEAM, args);
		}
		else if (!Q_stricmp(buf, "vtell")) {
			BotVoiceChatCommand(bs, SAY_TELL, args);
		}
#endif
		else if (!Q_stricmp(buf, "scores"))
			{ /*FIXME: parse scores?*/ }
		else if (!Q_stricmp(buf, "clientLevelShot"))
			{ /*ignore*/ }
	}
	//add the delta angles to the bot's current view angles
	for (j = 0; j < 3; j++) {
		bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
	}
	//increase the local time of the bot
	bs->ltime += thinktime;
	//
	bs->thinktime = thinktime;
	//origin of the bot
	VectorCopy(bs->cur_ps.origin, bs->origin);
	//eye coordinates of the bot
	VectorCopy(bs->cur_ps.origin, bs->eye);
	bs->eye[2] += bs->cur_ps.viewheight;
	//get the area the bot is in
	bs->areanum = BotPointAreaNum(bs->origin);
	//the real AI
	BotDeathmatchAI(bs, thinktime);
	//set the weapon selection every AI frame
	EA_SelectWeapon(bs->playernum, bs->weaponnum);
	//subtract the delta angles
	for (j = 0; j < 3; j++) {
		bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
	}
	//everything was ok
	return qtrue;
}
示例#25
0
文件: p_client.c 项目: ZwS/qudos
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*/
void ClientThink (edict_t *ent, usercmd_t *ucmd)
{
	gclient_t	*client;
	edict_t	*other;
	int		i, j;
	pmove_t	pm;

#if defined(_DEBUG) && defined(_Z_TESTMODE)

  if(testitemOriginMove && testItemDroped)
  {
    if(ucmd->forwardmove > 0)
    {
      testItemDroped->s.origin[2]++;
    }
    else if(ucmd->forwardmove < 0)
    {
      testItemDroped->s.origin[2]--;
    }

    return;
  }

#endif

	level.current_entity = ent;
	client = ent->client;
	
#ifdef GAME_MOD
	Blinky_BeginClientThink(ent, ucmd);
#endif

	if (level.intermissiontime)
	{
		client->ps.pmove.pm_type = PM_FREEZE;
		// can exit intermission after five seconds
		if (level.time > level.intermissiontime + 5.0 
			&& (ucmd->buttons & BUTTON_ANY) )
			level.exitintermission = true;
		return;
	}

	if(ent->movetype == MOVETYPE_FREEZE)
	{
		client->ps.pmove.pm_type = PM_FREEZE;
		return;
	}

	pm_passent = ent;

	// set up for pmove
	memset (&pm, 0, sizeof(pm));
	
	if (ent->movetype == MOVETYPE_NOCLIP)
		client->ps.pmove.pm_type = PM_SPECTATOR;
	else if (ent->s.modelindex != 255)
		client->ps.pmove.pm_type = PM_GIB;
	else if (ent->deadflag)
		client->ps.pmove.pm_type = PM_DEAD;
	else
		client->ps.pmove.pm_type = PM_NORMAL;

	client->ps.pmove.gravity = sv_gravity->value;
	pm.s = client->ps.pmove;

	for (i=0 ; i<3 ; i++)
	{
		pm.s.origin[i] = ent->s.origin[i]*8;
		pm.s.velocity[i] = ent->velocity[i]*8;
	}

	if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
	{
		pm.snapinitial = true;
//		gi.dprintf ("pmove changed!\n");
	}

	pm.cmd = *ucmd;

	pm.trace = PM_trace;	// adds default parms
	pm.pointcontents = gi.pointcontents;

	// perform a pmove
	gi.Pmove (&pm);

	// save results of pmove
	client->ps.pmove = pm.s;
	client->old_pmove = pm.s;

	for (i=0 ; i<3 ; i++)
	{
		ent->s.origin[i] = pm.s.origin[i]*0.125;
		ent->velocity[i] = pm.s.velocity[i]*0.125;
	}

	VectorCopy (pm.mins, ent->mins);
	VectorCopy (pm.maxs, ent->maxs);

	client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
	client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
	client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);

	if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
	{
		gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
		PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
	}

	ent->viewheight = pm.viewheight;
	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;
	ent->groundentity = pm.groundentity;
	if (pm.groundentity)
		ent->groundentity_linkcount = pm.groundentity->linkcount;

	if (ent->deadflag)
	{
		client->ps.viewangles[ROLL] = 40;
		client->ps.viewangles[PITCH] = -15;
		client->ps.viewangles[YAW] = client->killer_yaw;
	}
	else
	{
		VectorCopy (pm.viewangles, client->v_angle);
		VectorCopy (pm.viewangles, client->ps.viewangles);
	}


	gi.linkentity (ent);

	if (ent->movetype != MOVETYPE_NOCLIP)
		G_TouchTriggers (ent);

	// touch other objects
	for (i=0 ; i<pm.numtouch ; i++)
	{
		other = pm.touchents[i];
		for (j=0 ; j<i ; j++)
			if (pm.touchents[j] == other)
				break;
		if (j != i)
			continue;	// duplicated
		if (!other->touch)
			continue;
		other->touch (other, ent, NULL, NULL);
	}


	client->oldbuttons = client->buttons;
	client->buttons = ucmd->buttons;
	client->latched_buttons |= client->buttons & ~client->oldbuttons;

	// save light level the player is standing on for
	// monster sighting AI
	ent->light_level = ucmd->lightlevel;

	// fire weapon from final position if needed
	if (client->latched_buttons & BUTTON_ATTACK)
	{
		if (!client->weapon_thunk)
		{
			client->weapon_thunk = true;
			Think_Weapon (ent);
		}
	}
#ifdef WITH_ACEBOT
// ACEBOT_ADD
	if (!ent->is_bot && !ent->deadflag && !ent->client->resp.spectator)
		ACEND_PathMap(ent);
// ACEBOT_END
#endif
}
示例#26
0
/*
==============
BotAI
==============
*/
int BotAI( int client, float thinktime ) {
	bot_state_t *bs;
	char buf[1024], *args;
	int j;

	trap_EA_ResetInput( client, NULL );
	//
	bs = botstates[client];
	if ( !bs || !bs->inuse ) {
		BotAI_Print( PRT_FATAL, "client %d hasn't been setup\n", client );
		return BLERR_AICLIENTNOTSETUP;
	}

	//retrieve the current client state
	BotAI_GetClientState( client, &bs->cur_ps );

	//retrieve any waiting console messages
	while ( trap_BotGetServerCommand( client, buf, sizeof( buf ) ) ) {
		//have buf point to the command and args to the command arguments
		args = strchr( buf, ' ' );
		if ( !args ) {
			continue;
		}
		*args++ = '\0';

		//remove color espace sequences from the arguments
		Q_CleanStr( args );

		//botai_import.Print(PRT_MESSAGE, "ConsoleMessage: \"%s\"\n", buf);
		if ( !Q_stricmp( buf, "cp " ) ) { /*CenterPrintf*/
		} else if ( !Q_stricmp( buf, "cs" ) )                                                      { /*ConfigStringModified*/
		} else if ( !Q_stricmp( buf, "print" ) )                                                                                                                       {
			trap_BotQueueConsoleMessage( bs->cs, CMS_NORMAL, args );
		} else if ( !Q_stricmp( buf, "chat" ) ) {
			trap_BotQueueConsoleMessage( bs->cs, CMS_CHAT, args );
		} else if ( !Q_stricmp( buf, "tchat" ) ) {
			trap_BotQueueConsoleMessage( bs->cs, CMS_CHAT, args );
		} else if ( !Q_stricmp( buf, "scores" ) ) { /*FIXME: parse scores?*/
		} else if ( !Q_stricmp( buf, "clientLevelShot" ) )                                                                    { /*ignore*/
		}
	}
	//add the delta angles to the bot's current view angles
	for ( j = 0; j < 3; j++ ) {
		bs->viewangles[j] = AngleMod( bs->viewangles[j] + SHORT2ANGLE( bs->cur_ps.delta_angles[j] ) );
	}
	//increase the local time of the bot
	bs->ltime += thinktime;
	//
	bs->thinktime = thinktime;
	//origin of the bot
	VectorCopy( bs->cur_ps.origin, bs->origin );
	//eye coordinates of the bot
	VectorCopy( bs->cur_ps.origin, bs->eye );
	bs->eye[2] += bs->cur_ps.viewheight;
	//get the area the bot is in
	bs->areanum = BotPointAreaNum( bs->origin );
	//the real AI
	BotDeathmatchAI( bs, thinktime );
	//set the weapon selection every AI frame
	trap_EA_SelectWeapon( bs->client, bs->weaponnum );
	//subtract the delta angles
	for ( j = 0; j < 3; j++ ) {
		bs->viewangles[j] = AngleMod( bs->viewangles[j] - SHORT2ANGLE( bs->cur_ps.delta_angles[j] ) );
	}
	//everything was ok
	return BLERR_NOERROR;
}
示例#27
0
void CL_FinishMove( usercmd_t *cmd ) {
	int		i;

	// copy the state that the cgame is currently sending
	cmd->weapon = cl.cgameUserCmdValue;
	cmd->forcesel = cl.cgameForceSelection;
	cmd->invensel = cl.cgameInvenSelection;

	if (cl.gcmdSendValue)
	{
		cmd->generic_cmd = cl.gcmdValue;
		//cl.gcmdSendValue = qfalse;
		cl.gcmdSentValue = qtrue;
	}
	else
	{
		cmd->generic_cmd = 0;
	}

	// send the current server time so the amount of movement
	// can be determined without allowing cheating
	cmd->serverTime = cl.serverTime;
	
	if (cl.cgameViewAngleForceTime > cl.serverTime)
	{
		cl.cgameViewAngleForce[YAW] -= SHORT2ANGLE(cl.snap.ps.delta_angles[YAW]);

		cl.viewangles[YAW] = cl.cgameViewAngleForce[YAW];
		cl.cgameViewAngleForceTime = 0;
	}

	if ( cl_crazyShipControls )
	{
		float pitchSubtract, pitchDelta, yawDelta;

		yawDelta = AngleSubtract(cl.viewangles[YAW],cl_lastViewAngles[YAW]);
		//yawDelta *= (4.0f*pVeh->m_fTimeModifier);
		cl_sendAngles[ROLL] -= yawDelta;

		float nRoll = fabs(cl_sendAngles[ROLL]);

		pitchDelta = AngleSubtract(cl.viewangles[PITCH],cl_lastViewAngles[PITCH]);
		//pitchDelta *= (2.0f*pVeh->m_fTimeModifier);
		pitchSubtract = pitchDelta * (nRoll/90.0f);
		cl_sendAngles[PITCH] += pitchDelta-pitchSubtract;

		//yaw-roll calc should be different
		if (nRoll > 90.0f)
		{
			nRoll -= 180.0f;
		}
		if (nRoll < 0.0f)
		{
			nRoll = -nRoll;
		}
		pitchSubtract = pitchDelta * (nRoll/90.0f);
		if ( cl_sendAngles[ROLL] > 0.0f )
		{
			cl_sendAngles[YAW] += pitchSubtract;
		}
		else
		{
			cl_sendAngles[YAW] -= pitchSubtract;
		}
		
		cl_sendAngles[PITCH] = AngleNormalize180( cl_sendAngles[PITCH] );
		cl_sendAngles[YAW] = AngleNormalize360( cl_sendAngles[YAW] );
		cl_sendAngles[ROLL] = AngleNormalize180( cl_sendAngles[ROLL] );

		for (i=0 ; i<3 ; i++) {
			cmd->angles[i] = ANGLE2SHORT(cl_sendAngles[i]);
		}
	}
	else
	{
		for (i=0 ; i<3 ; i++) {
			cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
		}
		//in case we switch to the cl_crazyShipControls
		VectorCopy( cl.viewangles, cl_sendAngles );
	}
	//always needed in for the cl_crazyShipControls
	VectorCopy( cl.viewangles, cl_lastViewAngles );
}
示例#28
0
/*
================
PM_UpdateViewAngles

This can be used as another entry point when only the viewangles
are being updated isntead of a full move

//FIXME: Now that they pmove twice per think, they snap-look really fast
================
*/
void PM_UpdateViewAngles( playerState_t *ps, usercmd_t *cmd, gentity_t *gent ) 
{
	short		temp;
	float		pitchMin=-75, pitchMax=75, yawMin=0, yawMax=0;	//just to shut up warnings
	int			i;
	vec3_t		start, end, tmins, tmaxs, right;
	trace_t		trace;
	qboolean	lockedYaw = qfalse;

	if ( ps->pm_type == PM_INTERMISSION ) 
	{
		return;		// no view changes at all
	}

	if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) 
	{
		return;		// no view changes at all
	}

//	if ( player_locked )
//	{//can't turn
//		return;
//	}
	if ( ps->eFlags & EF_NPC && gent != NULL && gent->client != NULL )
	{
		if(gent->client->renderInfo.renderFlags & RF_LOCKEDANGLE)
		{
			pitchMin = 0 - gent->client->renderInfo.headPitchRangeUp - gent->client->renderInfo.torsoPitchRangeUp;
			pitchMax = gent->client->renderInfo.headPitchRangeDown + gent->client->renderInfo.torsoPitchRangeDown;
			
			yawMin = 0 - gent->client->renderInfo.headYawRangeLeft - gent->client->renderInfo.torsoYawRangeLeft;
			yawMax = gent->client->renderInfo.headYawRangeRight + gent->client->renderInfo.torsoYawRangeRight;

			lockedYaw = qtrue;
		}
		else
		{
			pitchMin = -gent->client->renderInfo.headPitchRangeUp-gent->client->renderInfo.torsoPitchRangeUp;
			pitchMax = gent->client->renderInfo.headPitchRangeDown+gent->client->renderInfo.torsoPitchRangeDown;
		}
	}

	if ( ps->eFlags & EF_LOCKED_TO_WEAPON )
	{
		// Emplaced guns have different pitch capabilities
		pitchMin = -35;
		pitchMax = 30;
	}

	const short pitchClampMin = ANGLE2SHORT(pitchMin);
	const short pitchClampMax = ANGLE2SHORT(pitchMax);

	// circularly clamp the angles with deltas
	for (i=0 ; i<3 ; i++) 
	{
		temp = cmd->angles[i] + ps->delta_angles[i];
		if ( i == PITCH ) 
		{
			//FIXME get this limit from the NPCs stats?
			// don't let the player look up or down more than 90 degrees
			if ( temp > pitchClampMax ) 
			{
				ps->delta_angles[i] = (pitchClampMax - cmd->angles[i]) & 0xffff;	//& clamp to short
				temp = pitchClampMax;
			} 
			else if ( temp < pitchClampMin ) 
			{
				ps->delta_angles[i] = (pitchClampMin - cmd->angles[i]) & 0xffff;	//& clamp to short
				temp = pitchClampMin;
			}
		}
		if ( i == ROLL && ps->vehicleModel != 0 ) 
		{
			if ( temp > pitchClampMax ) 
			{
				ps->delta_angles[i] = (pitchClampMax - cmd->angles[i]) & 0xffff;
				temp = pitchClampMax;
			} 
			else if ( temp < pitchClampMin ) 
			{
				ps->delta_angles[i] = (pitchClampMin - cmd->angles[i]) & 0xffff;
				temp = pitchClampMin;
			}
		}
		//FIXME: Are we losing precision here?  Is this why it jitters?
		ps->viewangles[i] = SHORT2ANGLE(temp);

		if ( i == YAW && lockedYaw) 
		{
			// don't let the player look left or right more than the clamp, if any
			if ( AngleSubtract(ps->viewangles[i], gent->client->renderInfo.lockYaw) > yawMax ) 
			{
				ps->viewangles[i] = yawMax;
			} 
			else if ( AngleSubtract(ps->viewangles[i], gent->client->renderInfo.lockYaw) < yawMin ) 
			{
				ps->viewangles[i] = yawMin;
			}
		}
	}

	if ( (!cg.renderingThirdPerson||cg.zoomMode) && (cmd->buttons & BUTTON_USE) && cmd->rightmove != 0 && !cmd->forwardmove && cmd->upmove <= 0 )
	{//Only lean if holding use button, strafing and not moving forward or back and not jumping
		if ( gent )
		{
			int leanofs = 0;
			vec3_t	viewangles;

			if ( cmd->rightmove > 0 )
			{
				/*
				if( pm->ps->legsAnim != LEGS_LEAN_RIGHT1)
				{
					PM_SetAnim(pm, SETANIM_LEGS, LEGS_LEAN_RIGHT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
				}
				pm->ps->legsAnimTimer = 500;//Force it to hold the anim for at least half a sec
				*/

				if ( ps->leanofs <= 28 )
				{
					leanofs = ps->leanofs + 4;
				}
				else
				{
					leanofs = 32;
				}
			}
			else
			{
				/*
				if ( pm->ps->legsAnim != LEGS_LEAN_LEFT1 )
				{
					PM_SetAnim(pm, SETANIM_LEGS, LEGS_LEAN_LEFT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
				}
				pm->ps->legsAnimTimer = 500;//Force it to hold the anim for at least half a sec
				*/

				if ( ps->leanofs >= -28 )
				{
					leanofs = ps->leanofs - 4;
				}
				else
				{
					leanofs = -32;
				}
			}

			VectorCopy( ps->origin, start );
			start[2] += ps->viewheight;
			VectorCopy( ps->viewangles, viewangles );
			viewangles[ROLL] = 0;
			AngleVectors( ps->viewangles, NULL, right, NULL );
			VectorNormalize( right );
			right[2] = (leanofs<0)?0.25:-0.25;
			VectorMA( start, leanofs, right, end );
			VectorSet( tmins, -8, -8, -4 );
			VectorSet( tmaxs, 8, 8, 4 );
			//if we don't trace EVERY frame, can TURN while leaning and
			//end up leaning into solid architecture (sigh)
			gi.trace( &trace, start, tmins, tmaxs, end, gent->s.number, MASK_PLAYERSOLID, (EG2_Collision)0, 0 );

			ps->leanofs = floor((float)leanofs * trace.fraction);

			ps->leanStopDebounceTime = 20;
		}
	}
	else
	{
		if ( gent && (cmd->forwardmove || cmd->upmove > 0) )
		{
			if( ( pm->ps->legsAnim == LEGS_LEAN_RIGHT1) ||
				( pm->ps->legsAnim == LEGS_LEAN_LEFT1) )
			{
				pm->ps->legsAnimTimer = 0;//Force it to stop the anim
			}
		}

		if ( ps->leanofs > 0 )
		{
			//FIXME: play lean anim backwards?
			ps->leanofs-=4;
			if ( ps->leanofs < 0 )
			{
				ps->leanofs = 0;
			}
		}
		else if ( ps->leanofs < 0 )
		{
			//FIXME: play lean anim backwards?
			ps->leanofs+=4;
			if ( ps->leanofs > 0 )
			{
				ps->leanofs = 0;
			}
		}
	}

	if ( ps->leanStopDebounceTime )
	{
		ps->leanStopDebounceTime -= 1;
		cmd->rightmove = 0;
		cmd->buttons &= ~BUTTON_USE;
	}
}
示例#29
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*/
void ClientThink (edict_t *ent, usercmd_t *ucmd)
{
	gclient_t	*client;
	edict_t	*other;
	int		i, j;
	pmove_t	pm;

	level.current_entity = ent;
	client = ent->client;

	if (level.intermissiontime)
	{
		client->ps.pmove.pm_type = PM_FREEZE;
		// can exit intermission after five seconds
		if (level.time > level.intermissiontime + 5.0 
			&& (ucmd->buttons & BUTTON_ANY) )
			level.exitintermission = true;
		return;
	}

	pm_passent = ent;

	if (ent->client->chase_target) {

		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);

	} else {

		// set up for pmove
		memset (&pm, 0, sizeof(pm));

		if (ent->movetype == MOVETYPE_NOCLIP)
			client->ps.pmove.pm_type = PM_SPECTATOR;
		else if (ent->s.modelindex != 255)
			client->ps.pmove.pm_type = PM_GIB;
		else if (ent->deadflag)
			client->ps.pmove.pm_type = PM_DEAD;
		else
			client->ps.pmove.pm_type = PM_NORMAL;

		client->ps.pmove.gravity = sv_gravity->value;
		pm.s = client->ps.pmove;

		for (i=0 ; i<3 ; i++)
		{
			pm.s.origin[i] = ent->s.origin[i]*8;
			pm.s.velocity[i] = ent->velocity[i]*8;
		}

		if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
		{
			pm.snapinitial = true;
	//		gi.dprintf ("pmove changed!\n");
		}

		pm.cmd = *ucmd;

		pm.trace = PM_trace;	// adds default parms
		pm.pointcontents = gi.pointcontents;

		// perform a pmove
		gi.Pmove (&pm);

		// save results of pmove
		client->ps.pmove = pm.s;
		client->old_pmove = pm.s;

		for (i=0 ; i<3 ; i++)
		{
			ent->s.origin[i] = pm.s.origin[i]*0.125;
			ent->velocity[i] = pm.s.velocity[i]*0.125;
		}

		VectorCopy (pm.mins, ent->mins);
		VectorCopy (pm.maxs, ent->maxs);

		client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
		client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
		client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);

		if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
		{
			gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
			PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
		}

		ent->viewheight = pm.viewheight;
		ent->waterlevel = pm.waterlevel;
		ent->watertype = pm.watertype;
		ent->groundentity = pm.groundentity;
		if (pm.groundentity)
			ent->groundentity_linkcount = pm.groundentity->linkcount;

		if (ent->deadflag)
		{
			client->ps.viewangles[ROLL] = 40;
			client->ps.viewangles[PITCH] = -15;
			client->ps.viewangles[YAW] = client->killer_yaw;
		}
		else
		{
			VectorCopy (pm.viewangles, client->v_angle);
			VectorCopy (pm.viewangles, client->ps.viewangles);
		}

		gi.linkentity (ent);

		if (ent->movetype != MOVETYPE_NOCLIP)
			G_TouchTriggers (ent);

		// touch other objects
		for (i=0 ; i<pm.numtouch ; i++)
		{
			other = pm.touchents[i];
			for (j=0 ; j<i ; j++)
				if (pm.touchents[j] == other)
					break;
			if (j != i)
				continue;	// duplicated
			if (!other->touch)
				continue;
			other->touch (other, ent, NULL, NULL);
		}

	}

	client->oldbuttons = client->buttons;
	client->buttons = ucmd->buttons;
	client->latched_buttons |= client->buttons & ~client->oldbuttons;

	// save light level the player is standing on for
	// monster sighting AI
	ent->light_level = ucmd->lightlevel;

	// fire weapon from final position if needed
	if (client->latched_buttons & BUTTON_ATTACK)
	{
		if (client->resp.spectator) {

			client->latched_buttons = 0;

			if (client->chase_target) {
				client->chase_target = NULL;
				client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
			} else
				GetChaseTarget(ent);

		} else if (!client->weapon_thunk) {
			client->weapon_thunk = true;
			Think_Weapon (ent);
		}
	}

	if (client->resp.spectator) {
		if (ucmd->upmove >= 10) {
			if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) {
				client->ps.pmove.pm_flags |= PMF_JUMP_HELD;
				if (client->chase_target)
					ChaseNext(ent);
				else
					GetChaseTarget(ent);
			}
		} else
			client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD;
	}

	// update chase cam if being followed
	for (i = 1; i <= maxclients->value; i++) {
		other = g_edicts + i;
		if (other->inuse && other->client->chase_target == ent)
			UpdateChaseCam(other);
	}
}
示例#30
0
文件: ai_cast.c 项目: natelo/rtcwPub
/*
============
AICast_CreateCharacter

  returns 0 if unable to create the character
============
*/
gentity_t *AICast_CreateCharacter( gentity_t *ent, float *attributes, cast_weapon_info_t *weaponInfo, char *castname, char *model, char *head, char *sex, char *color, char *handicap )
{
	gentity_t		*newent;
	gclient_t		*client;
	cast_state_t	*cs;
	char			**ppStr;
	int j;

	if (g_gametype.integer != GT_SINGLE_PLAYER)
	{	// no cast AI in multiplayer
		return NULL;
	}
	// are bots enabled?
	if ( !trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
		G_Printf( S_COLOR_RED "ERROR: Unable to spawn %s, 'bot_enable' is not set\n", ent->classname );
		return NULL;
	}
	//
	// make sure we have a free slot for them
	//
	if (level.numPlayingClients+1 > aicast_maxclients)
	{
		G_Error( "Exceeded sv_maxclients (%d), unable to create %s\n", aicast_maxclients, ent->classname );
		return NULL;
	}
	//
	// add it to the list (only do this if everything else passed)
	//

	newent = AICast_AddCastToGame( ent, castname, model, head, sex, color, handicap );

	if (!newent) {
		return NULL;
	}
	client = newent->client;
	//
	// setup the character..
	//
	cs = AICast_GetCastState( newent->s.number );
	//
	// setup the attributes
	memcpy( cs->attributes, attributes, sizeof(cs->attributes) );
	ppStr = &ent->aiAttributes;
	AICast_CheckLevelAttributes( cs, ent, ppStr );
	//
	AICast_SetAASIndex( cs );
	// make sure they face the right direction
	VectorCopy( ent->s.angles, cs->bs->ideal_viewangles );
	// factor in the delta_angles
	for (j = 0; j < 3; j++) {
		cs->bs->viewangles[j] = AngleMod(newent->s.angles[j] - SHORT2ANGLE(newent->client->ps.delta_angles[j]));
	}
	VectorCopy( ent->s.angles, newent->s.angles );
	VectorCopy( ent->s.origin, cs->startOrigin );
	//
	cs->lastEnemy = -1;
	cs->bs->enemy = -1;
	cs->leaderNum = -1;
	cs->castScriptStatus.scriptGotoEnt = -1;
	cs->aiCharacter = ent->aiCharacter;
	//
	newent->aiName = ent->aiName;
	newent->aiTeam = ent->aiTeam;
	newent->targetname = ent->targetname;
	//
	newent->AIScript_AlertEntity = ent->AIScript_AlertEntity;
	newent->aiInactive = ent->aiInactive;
	newent->aiCharacter = cs->aiCharacter;
	//
	// parse the AI script for this character (if applicable)
	cs->aiFlags |= AIFL_CORPSESIGHTING;		// this is on by default for all characters, disabled if they have a "friendlysightcorpse" script event
	AICast_ScriptParse( cs );
	//
	// setup bounding boxes
	//VectorCopy( mins, client->ps.mins );
	//VectorCopy( maxs, client->ps.maxs );
	AIChar_SetBBox( newent, cs );
	client->ps.friction = cs->attributes[RUNNING_SPEED]/300.0;
	//
	// clear weapons/ammo
	client->ps.weapon = 0;
	memcpy( client->ps.weapons, weaponInfo->startingWeapons, sizeof(weaponInfo->startingWeapons) );
	memcpy( client->ps.ammo, weaponInfo->startingAmmo, sizeof(client->ps.ammo) );
	//
	// starting health
	if (ent->health) {
		newent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] = ent->health;
	} else {
		newent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] = cs->attributes[STARTING_HEALTH];
	}
	//
	cs->weaponInfo = weaponInfo;
	//
	cs->lastThink = level.time;
	//
	newent->pain = AICast_Pain;
	newent->die = AICast_Die;
	//
	//update the attack inventory values
	AICast_UpdateBattleInventory(cs, cs->bs->enemy);

//----(SA)	make sure all clips are loaded so we don't hear everyone loading up
//			(we don't want to do this inside AICast_UpdateBattleInventory(), only on spawn or giveweapon)
	for (j=0; j<MAX_WEAPONS; j++) {
		Fill_Clip (&client->ps, j);
	}
//----(SA)	end

	// select a weapon
	AICast_ChooseWeapon( cs, qfalse );

	//
	// set the default function, overwrite if necessary
	cs->aiFlags |= AIFL_JUST_SPAWNED;
	AIFunc_DefaultStart( cs );
	//
	numcast++;
	//
	return newent;
}