/* =============== CG_smoothWJTransitions =============== */ static void CG_smoothWJTransitions( playerState_t *ps, const vec3_t in, vec3_t out ) { int i; float stLocal, sFraction; qboolean performed = qfalse; vec3_t inAxis[ 3 ], outAxis[ 3 ]; Q_UNUSED(ps); if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { VectorCopy( in, out ); return; } AnglesToAxis( in, inAxis ); //iterate through ops for ( i = MAXSMOOTHS - 1; i >= 0; i-- ) { //if this op has time remaining, perform it if ( cg.time < cg.sList[ i ].time + cg_wwSmoothTime.integer ) { stLocal = ( ( cg.sList[ i ].time + cg_wwSmoothTime.integer ) - cg.time ) / cg_wwSmoothTime.integer; sFraction = 1.0f - ( ( cos( stLocal * M_PI * 2.0f ) + 1.0f ) / 2.0f ); RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis, inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis, inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis, inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle ); AxisCopy( outAxis, inAxis ); performed = qtrue; } } //if we performed any ops then return the smoothed angles //otherwise simply return the in angles if ( performed ) { AxisToAngles( outAxis, out ); } else { VectorCopy( in, out ); } }
bool HoldableItemExplosive::findPlaceToSet( Vector &newOrigin, Vector &newAngles ) { Player *player; trace_t viewTrace; Vector forward; Vector left; Vector up; float axis[3][3]; vec3_t newAnglesVec; if ( !_owner || !_owner->isSubclassOf( Player ) ) return false; player = (Player *)_owner; memset( &viewTrace, 0, sizeof(trace_t) ); player->GetViewTrace( viewTrace, MASK_SHOT, 16.0f * 7.0f ); if ( ( viewTrace.fraction < 1.0f ) && ( viewTrace.ent && viewTrace.entityNum == ENTITYNUM_WORLD ) ) { newOrigin = viewTrace.endpos; up = viewTrace.plane.normal; PerpendicularVector( forward, viewTrace.plane.normal ); left.CrossProduct( up, forward ); forward.copyTo( axis[ AXIS_FORWARD_VECTOR ] ); left.copyTo( axis[ AXIS_RIGHT_VECTOR ] ); up.copyTo( axis[ AXIS_UP_VECTOR ] ); AxisToAngles( axis, newAnglesVec ); newAngles = newAnglesVec; return true; } return false; }
/* ============= PhysicsEntitySetTransform ============= */ static void PhysicsEntitySetTransform ( const NewtonBody* body, const dFloat* matrix, int threadIndex ) { if(com_sv_running->integer) { sharedEntity_t *ent = (sharedEntity_t*)NewtonBodyGetUserData (body); vec3_t newPosition, angles, axis[3]; SV_UnlinkEntity (ent); newPosition[0] = matrix[12]; newPosition[1] = matrix[13]; newPosition[2] = matrix[14]; // update the origin. VectorScale (newPosition, METRES_PER_UNIT, newPosition); VectorCopy (newPosition, ent->s.pos.trBase); VectorCopy (newPosition, ent->r.currentOrigin); VectorCopy (newPosition, ent->s.origin); axis[0][0] = matrix[0]; axis[0][1] = matrix[1]; axis[0][2] = matrix[2]; axis[1][0] = matrix[4]; axis[1][1] = matrix[5]; axis[1][2] = matrix[6]; axis[2][0] = matrix[8]; axis[2][1] = matrix[9]; axis[2][2] = matrix[10]; AxisToAngles (axis, angles); VectorCopy (angles, ent->s.apos.trBase); VectorCopy (angles, ent->r.currentAngles); VectorCopy (angles, ent->s.angles); SV_LinkEntity (ent); #if defined(_DEBUG) Com_Printf ("PHYSICS: updating %d new position %s\n", ent->s.number, vtos (newPosition)); #endif } }
/* =============== 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( ); }
/* =============== 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 ); } }
/* =============== CG_smoothWWTransitions =============== */ static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t out ) { vec3_t surfNormal, rotAxis, temp; vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; int i; float stLocal, sFraction, rotAngle; float smoothTime, timeMod; qboolean performed = qfalse; vec3_t inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ]; if( cg.snap->ps.pm_flags & PMF_FOLLOW ) { VectorCopy( in, out ); return; } //set surfNormal BG_GetClientNormal( ps, surfNormal ); AnglesToAxis( in, inAxis ); //if we are moving from one surface to another smooth the transition if( !VectorCompare( surfNormal, cg.lastNormal ) ) { //if we moving from the ceiling to the floor special case //( x product of colinear vectors is undefined) if( VectorCompare( ceilingNormal, cg.lastNormal ) && VectorCompare( refNormal, surfNormal ) ) { AngleVectors( in, temp, NULL, NULL ); ProjectPointOnPlane( rotAxis, temp, refNormal ); VectorNormalize( rotAxis ); rotAngle = 180.0f; timeMod = 1.5f; } else { AnglesToAxis( cg.lastVangles, lastAxis ); rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) + DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) + DotProduct( inAxis[ 2 ], lastAxis[ 2 ] ); rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) ); CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp ); VectorCopy( temp, rotAxis ); CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp ); VectorAdd( rotAxis, temp, rotAxis ); CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp ); VectorAdd( rotAxis, temp, rotAxis ); VectorNormalize( rotAxis ); timeMod = 1.0f; } //add the op CG_addSmoothOp( rotAxis, rotAngle, timeMod ); } //iterate through ops for( i = MAXSMOOTHS - 1; i >= 0; i-- ) { smoothTime = (int)( cg_wwSmoothTime.integer * cg.sList[ i ].timeMod ); //if this op has time remaining, perform it if( cg.time < cg.sList[ i ].time + smoothTime ) { stLocal = 1.0f - ( ( ( cg.sList[ i ].time + smoothTime ) - cg.time ) / smoothTime ); sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f; RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis, inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis, inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle ); RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis, inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle ); AxisCopy( outAxis, inAxis ); performed = qtrue; } } //if we performed any ops then return the smoothed angles //otherwise simply return the in angles if( performed ) AxisToAngles( outAxis, out ); else VectorCopy( in, out ); //copy the current normal to the lastNormal VectorCopy( in, cg.lastVangles ); VectorCopy( surfNormal, cg.lastNormal ); }
void CG_GibPlayer(centity_t *cent, vec3_t playerOrigin, vec3_t gdir) { int i, count = 0, tagIndex, gibIndex; vec3_t origin, velocity, dir; trace_t trace; qboolean foundtag; clientInfo_t *ci; int clientNum; bg_character_t *character; vec4_t projection, color; // Rafael // BloodCloud qboolean newjunction[MAXJUNCTIONS]; vec3_t junctionOrigin[MAXJUNCTIONS]; int junction; int j; vec3_t axis[3], angles; char *JunctiongibTags[] = { // leg tag "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", // torsotags "tag_armright", "tag_armleft", "tag_torso", "tag_chest" }; char *ConnectTags[] = { // legs tags "tag_legright", "tag_legleft", "tag_torso", "tag_torso", // torso tags "tag_chest", "tag_chest", "tag_chest", "tag_torso", }; char *gibTags[] = { // tags in the legs "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", "tag_torso", // tags in the torso "tag_chest", "tag_armright", "tag_armleft", "tag_head", NULL }; if (cg_blood.integer) { // Rafael for (i = 0; i < MAXJUNCTIONS; i++) newjunction[i] = qfalse; clientNum = cent->currentState.clientNum; if (clientNum < 0 || clientNum >= MAX_CLIENTS) { CG_Error("Bad clientNum on player entity"); } ci = &cgs.clientinfo[clientNum]; character = CG_CharacterForClientinfo(ci, cent); // Ridah, fetch the various positions of the tag_gib*'s // and spawn the gibs from the correct places (especially the head) for (gibIndex = 0, count = 0, foundtag = qtrue; foundtag && gibIndex < MAX_GIB_MODELS && gibTags[gibIndex]; gibIndex++) { refEntity_t *re = 0; foundtag = qfalse; if (!character->gibModels[gibIndex]) { continue; } re = ¢->pe.bodyRefEnt; for (tagIndex = 0; (tagIndex = CG_GetOriginForTag(cent, re, gibTags[gibIndex], tagIndex, origin, axis)) >= 0; count++, tagIndex++) { foundtag = qtrue; VectorSubtract(origin, re->origin, dir); VectorNormalize(dir); // spawn a gib velocity[0] = dir[0] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[1] = dir[1] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[2] = GIB_JUMP + dir[2] * (0.5 + random()) * GIB_VELOCITY * 0.5; VectorMA(velocity, GIB_VELOCITY, gdir, velocity); AxisToAngles(axis, angles); CG_LaunchGib(cent, origin, angles, velocity, character->gibModels[gibIndex], 1.0, 0); for (junction = 0; junction < MAXJUNCTIONS; junction++) { if (!Q_stricmp(gibTags[gibIndex], JunctiongibTags[junction])) { VectorCopy(origin, junctionOrigin[junction]); newjunction[junction] = qtrue; } } } } for (i = 0; i < MAXJUNCTIONS; i++) { if (newjunction[i] == qtrue) { for (j = 0; j < MAXJUNCTIONS; j++) { if (!Q_stricmp(JunctiongibTags[j], ConnectTags[i])) { if (newjunction[j] == qtrue) { // spawn a blood cloud somewhere on the vec from VectorSubtract(junctionOrigin[i], junctionOrigin[j], dir); CG_ParticleBloodCloud(cent, junctionOrigin[i], dir); } } } } } // Ridah, spawn a bunch of blood dots around the place #define GIB_BLOOD_DOTS 3 for (i = 0, count = 0; i < GIB_BLOOD_DOTS * 2; i++) { // TTimo: unused //static vec3_t mins = {-10,-10,-10}; //static vec3_t maxs = { 10, 10, 10}; if (i > 0) { velocity[0] = ((i % 2) * 2 - 1) * (40 + 40 * random()); velocity[1] = (((i / 2) % 2) * 2 - 1) * (40 + 40 * random()); velocity[2] = (((i < GIB_BLOOD_DOTS) * 2) - 1) * 40; } else { VectorClear(velocity); velocity[2] = -64; } VectorAdd(playerOrigin, velocity, origin); CG_Trace(&trace, playerOrigin, NULL, NULL, origin, -1, CONTENTS_SOLID); if (trace.fraction < 1.0) { //% BG_GetMarkDir( velocity, trace.plane.normal, velocity ); //% CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace.endpos, velocity, random()*360, //% 1,1,1,1, qtrue, 30, qfalse, cg_bloodTime.integer * 1000 ); #if 0 BG_GetMarkDir(velocity, trace.plane.normal, projection); VectorSubtract(vec3_origin, projection, projection); projection[3] = 64; VectorMA(trace.endpos, -8.0f, projection, markOrigin); CG_ImpactMark(cgs.media.bloodDotShaders[rand() % 5], markOrigin, projection, 30.0f, random() * 360.0f, 1.0f, 1.0f, 1.0f, 1.0f, cg_bloodTime.integer * 1000); #else VectorSet(projection, 0, 0, -1); projection[3] = 30.0f; Vector4Set(color, 1.0f, 1.0f, 1.0f, 1.0f); trap_R_ProjectDecal(cgs.media.bloodDotShaders[rand() % 5], 1, (vec3_t *) trace.endpos, projection, color, cg_bloodTime.integer * 1000, (cg_bloodTime.integer * 1000) >> 4); #endif if (count++ > GIB_BLOOD_DOTS) { break; } } } }