/* ================ CG_AddFragment ================ */ void CG_AddFragment( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; if ( le->pos.trType == TR_STATIONARY ) { // sink into the ground if near the removal time int t; float oldZ; t = le->endTime - cg.time; if ( t < SINK_TIME ) { // we must use an explicit lighting origin, otherwise the // lighting would be lost as soon as the origin went // into the ground VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin ); le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; oldZ = le->refEntity.origin[2]; le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME ); CG_AddRefEntityWithMinLight( &le->refEntity ); le->refEntity.origin[2] = oldZ; } else { CG_AddRefEntityWithMinLight( &le->refEntity ); } return; } // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); if ( le->leFlags & LEF_TUMBLE ) { vec3_t angles; BG_EvaluateTrajectory( &le->angles, cg.time, angles ); AnglesToAxis( angles, le->refEntity.axis ); } CG_AddRefEntityWithMinLight( &le->refEntity ); // add a blood trail if ( le->leBounceSoundType == LEBS_BLOOD ) { CG_BloodTrail( le ); } return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { CG_FreeLocalEntity( le ); return; } // leave a mark CG_FragmentBounceMark( le, &trace ); // do a bouncy sound CG_FragmentBounceSound( le, &trace ); // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); CG_AddRefEntityWithMinLight( &le->refEntity ); }
/* ================ CG_AddFragment ================ */ void CG_AddFragment( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; if (le->forceAlpha) { le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA; le->refEntity.shaderRGBA[3] = le->forceAlpha; } if ( le->pos.trType == TR_STATIONARY ) { // sink into the ground if near the removal time int t; float t_e; t = le->endTime - cg.time; if ( t < (SINK_TIME*2) ) { le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA; t_e = (float)((float)(le->endTime - cg.time)/(SINK_TIME*2)); t_e = (int)((t_e)*255); if (t_e > 255) { t_e = 255; } if (t_e < 1) { t_e = 1; } if (le->refEntity.shaderRGBA[3] && t_e > le->refEntity.shaderRGBA[3]) { t_e = le->refEntity.shaderRGBA[3]; } le->refEntity.shaderRGBA[3] = t_e; trap->R_AddRefEntityToScene( &le->refEntity ); } else { trap->R_AddRefEntityToScene( &le->refEntity ); } return; } // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); if ( le->leFlags & LEF_TUMBLE ) { vec3_t angles; BG_EvaluateTrajectory( &le->angles, cg.time, angles ); AnglesToAxis( angles, le->refEntity.axis ); ScaleModelAxis(&le->refEntity); } trap->R_AddRefEntityToScene( &le->refEntity ); // add a blood trail if ( le->leBounceSoundType == LEBS_BLOOD ) { CG_BloodTrail( le ); } return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if ( trap->CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { CG_FreeLocalEntity( le ); return; } if (!trace.startsolid) { // leave a mark CG_FragmentBounceMark( le, &trace ); // do a bouncy sound CG_FragmentBounceSound( le, &trace ); if (le->bounceSound) { //specified bounce sound (debris) trap->S_StartSound(le->pos.trBase, ENTITYNUM_WORLD, CHAN_AUTO, le->bounceSound); } // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); trap->R_AddRefEntityToScene( &le->refEntity ); } }
/* ================ CG_AddFragment ================ */ void CG_AddFragment( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; refEntity_t *re; float flameAlpha = 0.0; // TTimo: init vec3_t flameDir; qboolean hasFlame = qfalse; int i; // Ridah re = &le->refEntity; if (!re->fadeStartTime || re->fadeEndTime < le->endTime) { if (le->endTime - cg.time > 5000) { re->fadeStartTime = le->endTime - 5000; } else { re->fadeStartTime = le->endTime - 1000; } re->fadeEndTime = le->endTime; } // Ridah, flaming gibs if (le->onFireStart && (le->onFireStart < cg.time && le->onFireEnd > cg.time)) { hasFlame = qtrue; // calc the alpha flameAlpha = 1.0 - ((float)(cg.time - le->onFireStart)/(float)(le->onFireEnd - le->onFireStart)); if (flameAlpha < 0.0) flameAlpha = 0.0; if (flameAlpha > 1.0) flameAlpha = 1.0; trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameCrackSound, (int)(20.0*flameAlpha) ); } //----(SA) added if(le->leFlags & LEF_SMOKING) { float alpha; refEntity_t flash; // create a little less smoke // TODO: FIXME: this is not quite right, because it'll become fps dependant - in a bad way. // the slower the fps, the /more/ smoke there'll be, probably driving the fps lower. if(!(rand()%5)) { alpha = 1.0 - ((float)(cg.time - le->startTime)/(float)(le->endTime - le->startTime)); alpha *= 0.25f; memset (&flash, 0, sizeof (flash)); CG_PositionEntityOnTag( &flash, &le->refEntity, "tag_flash", 0, NULL); CG_ParticleImpactSmokePuffExtended(cgs.media.smokeParticleShader, flash.origin, 1000, 8, 20, 20, alpha); } } //----(SA) end if ( le->pos.trType == TR_STATIONARY ) { int t; // Ridah, add the flame if (hasFlame) { refEntity_t backupEnt; backupEnt = le->refEntity; VectorClear( flameDir ); flameDir[2] = 1; le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha); VectorCopy( flameDir, le->refEntity.fireRiseDir ); le->refEntity.customShader = cgs.media.onFireShader; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.customShader = cgs.media.onFireShader2; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity = backupEnt; } t = le->endTime - cg.time; trap_R_AddRefEntityToScene( &le->refEntity ); return; } else if ( le->pos.trType == TR_GRAVITY_PAUSED ) { int t; // Ridah, add the flame if (hasFlame) { refEntity_t backupEnt; backupEnt = le->refEntity; VectorClear( flameDir ); flameDir[2] = 1; le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha); VectorCopy( flameDir, le->refEntity.fireRiseDir ); le->refEntity.customShader = cgs.media.onFireShader; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.customShader = cgs.media.onFireShader2; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity = backupEnt; } t = le->endTime - cg.time; trap_R_AddRefEntityToScene( &le->refEntity ); // trace a line from previous position down, to see if I should start falling again VectorCopy(le->refEntity.origin, newOrigin); newOrigin [2] -= 5; CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MISSILECLIP ); if(trace.fraction == 1.0) // it's clear, start moving again { VectorClear(le->pos.trDelta); VectorClear(le->angles.trDelta); le->pos.trType = TR_GRAVITY; // nothing below me, start falling again } else return; } // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); if (hasFlame) { // calc the flame dir VectorSubtract( le->refEntity.origin, newOrigin, flameDir ); if (VectorLength( flameDir ) == 0) { flameDir[2] = 1; // play a burning sound when not moving trap_S_AddLoopingSound( 0, newOrigin, vec3_origin, cgs.media.flameSound, (int)(0.3*255.0*flameAlpha) ); } else { VectorNormalize( flameDir ); // play a flame blow sound when moving trap_S_AddLoopingSound( 0, newOrigin, vec3_origin, cgs.media.flameBlowSound, (int)(0.3*255.0*flameAlpha) ); } } // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); if ( le->leFlags & LEF_TUMBLE || le->angles.trType == TR_LINEAR) { vec3_t angles; BG_EvaluateTrajectory( &le->angles, cg.time, angles ); AnglesToAxis( angles, le->refEntity.axis ); if (le->sizeScale && le->sizeScale != 1.0) { for (i=0;i<3;i++) VectorScale( le->refEntity.axis[i], le->sizeScale, le->refEntity.axis[i] ); } } // Ridah, add the flame if (hasFlame) { refEntity_t backupEnt; backupEnt = le->refEntity; le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha); VectorCopy( flameDir, le->refEntity.fireRiseDir ); le->refEntity.customShader = cgs.media.onFireShader; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.customShader = cgs.media.onFireShader2; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity = backupEnt; } trap_R_AddRefEntityToScene( &le->refEntity ); // add a blood trail if ( le->leBounceSoundType == LEBS_BLOOD ) { CG_BloodTrail( le ); } return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { CG_FreeLocalEntity( le ); return; } // do a bouncy sound CG_FragmentBounceSound( le, &trace ); // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); // break on contact? if (le->breakCount) { clientInfo_t *ci; int clientNum; localEntity_t *nle; vec3_t dir; clientNum = le->ownerNum; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { CG_Error( "Bad clientNum on player entity"); } ci = &cgs.clientinfo[ clientNum ]; // spawn some new fragments for (i=0;i<=le->breakCount;i++) { nle = CG_AllocLocalEntity(); memcpy( &(nle->leType), &(le->leType), sizeof(localEntity_t) - 2*sizeof(localEntity_t *) ); if (nle->breakCount-- < 2) nle->refEntity.hModel = ci->gibModels[rand()%2]; else nle->refEntity.hModel = ci->gibModels[rand()%4]; // make it smaller nle->endTime = cg.time + 5000 + rand()%2000; nle->sizeScale *= 0.8; if (nle->sizeScale < 0.7) { nle->sizeScale = 0.7; nle->leBounceSoundType = 0; } // move us a bit VectorNormalize2( nle->pos.trDelta, dir ); VectorMA( trace.endpos, 4.0*le->sizeScale*i, dir, nle->pos.trBase ); // randomize vel a bit VectorMA( nle->pos.trDelta, VectorLength(nle->pos.trDelta)*0.3, bytedirs[rand()%NUMVERTEXNORMALS], nle->pos.trDelta ); } // we're done CG_FreeLocalEntity( le ); return; } if (le->pos.trType == TR_STATIONARY && le->leMarkType == LEMT_BLOOD) { // RF, disabled for performance reasons in boss1 //if (le->leBounceSoundType) // CG_BloodPool (le, cgs.media.bloodPool, &trace); // leave a mark if (le->leMarkType) CG_FragmentBounceMark( le, &trace ); } // Ridah, add the flame if (hasFlame) { refEntity_t backupEnt; backupEnt = le->refEntity; le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha); VectorCopy( flameDir, le->refEntity.fireRiseDir ); le->refEntity.customShader = cgs.media.onFireShader; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.customShader = cgs.media.onFireShader2; trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity = backupEnt; } trap_R_AddRefEntityToScene( &le->refEntity ); }
/* ================ CG_AddDebrisElements ================ */ void CG_AddDebrisElements( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; float lifeFrac; int t, step = 50; for (t = le->lastTrailTime + step; t < cg.time; t += step) { // calculate new position BG_EvaluateTrajectory( &le->pos, t, newOrigin ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, MASK_SHOT ); // if stuck, kill it if (trace.startsolid) { // HACK, some walls screw up, so just pass through if starting in a solid VectorCopy( newOrigin, trace.endpos ); trace.fraction = 1.0; } // moved some distance VectorCopy( trace.endpos, le->refEntity.origin ); // add a trail lifeFrac = (float)(t - le->startTime) / (float)(le->endTime - le->startTime); #if 0 // fire #if 1 // flame if (le->effectWidth > 0) { le->headJuncIndex = CG_AddSparkJunc( le->headJuncIndex, cgs.media.fireTrailShader, le->refEntity.origin, (int)(500.0 * (0.5 + 0.5*(1.0 - lifeFrac))), // trail life 1.0, // alpha 0.5, // end alpha 3, // start width le->effectWidth ); // end width #else // spark line if (le->effectWidth > 0) { le->headJuncIndex = CG_AddSparkJunc( le->headJuncIndex, cgs.media.sparkParticleShader, le->refEntity.origin, (int)(600.0 * (0.5 + 0.5*(0.5 - lifeFrac))), // trail life 1.0 - lifeFrac*2, // alpha 0.5 * (1.0 - lifeFrac), // end alpha 5.0 * (1.0 - lifeFrac), // start width 5.0 * (1.0 - lifeFrac) ); // end width #endif } #endif // smoke if (le->effectFlags & 1) { le->headJuncIndex2 = CG_AddSmokeJunc( le->headJuncIndex2, cgs.media.smokeTrailShader, le->refEntity.origin, (int)(2000.0 * (0.5 + 0.5*(1.0 - lifeFrac))), // trail life 1.0 * (trace.fraction == 1.0) * (0.5 + 0.5 * (1.0 - lifeFrac)), // alpha 1, // start width (int)(60.0 * (0.5 + 0.5*(1.0 - lifeFrac))) ); // end width } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels // if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { // CG_FreeLocalEntity( le ); // return; // } if (trace.fraction < 1.0) { // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); if (VectorLength(le->pos.trDelta) < 1) { CG_FreeLocalEntity( le ); return; } // the intersection is a fraction of the frametime le->pos.trTime = t; } le->lastTrailTime = t; } } // Rafael Shrapnel /* =============== CG_AddShrapnel =============== */ void CG_AddShrapnel (localEntity_t *le) { vec3_t newOrigin; trace_t trace; if ( le->pos.trType == TR_STATIONARY ) { // sink into the ground if near the removal time int t; float oldZ; t = le->endTime - cg.time; if ( t < SINK_TIME ) { // we must use an explicit lighting origin, otherwise the // lighting would be lost as soon as the origin went // into the ground VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin ); le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; oldZ = le->refEntity.origin[2]; le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME ); trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.origin[2] = oldZ; } else { trap_R_AddRefEntityToScene( &le->refEntity ); CG_AddParticleShrapnel (le); } return; } // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); if ( le->leFlags & LEF_TUMBLE ) { vec3_t angles; BG_EvaluateTrajectory( &le->angles, cg.time, angles ); AnglesToAxis( angles, le->refEntity.axis ); } trap_R_AddRefEntityToScene( &le->refEntity ); CG_AddParticleShrapnel (le); return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { CG_FreeLocalEntity( le ); return; } // leave a mark CG_FragmentBounceMark( le, &trace ); // do a bouncy sound CG_FragmentBounceSound( le, &trace ); // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); trap_R_AddRefEntityToScene( &le->refEntity ); CG_AddParticleShrapnel (le); }
/* ======================================================================================================================================= CG_AddFragment ======================================================================================================================================= */ void CG_AddFragment(localEntity_t *le) { vec3_t newOrigin, angles; trace_t trace; if (le->pos.trType == TR_STATIONARY) { // sink into the ground if near the removal time int t; float oldZ; CG_AdjustPositionForMover(le->refEntity.origin, le->groundEntityNum, le->pos.trTime, cg.time, le->refEntity.origin, le->angles.trBase, le->angles.trBase); AnglesToAxis(le->angles.trBase, le->refEntity.axis); le->pos.trTime = cg.time; t = le->endTime - cg.time; if (t < SINK_TIME) { // we must use an explicit lighting origin, otherwise the lighting would be lost as soon as the origin went into the ground VectorCopy(le->refEntity.origin, le->refEntity.lightingOrigin); le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; oldZ = le->refEntity.origin[2]; le->refEntity.origin[2] -= 16 * (1.0 - (float)t / SINK_TIME); trap_R_AddRefEntityToScene(&le->refEntity); le->refEntity.origin[2] = oldZ; } else { trap_R_AddRefEntityToScene(&le->refEntity); } return; } // never free fragments while they're flying if (le->endTime < cg.time + 2000) { le->endTime = cg.time + 2000; } // calculate new position BG_EvaluateTrajectory(&le->pos, cg.time, newOrigin); // trace a line from previous position to new position CG_Trace(&trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID); if (trace.fraction == 1.0) { // still in free fall VectorCopy(newOrigin, le->refEntity.origin); VectorClear(angles); switch (le->leFlags) { case LEF_TUMBLE: BG_EvaluateTrajectory(&le->angles, cg.time, angles); break; case LEF_GIBS: angles[1] = ((cg.time & 2047) * 360 / 2048.0 + 120); angles[0] = ((cg.time & 2047) * 360 / 2048.0); angles[2] = ((cg.time & 2047) * 360 / 2048.0 + 240); break; default: break; } AnglesToAxis(angles, le->refEntity.axis); trap_R_AddRefEntityToScene(&le->refEntity); // add a blood trail if (le->leBounceSoundType == LEBS_BLOOD) { CG_BloodTrail(le); } return; } // fragment inside mover, find the direction/origin of impact if (trace.allsolid && cg_entities[trace.entityNum].currentState.eType == ET_MOVER) { vec3_t origin, angles, dir; float dist; int oldTime; trace_t tr; // get last location if (cg.time == le->pos.trTime) { // fragment was added this frame. no good way to fix this. CG_FreeLocalEntity(le); return; } else { oldTime = le->pos.trTime; } BG_EvaluateTrajectory(&le->pos, oldTime, origin); VectorClear(angles); // add the distance mover has moved since then CG_AdjustPositionForMover(origin, trace.entityNum, oldTime, cg.time, origin, angles, angles); // nudge the origin farther to avoid being co-planar VectorSubtract(origin, newOrigin, dir); dist = VectorNormalize(dir); VectorMA(origin, dist, dir, origin); CG_Trace(&tr, origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID); // found impact. restore allsolid because trace fraction won't work correct in CG_ReflectVelocity if (!tr.allsolid) { trace = tr; trace.allsolid = qtrue; } } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death and floating levels if (CG_PointContents(trace.endpos, 0) & CONTENTS_NODROP) { CG_FreeLocalEntity(le); return; } // leave a mark CG_FragmentBounceMark(le, &trace); // do a bouncy sound CG_FragmentBounceSound(le, &trace); // reflect the velocity on the trace plane CG_ReflectVelocity(le, &trace); trap_R_AddRefEntityToScene(&le->refEntity); }
/* ================ CG_AddFragment ================ */ void CG_AddFragment(localEntity_t * le) { vec3_t newOrigin; trace_t trace; if(le->pos.trType == TR_STATIONARY) { // sink into the ground if near the removal time int t; float oldZ; t = le->endTime - cg.time; if(t < SINK_TIME) { // we must use an explicit lighting origin, otherwise the // lighting would be lost as soon as the origin went // into the ground VectorCopy(le->refEntity.origin, le->refEntity.lightingOrigin); le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; oldZ = le->refEntity.origin[2]; le->refEntity.origin[2] -= 16 * (1.0 - (float)t / SINK_TIME); trap_R_AddRefEntityToScene(&le->refEntity); le->refEntity.origin[2] = oldZ; } else { trap_R_AddRefEntityToScene(&le->refEntity); } return; } // calculate new position BG_EvaluateTrajectory(&le->pos, cg.time, newOrigin); // trace a line from previous position to new position CG_Trace(&trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID); if(trace.fraction == 1.0) { // still in free fall VectorCopy(newOrigin, le->refEntity.origin); if(le->leFlags & LEF_TUMBLE) { #if 0 vec3_t angles; BG_EvaluateTrajectory(&le->angles, cg.time, angles); AnglesToAxis(angles, le->refEntity.axis); #else // Tr3B - new quaternion code quat_t qrot; // angular rotation for this frame float angle = le->angVel * (cg.time - le->angles.trTime) * 0.001 / 2; // create the rotation quaternion qrot[3] = cos(angle); // real part VectorScale(le->rotAxis, sin(angle), qrot); // imaginary part QuatNormalize(qrot); // create the new orientation QuatMultiply0(le->quatOrient, qrot); // apply the combined previous rotations around other axes QuatMultiply1(le->quatOrient, le->quatRot, qrot); // convert the orientation into the form the renderer wants QuatToAxis(qrot, le->refEntity.axis); le->angles.trTime = cg.time; #endif } trap_R_AddRefEntityToScene(&le->refEntity); // add a blood trail if(le->leBounceSoundType == LEBS_BLOOD) { CG_BloodTrail(le); } return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if(trap_CM_PointContents(trace.endpos, 0) & CONTENTS_NODROP) { CG_FreeLocalEntity(le); return; } // leave a mark CG_FragmentBounceMark(le, &trace); // do a bouncy sound CG_FragmentBounceSound(le, &trace); // reflect the velocity on the trace plane CG_ReflectVelocity(le, &trace); trap_R_AddRefEntityToScene(&le->refEntity); }
/* ================ CG_AddFragment ================ */ void CG_AddFragment( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; if ( le->pos.trType == TR_STATIONARY ) { // sink into the ground if near the removal time int t; float oldZ; t = le->endTime - cg.time; if ( t < SINK_TIME ) { // we must use an explicit lighting origin, otherwise the // lighting would be lost as soon as the origin went // into the ground VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin ); le->refEntity.renderfx |= RF_LIGHTING_ORIGIN; oldZ = le->refEntity.origin[2]; le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME ); trap_R_AddRefEntityToScene( &le->refEntity ); le->refEntity.origin[2] = oldZ; } else { trap_R_AddRefEntityToScene( &le->refEntity ); } return; } // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); // trace a line from previous position to new position CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { qboolean inWater; vec3_t newDelta; // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); // check for water inWater = CG_PointContents( newOrigin, -1 ) & CONTENTS_WATER; if ( inWater && le->pos.trType == TR_GRAVITY ) { BG_EvaluateTrajectoryDelta( &le->pos, cg.time, newDelta ); le->pos.trType = TR_WATER_GRAVITY; VectorCopy( newOrigin, le->pos.trBase ); VectorCopy( newDelta, le->pos.trDelta ); le->pos.trTime = cg.time; } if ( !inWater && le->pos.trType == TR_WATER_GRAVITY ) { BG_EvaluateTrajectoryDelta( &le->pos, cg.time, newDelta ); le->pos.trType = TR_GRAVITY; VectorCopy( newOrigin, le->pos.trBase ); VectorCopy( newDelta, le->pos.trDelta ); le->pos.trTime = cg.time; } if ( le->leFlags & LEF_TUMBLE ) { vec3_t angles; BG_EvaluateTrajectory( &le->angles, cg.time, angles ); AnglesToAxis( angles, le->refEntity.axis ); } trap_R_AddRefEntityToScene( &le->refEntity ); // add a fire trail // CG_FireTrail( le ); return; } // if it is in a nodrop zone, remove it // this keeps gibs from waiting at the bottom of pits of death // and floating levels if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) { CG_FreeLocalEntity( le ); return; } // stop rotation le->angles.trType = TR_STATIONARY; // leave a mark CG_FragmentBounceMark( le, &trace ); // reflect the velocity on the trace plane CG_ReflectVelocity( le, &trace ); trap_R_AddRefEntityToScene( &le->refEntity ); }