static void CG_AddFadeScaleModel( localEntity_t *le ) { refEntity_t *ent = &le->refEntity; float frac = (cg.time - le->startTime) / ((float)(le->endTime - le->startTime)); frac *= frac * frac; // yes, this is completely ridiculous...but it causes the shell to grow slowly then "explode" at the end ent->nonNormalizedAxes = qtrue; AxisCopy( axisDefault, ent->axis ); VectorScale( &ent->axis[0], le->radius*frac, &ent->axis[0] ); VectorScale( &ent->axis[1], le->radius*frac, &ent->axis[1] ); VectorScale( &ent->axis[2], le->radius*0.5f*frac, &ent->axis[2] ); frac = 1.0f - frac; ent->shaderRGBA[0] = le->color[0] * frac; ent->shaderRGBA[1] = le->color[1] * frac; ent->shaderRGBA[2] = le->color[2] * frac; ent->shaderRGBA[3] = le->color[3] * frac; // add the entity SE_R_AddRefEntityToScene( ent, MAX_CLIENTS ); }
/* ================== CG_LaunchGib ================== */ void CG_LaunchGib( vector3 *origin, vector3 *velocity, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 5000 + random() * 3000; VectorCopy( origin, &re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; VectorCopy( origin, &le->pos.trBase ); VectorCopy( velocity, &le->pos.trDelta ); le->pos.trTime = cg.time; le->bounceFactor = 0.6f; le->leBounceSoundType = LEBS_BLOOD; le->leMarkType = LEMT_BLOOD; }
/* ================== CG_LaunchGib ================== */ void CG_LaunchGib( bvec3_t origin, bvec3_t velocity, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 5000 + FIXED_TO_INT(random() * GFIXED(3000,0)); VectorCopy( origin, re->origin ); AxisCopy( aaxisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); le->pos.trTime = cg.time; le->bounceFactor = BFIXED(0,6); le->leBounceSoundType = LEBS_BLOOD; le->leMarkType = LEMT_BLOOD; }
/* ================== CG_LaunchGib ================== */ void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 10000 + random() * 6000; VectorCopy( origin, re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); le->pos.trTime = cg.time; le->bounceFactor = 0.1f; le->leBounceSoundType = LEBS_BRASS; le->leMarkType = LEMT_NONE; }
/* ================== CG_ThrowChunk ================== */ void CG_ThrowChunk( vec3_t origin, vec3_t velocity, qhandle_t hModel, int optionalSound, int startalpha ) { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 5000 + random() * 3000; VectorCopy( origin, re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; le->angles.trType = TR_GRAVITY; VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); VectorSet(le->angles.trBase, 20, 20, 20); VectorCopy( velocity, le->angles.trDelta ); le->pos.trTime = cg.time; le->angles.trTime = cg.time; le->leFlags = LEF_TUMBLE; le->angles.trBase[YAW] = 180; le->bounceFactor = 0.3f; le->bounceSound = optionalSound; le->forceAlpha = startalpha; }
/* ================== CG_LaunchGib ================== */ void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 5000 + random() * 3000; VectorCopy( origin, re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); le->pos.trTime = cg.time; le->bounceFactor = 0.6f; le->leBounceSoundType = LEBS_BLOOD; le->leMarkType = LEMT_BLOOD; if ( cg_leiSuperGoreyAwesome.integer ) { CG_SpurtBlood( origin, velocity, 7); // LEILEI toss some extra juice CG_SpurtBlood( origin, velocity, 22); CG_SpurtBlood( origin, velocity, 11); } }
/* =============== 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 ); } }
/* =============== CG_AttachmentAxis Return the attachment axis =============== */ qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] ) { centity_t *cent; if ( !a ) { return qfalse; } switch ( a->type ) { case AT_STATIC: return qfalse; break; case AT_TAG: if ( !a->tagValid ) { return qfalse; } AxisCopy( a->re.axis, axis ); break; case AT_CENT: if ( !a->centValid ) { return qfalse; } cent = &cg_entities[ a->centNum ]; AnglesToAxis( cent->lerpAngles, axis ); break; case AT_PARTICLE: return qfalse; break; default: CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); break; } return qtrue; }
/* ================== CG_LaunchGib ================== */ void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; //freeze int num; centity_t *cent; //freeze le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 5000 + random() * 3000; VectorCopy( origin, re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; le->pos.trType = TR_GRAVITY; VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); le->pos.trTime = cg.time; le->bounceFactor = 0.6f; le->leBounceSoundType = LEBS_BLOOD; le->leMarkType = LEMT_BLOOD; //freeze for ( num = 0; num < cg.snap->numEntities; num++ ) { cent = &cg_entities[ cg.snap->entities[ num ].number ]; if ( cent->currentState.eventParm != 255 ) continue; if ( VectorCompare( cent->lerpOrigin, origin ) ) { re->customShader = cgs.media.freezeShader; break; } } //freeze }
/* =============== CG_AttachmentPoint Return the attachment point =============== */ qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v ) { centity_t *cent; if ( !a ) { return qfalse; } // if it all breaks, then use the last point we know was correct VectorCopy( a->lastValidAttachmentPoint, v ); switch ( a->type ) { case AT_STATIC: if ( !a->staticValid ) { return qfalse; } VectorCopy( a->origin, v ); break; case AT_TAG: if ( !a->tagValid ) { return qfalse; } AxisCopy( axisDefault, a->re.axis ); CG_PositionRotatedEntityOnTag( &a->re, &a->parent, a->model, a->tagName ); VectorCopy( a->re.origin, v ); break; case AT_CENT: if ( !a->centValid ) { return qfalse; } if ( a->centNum == cg.predictedPlayerState.clientNum ) { // this is smoother if it's the local client VectorCopy( cg.predictedPlayerState.origin, v ); } else { cent = &cg_entities[ a->centNum ]; VectorCopy( cent->lerpOrigin, v ); } break; case AT_PARTICLE: if ( !a->particleValid ) { return qfalse; } if ( !a->particle->valid ) { a->particleValid = qfalse; return qfalse; } else { VectorCopy( a->particle->origin, v ); } break; default: CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); break; } if ( a->hasOffset ) { VectorAdd( v, a->offset, v ); } VectorCopy( v, a->lastValidAttachmentPoint ); return qtrue; }
/* ========================== CG_MachineGunEjectBrass ========================== */ static void CG_MachineGunEjectBrass( centity_t *cent ) { localEntity_t *le; refEntity_t *re; vec3_t velocity, xvelocity; vec3_t offset, xoffset; float waterScale = 1.0f; vec3_t v[3]; if ( cg_brassTime.integer <= 0 ) { return; } le = CG_AllocLocalEntity(); re = &le->refEntity; velocity[0] = 0; velocity[1] = -50 + 40 * crandom(); velocity[2] = 100 + 50 * crandom(); le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random(); le->pos.trType = TR_GRAVITY; le->pos.trTime = cg.time - (rand()&15); AnglesToAxis( cent->lerpAngles, v ); offset[0] = 8; offset[1] = -4; offset[2] = 24; xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; VectorAdd( cent->lerpOrigin, xoffset, re->origin ); VectorCopy( re->origin, le->pos.trBase ); if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { waterScale = 0.10f; } xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; VectorScale( xvelocity, waterScale, le->pos.trDelta ); AxisCopy( axisDefault, re->axis ); re->hModel = cgs.media.machinegunBrassModel; le->bounceFactor = 0.4 * waterScale; le->angles.trType = TR_LINEAR; le->angles.trTime = cg.time; le->angles.trBase[0] = rand()&31; le->angles.trBase[1] = rand()&31; le->angles.trBase[2] = rand()&31; le->angles.trDelta[0] = 2; le->angles.trDelta[1] = 1; le->angles.trDelta[2] = 0; le->leFlags = LEF_TUMBLE; le->leBounceSoundType = LEBS_BRASS; le->leMarkType = LEMT_NONE; }
/* =============== 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 ); } }
/* ================= R_GetPortalOrientation entityNum is the entity that the portal surface is a part of, which may be moving and rotating. Returns qtrue if it should be mirrored ================= */ qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, orientation_t *surface, orientation_t *camera, vec3_t pvsOrigin, qboolean *mirror ) { int i; cplane_t originalPlane, plane; trRefEntity_t *e; float d; vec3_t transformed; // create plane axis for the portal we are seeing R_PlaneForSurface( drawSurf->surface, &originalPlane ); // rotate the plane if necessary if ( entityNum != REFENTITYNUM_WORLD ) { tr.currentEntityNum = entityNum; tr.currentEntity = &tr.refdef.entities[entityNum]; // get the orientation of the entity R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.ori ); // rotate the plane, but keep the non-rotated version for matching // against the portalSurface entities R_LocalNormalToWorld( originalPlane.normal, plane.normal ); plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.ori.origin ); // translate the original plane originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.ori.origin ); } else { plane = originalPlane; } VectorCopy( plane.normal, surface->axis[0] ); PerpendicularVector( surface->axis[1], surface->axis[0] ); CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be // the origin of the camera for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { e = &tr.refdef.entities[i]; if ( e->e.reType != RT_PORTALSURFACE ) { continue; } d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; if ( d > 64 || d < -64) { continue; } // get the pvsOrigin from the entity VectorCopy( e->e.oldorigin, pvsOrigin ); // if the entity is just a mirror, don't use as a camera point if ( e->e.oldorigin[0] == e->e.origin[0] && e->e.oldorigin[1] == e->e.origin[1] && e->e.oldorigin[2] == e->e.origin[2] ) { VectorScale( plane.normal, plane.dist, surface->origin ); VectorCopy( surface->origin, camera->origin ); VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); VectorCopy( surface->axis[1], camera->axis[1] ); VectorCopy( surface->axis[2], camera->axis[2] ); *mirror = qtrue; return qtrue; } // project the origin onto the surface plane to get // an origin point we can rotate around d = DotProduct( e->e.origin, plane.normal ) - plane.dist; VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); // now get the camera origin and orientation VectorCopy( e->e.oldorigin, camera->origin ); AxisCopy( e->e.axis, camera->axis ); VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); // optionally rotate if ( e->e.oldframe ) { // if a speed is specified if ( e->e.frame ) { // continuous rotate d = (tr.refdef.time/1000.0f) * e->e.frame; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } else { // bobbing rotate, with skinNum being the rotation offset d = sin( tr.refdef.time * 0.003f ); d = e->e.skinNum + d * 4; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } } else if ( e->e.skinNum ) { d = e->e.skinNum; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } *mirror = qfalse; return qtrue; } // if we didn't locate a portal entity, don't render anything. // We don't want to just treat it as a mirror, because without a // portal entity the server won't have communicated a proper entity set // in the snapshot // unfortunately, with local movement prediction it is easily possible // to see a surface before the server has communicated the matching // portal surface entity, so we don't want to print anything here... //ri->Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); return qfalse; }
void ME_DrawVehicle( IGME_vehicle_t* veh ) { if( !veh ) return; if( veh->groundInstallation ) { DrawInfo_GI_t drawInfo; memset( &drawInfo, 0, sizeof(drawInfo) ); VectorCopy( veh->angles, drawInfo.basicInfo.angles ); VectorCopy( veh->origin, drawInfo.basicInfo.origin ); AnglesToAxis( veh->angles, drawInfo.basicInfo.axis ); drawInfo.basicInfo.vehicleIndex = veh->vehidx; drawInfo.basicInfo.entityNum = -1; drawInfo.turretAngle = 0; drawInfo.gunAngle = 10; drawInfo.upgrades = availableGroundInstallations[veh->vehidx].upgrades; CG_DrawGI(&drawInfo); } else { switch( availableVehicles[veh->vehidx].cat ) { case CAT_PLANE: { DrawInfo_Plane_t drawInfo; memset( &drawInfo, 0, sizeof(drawInfo) ); VectorCopy( veh->angles, drawInfo.basicInfo.angles ); VectorCopy( veh->origin, drawInfo.basicInfo.origin ); AnglesToAxis( veh->angles, drawInfo.basicInfo.axis ); drawInfo.basicInfo.vehicleIndex = veh->vehidx; drawInfo.basicInfo.entityNum = -1; drawInfo.basicInfo.usedLoadout = &availableLoadouts[veh->vehidx]; CG_DrawPlane(&drawInfo); } break; case CAT_GROUND: { DrawInfo_GV_t drawInfo; memset( &drawInfo, 0, sizeof(drawInfo) ); VectorCopy( veh->angles, drawInfo.basicInfo.angles ); VectorCopy( veh->origin, drawInfo.basicInfo.origin ); AnglesToAxis( veh->angles, drawInfo.basicInfo.axis ); drawInfo.basicInfo.vehicleIndex = veh->vehidx; drawInfo.basicInfo.entityNum = -1; drawInfo.basicInfo.usedLoadout = &availableLoadouts[veh->vehidx]; CG_DrawGV(&drawInfo); } break; case CAT_BOAT: { DrawInfo_Boat_t drawInfo; memset( &drawInfo, 0, sizeof(drawInfo) ); VectorCopy( veh->angles, drawInfo.basicInfo.angles ); VectorCopy( veh->origin, drawInfo.basicInfo.origin ); AnglesToAxis( veh->angles, drawInfo.basicInfo.axis ); drawInfo.basicInfo.vehicleIndex = veh->vehidx; drawInfo.basicInfo.entityNum = -1; drawInfo.basicInfo.usedLoadout = &availableLoadouts[veh->vehidx]; CG_DrawBoat(&drawInfo); } break; case CAT_HELO: break; case CAT_LQM: break; } } // draw selectors if( veh->selected ) { refEntity_t sel; int j; memset( &sel, 0, sizeof(sel) ); sel.hModel = cgs.media.IGME_selector; VectorCopy( veh->origin, sel.origin ); VectorCopy( veh->origin, sel.lightingOrigin ); VectorCopy( veh->origin, sel.oldorigin ); AnglesToAxis( veh->angles, sel.axis ); for( j = 0; j < 3; ++j ) { VectorScale( sel.axis[j], veh->selectorScale[j], sel.axis[j] ); } sel.nonNormalizedAxes = true; refExport.AddRefEntityToScene( &sel ); } // draw waypoints if( cgs.IGME.waypointmode && (veh->selected || cgs.IGME.showAllWaypoints) ) { int k; vec3_t lastpos, dir, ang; VectorCopy( veh->origin, lastpos ); for( k = 0; k < IGME_MAX_WAYPOINTS; ++k ) { refEntity_t wpt, lnk; int l; float dist; if( !veh->waypoints[k].active ) break;//as they are in a row memset( &wpt, 0, sizeof(wpt) ); wpt.hModel = cgs.media.IGME_selector; VectorCopy( veh->waypoints[k].origin, wpt.origin ); VectorCopy( wpt.origin, wpt.lightingOrigin ); VectorCopy( wpt.origin, wpt.oldorigin ); AxisCopy( axisDefault, wpt.axis ); for( l = 0; l < 3; ++l ) { VectorScale( wpt.axis[l], 0.25f, wpt.axis[l] ); } wpt.nonNormalizedAxes = true; if( veh->waypoints[k].selected ) { wpt.customShader = cgs.media.IGME_waypoint; } else { wpt.customShader = cgs.media.IGME_waypoint2; } refExport.AddRefEntityToScene( &wpt ); // draw link VectorSubtract( wpt.origin, lastpos, dir ); dist = VectorNormalize( dir ); dist *= 0.97f; vectoangles( dir, ang ); memset( &lnk, 0, sizeof(lnk) ); lnk.hModel = cgs.media.IGME_selector; VectorMA( lastpos, dist/2, dir, lnk.origin ); VectorCopy( lnk.origin, lnk.lightingOrigin ); VectorCopy( lnk.origin, lnk.oldorigin ); AnglesToAxis( ang, lnk.axis ); VectorScale( lnk.axis[0], dist/200.0f, lnk.axis[0] ); VectorScale( lnk.axis[1], 0.01f, lnk.axis[1] ); VectorScale( lnk.axis[2], 0.01f, lnk.axis[2] ); lnk.nonNormalizedAxes = true; lnk.customShader = cgs.media.IGME_waypoint2; refExport.AddRefEntityToScene( &lnk ); VectorCopy( veh->waypoints[k].origin, lastpos ); } } }
void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins, const vec3_t maxs, float speed, int numChunks, material_t chunkType, int customChunk, float baseScale, int customSound = 0 ) { localEntity_t *le; refEntity_t *re; vec3_t dir; int i, j, k; int chunkModel = 0; leBounceSound_t bounce = LEBS_NONE; float r, speedMod = 1.0f; qboolean chunk = qfalse; if ( chunkType == MAT_NONE ) { // Well, we should do nothing return; } if ( customSound ) { if ( cgs.sound_precache[customSound] ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.sound_precache[customSound] ); } } // Set up our chunk sound info...breaking sounds are done here so they are done once on breaking..some return instantly because the chunks are done with effects instead of models switch( chunkType ) { case MAT_GLASS: if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound ); } return; break; case MAT_GRATE1: if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.grateSound ); } return; break; case MAT_ELECTRICAL:// (sparks) if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgi_S_RegisterSound (va("sound/ambience/spark%d.wav", Q_irand(1, 6))) ); } return; break; case MAT_DRK_STONE: case MAT_LT_STONE: case MAT_GREY_STONE: case MAT_WHITE_METAL: // not quite sure what this stuff is supposed to be...it's for Stu if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.rockBreakSound ); bounce = LEBS_ROCK; } speedMod = 0.5f; // rock blows up less break; case MAT_GLASS_METAL: if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound ); // FIXME: should probably have a custom sound bounce = LEBS_METAL; } break; case MAT_CRATE1: case MAT_CRATE2: if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.crateBreakSound[Q_irand(0,1)] ); } break; case MAT_METAL: case MAT_METAL2: case MAT_METAL3: case MAT_ELEC_METAL:// FIXME: maybe have its own sound? if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.chunkSound ); bounce = LEBS_METAL; } speedMod = 0.8f; // metal blows up a bit more break; case MAT_ROPE: /* if ( !customSound ) { cgi_S_StartSound( NULL, owner, CHAN_BODY, cgi_S_RegisterSound( "" )); FIXME: needs a sound } */ return; default: break; } if ( baseScale <= 0.0f ) { baseScale = 1.0f; } // Chunks for( i = 0; i < numChunks; i++ ) { if ( customChunk > 0 ) { // Try to use a custom chunk. if ( cgs.model_draw[customChunk] ) { chunk = qtrue; chunkModel = cgs.model_draw[customChunk]; } } if ( !chunk ) { // No custom chunk. Pick a random chunk type at run-time so we don't get the same chunks switch( chunkType ) { case MAT_METAL2: //bluegrey chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)]; break; case MAT_GREY_STONE://gray chunkModel = cgs.media.chunkModels[CHUNK_ROCK1][Q_irand(0, 3)]; break; case MAT_LT_STONE: //tan chunkModel = cgs.media.chunkModels[CHUNK_ROCK2][Q_irand(0, 3)]; break; case MAT_DRK_STONE://brown chunkModel = cgs.media.chunkModels[CHUNK_ROCK3][Q_irand(0, 3)]; break; case MAT_WHITE_METAL: chunkModel = cgs.media.chunkModels[CHUNK_WHITE_METAL][Q_irand(0, 3)]; break; case MAT_CRATE1://yellow multi-colored crate chunks chunkModel = cgs.media.chunkModels[CHUNK_CRATE1][Q_irand(0, 3)]; break; case MAT_CRATE2://red multi-colored crate chunks chunkModel = cgs.media.chunkModels[CHUNK_CRATE2][Q_irand(0, 3)]; break; case MAT_ELEC_METAL: case MAT_GLASS_METAL: case MAT_METAL://grey chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)]; break; case MAT_METAL3: if ( rand() & 1 ) { chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)]; } else { chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)]; } break; default: break; } } // It wouldn't look good to throw a bunch of RGB axis models...so make sure we have something to work with. if ( chunkModel ) { le = CG_AllocLocalEntity(); re = &le->refEntity; re->hModel = chunkModel; le->leType = LE_FRAGMENT; le->endTime = cg.time + 1300 + Q_flrand(0.0f, 1.0f) * 900; // spawn chunk roughly in the bbox of the thing...bias towards center in case thing blowing up doesn't complete fill its bbox. for( j = 0; j < 3; j++ ) { r = Q_flrand(0.0f, 1.0f) * 0.8f + 0.1f; re->origin[j] = ( r * mins[j] + ( 1 - r ) * maxs[j] ); } VectorCopy( re->origin, le->pos.trBase ); // Move out from center of thing, otherwise you can end up things moving across the brush in an undesirable direction. Visually looks wrong VectorSubtract( re->origin, origin, dir ); VectorNormalize( dir ); VectorScale( dir, Q_flrand( speed * 0.5f, speed * 1.25f ) * speedMod, le->pos.trDelta ); // Angular Velocity VectorSet( le->angles.trBase, Q_flrand(0.0f, 1.0f) * 360, Q_flrand(0.0f, 1.0f) * 360, Q_flrand(0.0f, 1.0f) * 360 ); le->angles.trDelta[0] = Q_flrand(-1.0f, 1.0f); le->angles.trDelta[1] = Q_flrand(-1.0f, 1.0f); le->angles.trDelta[2] = 0; // don't do roll VectorScale( le->angles.trDelta, Q_flrand(0.0f, 1.0f) * 600.0f + 200.0f, le->angles.trDelta ); le->pos.trType = TR_GRAVITY; le->angles.trType = TR_LINEAR; le->pos.trTime = le->angles.trTime = cg.time; le->bounceFactor = 0.2f + Q_flrand(0.0f, 1.0f) * 0.2f; le->leFlags |= LEF_TUMBLE; le->ownerGentNum = owner; le->leBounceSoundType = bounce; // Make sure that we have the desired start size set le->radius = Q_flrand( baseScale * 0.75f, baseScale * 1.25f ); re->nonNormalizedAxes = qtrue; AxisCopy( axisDefault, re->axis ); // could do an angles to axis, but this is cheaper and works ok for( k = 0; k < 3; k++ ) { VectorScale( re->axis[k], le->radius, re->axis[k] ); } } } }
/* ============== CG_LoseHat ============== */ void CG_LoseHat(centity_t *cent, vec3_t dir) { clientInfo_t *ci; int clientNum; // int i, count, tagIndex, gibIndex; int tagIndex; vec3_t origin, velocity; bg_character_t *character; 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); // don't launch anything if they don't have one if (!character->accModels[ACC_HAT]) { return; } tagIndex = CG_GetOriginForTag(cent, ¢->pe.headRefEnt, "tag_mouth", 0, origin, NULL); velocity[0] = dir[0] * (0.75 + random()) * GIB_VELOCITY; velocity[1] = dir[1] * (0.75 + random()) * GIB_VELOCITY; velocity[2] = GIB_JUMP - 50 + dir[2] * (0.5 + random()) * GIB_VELOCITY; { localEntity_t *le; refEntity_t *re; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->startTime = cg.time; le->endTime = le->startTime + 20000 + (crandom() * 5000); VectorCopy(origin, re->origin); AxisCopy(axisDefault, re->axis); re->hModel = character->accModels[ACC_HAT]; re->customSkin = character->accSkins[ACC_HAT]; re->fadeStartTime = le->endTime - 1000; re->fadeEndTime = le->endTime; // (SA) FIXME: origin of hat md3 is offset from center. need to center the origin when you toss it le->pos.trType = TR_GRAVITY; VectorCopy(origin, le->pos.trBase); VectorCopy(velocity, le->pos.trDelta); le->pos.trTime = cg.time; // spin it a bit le->angles.trType = TR_LINEAR; VectorCopy(tv(0, 0, 0), le->angles.trBase); le->angles.trDelta[0] = 0; le->angles.trDelta[1] = (100 + (rand() & 500)) - 300; // le->angles.trDelta[2] = 0; le->angles.trDelta[2] = 400; // (SA) this is set with a very particular value to try to get it // to flip exactly once before landing (based on player alive // (standing) and on level ground) and will be unnecessary when // I have things landing properly on their own le->angles.trTime = cg.time; le->bounceFactor = 0.2; // Ridah, if the player is on fire, then make the hat on fire if (cent && CG_EntOnFire(cent)) { le->onFireStart = cent->currentState.onFireStart; le->onFireEnd = cent->currentState.onFireEnd + 4000; } } }
void CBulletVolume::render( centity_t& ent ) { entityState_t& es = ent.currentState; if (!(es.groundEntityNum & BVF_ENABLED)) return; // Setup refent. refEntity_t re; memset( &re, 0, sizeof(re) ); re.reType = RT_MODEL; re.renderfx = RF_NOSHADOW; re.hModel = cgs.media.polygonCubeFO; re.nonNormalizedAxes = qtrue; re.customShader = cgs.media.bulletVolumeShader; re.shaderRGBA[3] = byte(es.angles2[2] * 255.0f); switch (es.modelindex) { default: // UNKNWON -> GRAY case 0: re.shaderRGBA[0] = byte(0.5f * 255.0f); re.shaderRGBA[1] = byte(0.5f * 255.0f); re.shaderRGBA[2] = byte(0.5f * 255.0f); break; case 1: // NOHIT -> BLUE re.shaderRGBA[0] = byte(0.0f * 255.0f); re.shaderRGBA[1] = byte(0.0f * 255.0f); re.shaderRGBA[2] = byte(1.0f * 255.0f); break; case 2: // HIT -> RED re.shaderRGBA[0] = byte(1.0f * 255.0f); re.shaderRGBA[1] = byte(0.0f * 255.0f); re.shaderRGBA[2] = byte(0.0f * 255.0f); break; case 3: // REFERENCE NOHIT -> GREEN re.shaderRGBA[0] = byte(0.0f * 255.0f); re.shaderRGBA[1] = byte(1.0f * 255.0f); re.shaderRGBA[2] = byte(0.0f * 255.0f); break; case 4: // REFERENCE HIT -> YELLOW re.shaderRGBA[0] = byte(1.0f * 255.0f); re.shaderRGBA[1] = byte(1.0f * 255.0f); re.shaderRGBA[2] = byte(0.0f * 255.0f); break; } // Apply entity rotation. AxisClear( re.axis ); AnglesToAxis( es.angles, re.axis ); // Apply scaling matrix. vec3_t smatrix[3]; AxisClear( smatrix ); smatrix[0][0] *= es.origin2[0]; smatrix[1][1] *= es.origin2[1]; smatrix[2][2] *= es.origin2[2]; vec3_t tmp[3]; MatrixMultiply( smatrix, re.axis, tmp ); AxisCopy( tmp, re.axis ); // Set origins. VectorCopy( es.origin, re.origin ); VectorCopy( es.origin, re.oldorigin ); VectorCopy( es.origin, re.lightingOrigin ); trap_R_AddRefEntityToScene( &re ); }
/* =============== 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 FX_EnergyGibs(vec3_t origin ) { localEntity_t *le; refEntity_t *re; vec3_t dir; int i, j, k; int chunkModel=0; float baseScale = 0.7f, dist; int numChunks; numChunks = irandom( 10, 15 ); VectorSubtract(cg.snap->ps.origin, origin, dir); dist = VectorLength(dir); if (dist > 512) { numChunks *= 512.0/dist; // 1/2 at 1024, 1/4 at 2048, etc. } for ( i = 0; i < numChunks; i++ ) { chunkModel = cgs.media.chunkModels[MT_METAL][irandom(0,5)]; le = CG_AllocLocalEntity(); re = &le->refEntity; le->leType = LE_FRAGMENT; le->endTime = cg.time + 2000; VectorCopy( origin, re->origin ); for ( j = 0; j < 3; j++ ) { re->origin[j] += crandom() * 12; } VectorCopy( re->origin, le->pos.trBase ); //Velocity VectorSet( dir, crandom(), crandom(), crandom() ); VectorScale( dir, flrandom( 300, 500 ), le->pos.trDelta ); //Angular Velocity VectorSet( le->angles.trBase, crandom() * 360, crandom() * 360, crandom() * 360 ); VectorSet( le->angles.trDelta, crandom() * 90, crandom() * 90, crandom() * 90 ); AxisCopy( axisDefault, re->axis ); le->data.fragment.radius = flrandom(baseScale * 0.4f, baseScale * 0.8f ); re->nonNormalizedAxes = qtrue; re->hModel = chunkModel; re->renderfx |= RF_CAP_FRAMES; re->customShader = cgs.media.quantumDisruptorShader; re->shaderTime = cg.time/1000.0f; le->pos.trType = TR_GRAVITY; le->pos.trTime = cg.time; le->angles.trType = TR_INTERPOLATE; le->angles.trTime = cg.time; le->bounceFactor = 0.2f + random() * 0.2f; le->leFlags |= LEF_TUMBLE; re->shaderRGBA[0] = re->shaderRGBA[1] = re->shaderRGBA[2] = re->shaderRGBA[3] = 255; // Make sure that we have the desired start size set for( k = 0; k < 3; k++) { VectorScale(le->refEntity.axis[k], le->data.fragment.radius, le->refEntity.axis[k]); } } }
/* =============== 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( ); }
static void CG_PlasmaTrail( centity_t *cent, const weaponInfo_t *wi ) { localEntity_t *le; refEntity_t *re; entityState_t *es; vec3_t velocity, xvelocity, origin; vec3_t offset, xoffset; vec3_t v[3]; int t, startTime, step; float waterScale = 1.0f; if ( cg_noProjectileTrail.integer || cg_oldPlasma.integer ) { return; } step = 50; es = ¢->currentState; startTime = cent->trailTime; t = step * ( (startTime + step) / step ); BG_EvaluateTrajectory( &es->pos, cg.time, origin ); le = CG_AllocLocalEntity(); re = &le->refEntity; velocity[0] = 60 - 120 * crandom(); velocity[1] = 40 - 80 * crandom(); velocity[2] = 100 - 200 * crandom(); le->leType = LE_MOVE_SCALE_FADE; le->leFlags = LEF_TUMBLE; le->leBounceSoundType = LEBS_NONE; le->leMarkType = LEMT_NONE; le->startTime = cg.time; le->endTime = le->startTime + 600; le->pos.trType = TR_GRAVITY; le->pos.trTime = cg.time; AnglesToAxis( cent->lerpAngles, v ); offset[0] = 2; offset[1] = 2; offset[2] = 2; xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0]; xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1]; xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2]; VectorAdd( origin, xoffset, re->origin ); VectorCopy( re->origin, le->pos.trBase ); if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) { waterScale = 0.10f; } xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0]; xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1]; xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2]; VectorScale( xvelocity, waterScale, le->pos.trDelta ); AxisCopy( axisDefault, re->axis ); re->shaderTime = cg.time / 1000.0f; re->reType = RT_SPRITE; re->radius = 0.25f; re->customShader = cgs.media.railRingsShader; le->bounceFactor = 0.3f; re->shaderRGBA[0] = wi->flashDlightColor[0] * 63; re->shaderRGBA[1] = wi->flashDlightColor[1] * 63; re->shaderRGBA[2] = wi->flashDlightColor[2] * 63; re->shaderRGBA[3] = 63; le->color[0] = wi->flashDlightColor[0] * 0.2; le->color[1] = wi->flashDlightColor[1] * 0.2; le->color[2] = wi->flashDlightColor[2] * 0.2; le->color[3] = 0.25f; le->angles.trType = TR_LINEAR; le->angles.trTime = cg.time; le->angles.trBase[0] = rand()&31; le->angles.trBase[1] = rand()&31; le->angles.trBase[2] = rand()&31; le->angles.trDelta[0] = 1; le->angles.trDelta[1] = 0.5; le->angles.trDelta[2] = 0; }