diff --git a/code/cgame/cg_localents.c b/code/cgame/cg_localents.c index 45535ab7..3ffa5bf8 100644 --- a/code/cgame/cg_localents.c +++ b/code/cgame/cg_localents.c @@ -217,6 +217,24 @@ void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) { } } +static void GetFragmentMinsMaxs( const localEntity_t *le, vec3_t mins, vec3_t maxs ) { + VectorCopy( vec3_origin, mins ); + VectorCopy( vec3_origin, maxs ); + + // can't use `le->leBounceSoundType` because for brass it gets unset + // after first impact + if ( le->refEntity.hModel == cgs.media.machinegunBrassModel ) { + // The primary point of this is to ensure + // that they don't half-sink into the the ground. + // Same for shotgun. + VectorSet(mins, -1, -1, -0.2); + VectorSet(maxs, 1, 1, 0.2); + } else if ( le->refEntity.hModel == cgs.media.shotgunBrassModel ) { + VectorSet(mins, -1, -1, -0.5); + VectorSet(maxs, 1, 1, 0.5); + } +} + /* ================ CG_AddFragment @@ -225,6 +243,11 @@ CG_AddFragment static void CG_AddFragment( localEntity_t *le ) { vec3_t newOrigin; trace_t trace; + vec3_t mins; + vec3_t maxs; + + VectorCopy( vec3_origin, mins ); + VectorCopy( vec3_origin, maxs ); if ( le->pos.trType == TR_STATIONARY ) { // sink into the ground if near the removal time @@ -252,8 +275,9 @@ static void CG_AddFragment( localEntity_t *le ) { // calculate new position BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin ); + GetFragmentMinsMaxs( le, mins, maxs ); // trace a line from previous position to new position - CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID ); + CG_Trace( &trace, le->refEntity.origin, mins, maxs, newOrigin, -1, CONTENTS_SOLID ); if ( trace.fraction == 1.0 ) { // still in free fall VectorCopy( newOrigin, le->refEntity.origin ); @@ -283,6 +307,22 @@ static void CG_AddFragment( localEntity_t *le ) { return; } + // stop pitch spin so that when it settles it lies flat on the ground + if ( le->leBounceSoundType == LEBS_BRASS ) { + // save current as base + BG_EvaluateTrajectory( &le->angles, cg.time, le->angles.trBase ); + le->angles.trTime = cg.time; + + // "fall over" to nearest horizontal orientation + // + // FIXME: handle non-horizontal surfaces (see `trace.plane.normal`) + // (YAW would need to be taken into account then) + le->angles.trBase[PITCH] = 90 + 180 * floor( le->angles.trBase[PITCH] / 180 ); + le->angles.trDelta[PITCH] = 0; + + AnglesToAxis( le->angles.trBase, le->refEntity.axis ); + } + // leave a mark CG_FragmentBounceMark( le, &trace ); diff --git a/code/cgame/cg_weapons.c b/code/cgame/cg_weapons.c index 57b13d28..1ce6f81f 100644 --- a/code/cgame/cg_weapons.c +++ b/code/cgame/cg_weapons.c @@ -51,10 +51,12 @@ static void CG_MachineGunEjectBrass( centity_t *cent ) { waterScale = 0.10f; } + // don't inherit the full velocity, to emulate air resistance + VectorScale( cent->currentState.pos.trDelta, 0.75, le->pos.trDelta ); 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 ); + VectorMA( le->pos.trDelta, waterScale, xvelocity, le->pos.trDelta ); AxisCopy( axisDefault, re->axis ); re->hModel = cgs.media.machinegunBrassModel; @@ -63,12 +65,14 @@ static void CG_MachineGunEjectBrass( centity_t *cent ) { 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; + VectorCopy ( cent->lerpAngles, le->angles.trBase ); + le->angles.trBase[PITCH] += 90; + le->angles.trBase[0] += rand()&31 - 15; + le->angles.trBase[1] += rand()&31 - 15; + le->angles.trBase[2] += rand()&31 - 15; + le->angles.trDelta[PITCH] = 1750 + rand()&511; + le->angles.trDelta[YAW] = le->angles.trDelta[0] / 2 * ((rand()&1)*2 - 1); + le->angles.trDelta[ROLL] = 0; le->leFlags = LEF_TUMBLE; le->leBounceSoundType = LEBS_BRASS; @@ -128,10 +132,12 @@ static void CG_ShotgunEjectBrass( centity_t *cent ) { waterScale = 0.10f; } + // don't inherit the full velocity, to emulate air resistance + VectorScale( cent->currentState.pos.trDelta, 0.675, le->pos.trDelta ); 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 ); + VectorMA( le->pos.trDelta, waterScale, xvelocity, le->pos.trDelta ); AxisCopy( axisDefault, re->axis ); re->hModel = cgs.media.shotgunBrassModel; @@ -139,12 +145,14 @@ static void CG_ShotgunEjectBrass( centity_t *cent ) { 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; + VectorCopy( cent->lerpAngles, le->angles.trBase ); + le->angles.trBase[PITCH] += 90; + le->angles.trBase[0] += rand()&31 - 15; + le->angles.trBase[1] += rand()&31 - 15; + le->angles.trBase[2] += rand()&31 - 15; + le->angles.trDelta[PITCH] = 750 + rand()&511; + le->angles.trDelta[YAW] = le->angles.trDelta[0] / 2 * ((rand()&1)*2 - 1); + le->angles.trDelta[ROLL] = 0; le->leFlags = LEF_TUMBLE; le->leBounceSoundType = LEBS_BRASS;