summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_event.c57
-rw-r--r--src/cgame/cg_local.h7
-rw-r--r--src/cgame/cg_main.c8
-rw-r--r--src/cgame/cg_particles.c13
-rw-r--r--src/game/bg_misc.c1
-rw-r--r--src/game/bg_public.h3
-rw-r--r--src/game/g_active.c48
-rw-r--r--src/game/g_combat.c12
-rw-r--r--src/game/g_local.h2
9 files changed, 144 insertions, 7 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index aa84609..49dec3f 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -532,6 +532,30 @@ void CG_PainEvent( centity_t *cent, int health )
}
/*
+================
+CG_HeadShotEvent
+
+Also called by playerstate transition
+================
+*/
+void CG_HeadShotEvent( centity_t *cent, int health )
+{
+ particleSystem_t *ps;
+
+ if( !cg_bleedSelfHeadShots.integer &&
+ cent->currentState.number == cg.snap->ps.clientNum )
+ return;
+
+ ps = CG_SpawnNewParticleSystem( cgs.media.headShotPS );
+ if( CG_IsParticleSystemValid( &ps ) )
+ {
+ CG_SetAttachmentCent( &ps->attachment, cent );
+ CG_AttachToCent( &ps->attachment );
+ }
+ //trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.humanGibSound );
+}
+
+/*
=========================
CG_Level2Zap
=========================
@@ -1074,10 +1098,15 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
break;
case EV_PAIN:
- // local player sounds are triggered in CG_CheckLocalSounds,
- // so ignore events on the player
- if( cent->currentState.number != cg.snap->ps.clientNum )
- CG_PainEvent( cent, es->eventParm );
+ {
+ const int health = es->eventParm & ~EVENT_HEADSHOT_BIT;
+ // local player sounds are triggered in CG_CheckLocalSounds,
+ // so ignore events on the player
+ if( cent->currentState.number != cg.snap->ps.clientNum )
+ CG_PainEvent( cent, health );
+ if( es->eventParm & EVENT_HEADSHOT_BIT )
+ CG_HeadShotEvent( cent, health );
+ }
break;
case EV_DEATH1:
@@ -1085,6 +1114,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_DEATH3:
trap_S_StartSound( NULL, es->number, CHAN_VOICE,
CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) );
+ if( es->eventParm & EVENT_HEADSHOT_BIT )
+ CG_HeadShotEvent( cent, 0 );
break;
case EV_OBITUARY:
@@ -1095,6 +1126,24 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
// no gibbing
break;
+ case EV_BLEED:
+ if( cg_bleedSelfWounds.integer ||
+ cent->currentState.number != cg.snap->ps.clientNum )
+ {
+ particleSystem_t *ps = NULL;
+ if( ci->team == TEAM_ALIENS )
+ ps = CG_SpawnNewParticleSystem( cgs.media.alienWoundsBleedPS );
+ else if( ci->team == TEAM_HUMANS )
+ ps = CG_SpawnNewParticleSystem( cgs.media.humanWoundsBleedPS );
+
+ if( ( ps != NULL ) && CG_IsParticleSystemValid( &ps ) )
+ {
+ CG_SetAttachmentCent( &ps->attachment, cent );
+ CG_AttachToCent( &ps->attachment );
+ }
+ }
+ break;
+
case EV_STOPLOOPINGSOUND:
trap_S_StopLoopingSound( es->number );
es->loopSound = 0;
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 1498af9..a477336 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1331,6 +1331,11 @@ typedef struct
qhandle_t healthCross3X;
qhandle_t healthCrossMedkit;
qhandle_t healthCrossPoisoned;
+
+ sfxHandle_t humanGibSound;
+ qhandle_t headShotPS;
+ qhandle_t humanWoundsBleedPS;
+ qhandle_t alienWoundsBleedPS;
} cgMedia_t;
typedef struct
@@ -1540,6 +1545,8 @@ extern vmCvar_t cg_disableBuildDialogs;
extern vmCvar_t cg_disableCommandDialogs;
extern vmCvar_t cg_disableScannerPlane;
extern vmCvar_t cg_tutorial;
+extern vmCvar_t cg_bleedSelfWounds;
+extern vmCvar_t cg_bleedSelfHeadShots;
extern vmCvar_t cg_painBlendUpRate;
extern vmCvar_t cg_painBlendDownRate;
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 1bd5c7f..c7b470c 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -190,6 +190,8 @@ vmCvar_t cg_disableBuildDialogs;
vmCvar_t cg_disableCommandDialogs;
vmCvar_t cg_disableScannerPlane;
vmCvar_t cg_tutorial;
+vmCvar_t cg_bleedSelfWounds;
+vmCvar_t cg_bleedSelfHeadShots;
vmCvar_t cg_painBlendUpRate;
vmCvar_t cg_painBlendDownRate;
@@ -317,6 +319,8 @@ static cvarTable_t cvarTable[ ] =
{ &cg_disableCommandDialogs, "cg_disableCommandDialogs", "0", CVAR_ARCHIVE },
{ &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE },
{ &cg_tutorial, "cg_tutorial", "1", CVAR_ARCHIVE },
+ { &cg_bleedSelfWounds, "cg_bleedSelfWounds", "1", CVAR_ARCHIVE },
+ { &cg_bleedSelfHeadShots, "cg_bleedSelfHeadShots", "1", CVAR_ARCHIVE },
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
{ &cg_hudFilesEnable, "cg_hudFilesEnable", "0", CVAR_ARCHIVE},
{ NULL, "cg_alienConfig", "", CVAR_ARCHIVE },
@@ -858,6 +862,10 @@ static void CG_RegisterGraphics( void )
cgs.media.alienSpiteful_AbcessDestroyedPS = CG_RegisterParticleSystem( "alienSpiteful_AbcessDestroyedPS" );
+ cgs.media.alienWoundsBleedPS = CG_RegisterParticleSystem( "alienWoundBleedPS" );
+ cgs.media.humanWoundsBleedPS = CG_RegisterParticleSystem( "humanWoundBleedPS" );
+ cgs.media.headShotPS = CG_RegisterParticleSystem( "headShotPS" );
+
CG_BuildableStatusParse( "ui/assets/human/buildstat.cfg", &cgs.humanBuildStat );
CG_BuildableStatusParse( "ui/assets/alien/buildstat.cfg", &cgs.alienBuildStat );
diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c
index c2374c7..b718600 100644
--- a/src/cgame/cg_particles.c
+++ b/src/cgame/cg_particles.c
@@ -2156,6 +2156,19 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
return;
}
+ if( bp->bounceMarkName[ 0 ] && p->bounceMarkCount > 0 )
+ {
+ CG_ImpactMark( bp->bounceMark, trace.endpos, trace.plane.normal,
+ random( ) * 360, 1, 1, 1, 1, qtrue, bp->bounceMarkRadius, qfalse );
+ p->bounceMarkCount--;
+ }
+
+ if( bp->bounceSoundName[ 0 ] && p->bounceSoundCount > 0 )
+ {
+ trap_S_StartSound( trace.endpos, ENTITYNUM_WORLD, CHAN_AUTO, bp->bounceSound );
+ p->bounceSoundCount--;
+ }
+
//remove particles that get into a CONTENTS_NODROP brush
if( ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) ||
( bp->cullOnStartSolid && trace.startsolid ) )
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 71f5507..1597194 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -4315,6 +4315,7 @@ char *eventnames[ ] =
"EV_DEATH3",
"EV_OBITUARY",
"EV_GIB_PLAYER", // gib a previously living player
+ "EV_BLEED",
"EV_BUILD_CONSTRUCT",
"EV_BUILD_DESTROY",
"EV_BUILD_DELAY", // can't build yet
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 9109a35..886d29b 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -478,6 +478,8 @@ typedef enum
#define EVENT_VALID_MSEC 300
+#define EVENT_HEADSHOT_BIT 0x80
+
const char *BG_EventName( int num );
typedef enum
@@ -538,6 +540,7 @@ typedef enum
EV_DEATH3,
EV_OBITUARY,
EV_GIB_PLAYER, // gib a previously living player
+ EV_BLEED,
EV_BUILD_CONSTRUCT,
EV_BUILD_DESTROY,
EV_BUILD_DELAY, // can't build yet
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 2f7f906..3c888a6 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -76,8 +76,14 @@ void P_DamageFeedback( gentity_t *player )
// play an apropriate pain sound
if( ( level.time > player->pain_debounce_time ) && !( player->flags & FL_GODMODE ) )
{
+ int param;
player->pain_debounce_time = level.time + 700;
- G_AddEvent( player, EV_PAIN, player->health > 255 ? 255 : player->health );
+ param = player->health;
+ if( param >= EVENT_HEADSHOT_BIT )
+ param = EVENT_HEADSHOT_BIT - 1;
+ if( client->damage_headshot )
+ param |= EVENT_HEADSHOT_BIT;
+ G_AddEvent( player, EV_PAIN, param );
client->ps.damageEvent++;
}
@@ -90,11 +96,48 @@ void P_DamageFeedback( gentity_t *player )
client->damage_blood = 0;
client->damage_armor = 0;
client->damage_knockback = 0;
+ client->damage_headshot = 0;
}
/*
+===============
+P_WoundsBleed
+
+===============
+*/
+void P_WoundsBleed( gentity_t *player )
+{
+ gclient_t *client;
+ int maxHealth;
+ int health;
+
+ if( player->nextBleedTime > level.time )
+ return;
+
+ client = player->client;
+ health = player->health;
+ maxHealth = client->ps.stats[ STAT_MAX_HEALTH ];
+ if( maxHealth > 100 )
+ maxHealth = 100;
+ maxHealth = maxHealth * 3 / 4;
+ if( ( health > maxHealth ) || ( health < 0 ) ) {
+ player->nextBleedTime = level.time + 2000;
+ return;
+ }
+
+ G_AddEvent( player, EV_BLEED, ( health > 255 ) ? 255 : health );
+
+ if( health < 20 )
+ health = 20;
+ player->nextBleedTime = level.time + 2000 * health / maxHealth;
+}
+
+
+
+
+/*
=============
P_WorldEffects
@@ -2292,6 +2335,9 @@ void ClientEndFrame( gentity_t *ent )
// burn from lava, etc
P_WorldEffects( ent );
+ // bleeding wounds
+ P_WoundsBleed( ent );
+
// apply all the damage taken this frame
P_DamageFeedback( ent );
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index c79594d..073c00c 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -687,8 +687,12 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
}
// use own entityid if killed by non-client to prevent uint8_t overflow
- G_AddEvent( self, EV_DEATH1 + i,
- ( killer < MAX_CLIENTS ) ? killer : self - g_entities );
+ {
+ int param = ( killer < MAX_CLIENTS ) ? killer : self - g_entities;
+ if( self->client->damage_headshot )
+ param |= EVENT_HEADSHOT_BIT;
+ G_AddEvent( self, EV_DEATH1 + i, param );
+ }
// globally cycle through the different death animations
i = ( i + 1 ) % 3;
@@ -1069,6 +1073,10 @@ static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *att
g_numDamageRegions[ class ],
hitRotation, hitRatio );
+ // For headshots done by an enemy, make a client event
+ if( ( modifier >= 1.2f ) && !OnSameTeam( targ, attacker ) )
+ targ->client->damage_headshot ++;
+
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 2683ac5..a9774a6 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -245,6 +245,7 @@ struct gentity_s
int lastDamageTime;
int nextRegenTime;
+ int nextBleedTime;
qboolean ownerClear; // used for missle tracking
@@ -399,6 +400,7 @@ struct gclient_s
int damage_knockback; // impact damage
vec3_t damage_from; // origin for vector calculation
qboolean damage_fromWorld; // if true, don't use the damage_from vector
+ int damage_headshot; // the number of head-shots taken in a frame
//
int lastkilled_client;// last client that this client killed