diff --git a/code/cgame/cg_cvar.h b/code/cgame/cg_cvar.h index 46811af9..19093773 100644 --- a/code/cgame/cg_cvar.h +++ b/code/cgame/cg_cvar.h @@ -91,6 +91,7 @@ CG_CVAR( cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE ) CG_CVAR( cg_buildScript, "com_buildScript", "0", 0 ) // force loading of all possible data amd error on failures CG_CVAR( cg_paused, "cl_paused", "0", CVAR_ROM ) CG_CVAR( cg_blood, "com_blood", "1", CVAR_ARCHIVE ) +CG_CVAR( cg_gibsDirectionalVelocityScale, "cg_gibsDirectionalVelocityScale", "1", CVAR_ARCHIVE ) #ifdef MISSIONPACK CG_CVAR( cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO ) CG_CVAR( cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO ) diff --git a/code/cgame/cg_effects.c b/code/cgame/cg_effects.c index 115c309f..3066661e 100644 --- a/code/cgame/cg_effects.c +++ b/code/cgame/cg_effects.c @@ -568,17 +568,33 @@ Generated a bunch of gibs launching out from the bodies location */ #define GIB_VELOCITY 250 #define GIB_JUMP 250 -void CG_GibPlayer( const vec3_t playerOrigin ) { +// TODO get player maxs and mins (in case of ducking (crouching)), +// and the direction they're facing. +void CG_GibPlayer( const vec3_t playerOrigin, const vec3_t dir ) { vec3_t origin, velocity; + float randomGibVelocity = GIB_VELOCITY / 2; + // TODO figure out whether we need this `/ 2` weirdness, + // since we have a CVAR already. No need to complicate things. + float directionalVelocityScale = + GIB_VELOCITY * + cg_gibsDirectionalVelocityScale.value / 2; if ( !cg_blood.integer ) { return; } + // TODO do we need to handle dir being `NULL`? + + // TODO also adjust speeds? So that gibs don't fly inwards. + VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + // Viewheight instead of maxs because it more closely corresponds + // to the head position. + origin[2] += DEFAULT_VIEWHEIGHT; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); if ( rand() & 1 ) { CG_LaunchGib( origin, velocity, cgs.media.gibSkull ); } else { @@ -591,57 +607,81 @@ void CG_GibPlayer( const vec3_t playerOrigin ) { } VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[0] += 1; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + // TODO player look direction? + origin[1] += 8; // See `PM_CheckDuck`, `15`, player width. + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibArm ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[2] += DEFAULT_VIEWHEIGHT * 3 / 4; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibChest ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[1] += -8; // See `PM_CheckDuck`, `15`, player width. + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibFist ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[2] += MINS_Z + 1; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibFoot ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[1] += -8; // See `PM_CheckDuck`, `15`, player width. + origin[2] += DEFAULT_VIEWHEIGHT / 2; // See `PM_CheckDuck`, `15`, player width. + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibForearm ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[0] += 3; + origin[1] += 1; + origin[2] += 1; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibIntestine ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[2] += MINS_Z / 2; + origin[1] += 15 / 2; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); VectorCopy( playerOrigin, origin ); - velocity[0] = crandom()*GIB_VELOCITY; - velocity[1] = crandom()*GIB_VELOCITY; - velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY; + origin[2] += MINS_Z / 2; + origin[1] += -15 / 2; + velocity[0] = crandom()*randomGibVelocity; + velocity[1] = crandom()*randomGibVelocity; + velocity[2] = GIB_JUMP + crandom()*randomGibVelocity; + VectorMA(velocity, directionalVelocityScale, dir, velocity); CG_LaunchGib( origin, velocity, cgs.media.gibLeg ); } diff --git a/code/cgame/cg_event.c b/code/cgame/cg_event.c index 67319e7f..116848f3 100644 --- a/code/cgame/cg_event.c +++ b/code/cgame/cg_event.c @@ -1215,7 +1215,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position, int entityNum ) { #else trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); #endif - CG_GibPlayer( cent->lerpOrigin ); + ByteToDir( es->eventParm, dir ); + CG_GibPlayer( cent->lerpOrigin, dir ); break; case EV_STOPLOOPINGSOUND: diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 240f6ed1..1bc16d4f 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -1406,7 +1406,7 @@ void CG_LightningBoltBeam( vec3_t start, vec3_t end ); #endif void CG_ScorePlum( int client, const vec3_t origin, int score ); -void CG_GibPlayer( const vec3_t playerOrigin ); +void CG_GibPlayer( const vec3_t playerOrigin, const vec3_t dir ); void CG_BigExplode( vec3_t playerOrigin ); void CG_Bleed( const vec3_t origin, int entityNum ); diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c index 0dca2086..d35eac28 100644 --- a/code/game/g_cmds.c +++ b/code/game/g_cmds.c @@ -464,7 +464,7 @@ void Cmd_Kill_f( gentity_t *ent ) { } ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = -999; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); + player_die (ent, ent, ent, NULL, 100000, MOD_SUICIDE); } @@ -652,7 +652,7 @@ qboolean SetTeam( gentity_t *ent, const char *s ) { // Kill him (makes sure he loses flags, etc) ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); + player_die (ent, ent, ent, NULL, 100000, MOD_SUICIDE); } // they go to the end of the line for tournements diff --git a/code/game/g_combat.c b/code/game/g_combat.c index 47138f7c..42d50178 100644 --- a/code/game/g_combat.c +++ b/code/game/g_combat.c @@ -220,7 +220,7 @@ void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) GibEntity ================== */ -void GibEntity( gentity_t *self, int killer ) { +void GibEntity( gentity_t *self, int killer, vec3_t dir ) { #ifdef MISSIONPACK gentity_t *ent; int i; @@ -242,7 +242,9 @@ void GibEntity( gentity_t *self, int killer ) { } #endif - G_AddEvent( self, EV_GIB_PLAYER, killer ); + // `killer` used to get passed as `eventParm`, + // but it's unused apparently + G_AddEvent( self, EV_GIB_PLAYER, DirToByte( dir ) ); self->takedamage = qfalse; self->s.eType = ET_INVISIBLE; self->r.contents = 0; @@ -253,7 +255,7 @@ void GibEntity( gentity_t *self, int killer ) { body_die ================== */ -void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { +void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, int damage, int meansOfDeath ) { if ( self->health > GIB_HEALTH ) { return; } @@ -262,7 +264,7 @@ void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int d return; } - GibEntity( self, 0 ); + GibEntity( self, 0, dir ); } @@ -393,7 +395,7 @@ void CheckAlmostScored( gentity_t *self, gentity_t *attacker ) { player_die ================== */ -void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { +void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, int damage, int meansOfDeath ) { gentity_t *ent; int anim; int contents; @@ -595,7 +597,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int // never gib in a nodrop if ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) && g_blood.integer) || meansOfDeath == MOD_SUICIDE) { // gib death - GibEntity( self, killer ); + GibEntity( self, killer, dir ); } else { // normal death static int i; @@ -867,6 +869,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } // figure momentum add, even if the damage won't be taken + // TODO so we can calculate the gib velocity here? + // Instead of it being a normalized vector. if ( knockback && targ->client ) { vec3_t kvel; float mass; @@ -1030,7 +1034,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, targ->health = -999; targ->enemy = attacker; - targ->die (targ, inflictor, attacker, take, mod); + targ->die (targ, inflictor, attacker, dir, take, mod); return; } else if ( targ->pain ) { targ->pain (targ, attacker, take); diff --git a/code/game/g_local.h b/code/game/g_local.h index 7c8b9a4f..8395ac40 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -116,7 +116,7 @@ struct gentity_s { void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace); void (*use)(gentity_t *self, gentity_t *other, gentity_t *activator); void (*pain)(gentity_t *self, gentity_t *attacker, int damage); - void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod); + void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, int damage, int mod); int pain_debounce_time; int fly_sound_debounce_time; // wind tunnel @@ -529,7 +529,7 @@ qboolean CanDamage (gentity_t *targ, vec3_t origin); void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod); qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod); int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir ); -void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ); +void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, int damage, int meansOfDeath ); void TossClientItems( gentity_t *self ); #ifdef MISSIONPACK void TossClientPersistantPowerups( gentity_t *self ); @@ -609,7 +609,7 @@ void respawn (gentity_t *ent); void BeginIntermission (void); void InitBodyQue (void); void ClientSpawn( gentity_t *ent ); -void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod); +void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, int damage, int mod); void AddScore( gentity_t *ent, vec3_t origin, int score ); void CalculateRanks( void ); qboolean SpotWouldTelefrag( gentity_t *spot ); diff --git a/code/game/g_missile.c b/code/game/g_missile.c index 8f3418d2..eb28ff60 100644 --- a/code/game/g_missile.c +++ b/code/game/g_missile.c @@ -93,7 +93,7 @@ static void ProximityMine_Explode( gentity_t *mine ) { ProximityMine_Die ================ */ -static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) { +static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, vec3_t dir, gentity_t *attacker, int damage, int mod ) { ent->think = ProximityMine_Explode; ent->nextthink = level.time + 1; }