From 8816244ec329acdd5eb64e0518e69ae77df1cd75 Mon Sep 17 00:00:00 2001 From: Petr Pudlak Date: Sat, 16 Aug 2014 14:26:16 +0200 Subject: Add the ability for humans to heal their team members The medkit handling is moved to a new function G_UseMedkit. If there is a human within a given range that is either more wounded than the player, or poisoned, the medkit is applied to him (see G_NeedsMedkit). The range and the breadth of the action is configurable by cvars. The original patch was used on a server, but this port wasn't tested (only that it compiles). --- src/cgame/cg_event.c | 25 +++++++++++++ src/game/g_active.c | 101 +++++++++++++++++++++++++++++++++++---------------- src/game/g_local.h | 3 ++ src/game/g_main.c | 4 ++ src/game/g_weapon.c | 31 ++++++++++++++++ 5 files changed, 132 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 2baf545..aa84609 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -1228,6 +1228,31 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) break; case EV_MEDKIT_USED: + // the parameter is the healer's entity number + { + const int healerNum = es->eventParm; + const char *configstring; + const char *name; + + if( healerNum != clientNum ) + { + if( healerNum == cg.clientNum ) + { + configstring = CG_ConfigString( clientNum + CS_PLAYERS ); + // isolate the player's name + name = Info_ValueForKey( configstring, "n" ); + + CG_Printf( S_COLOR_CYAN "You bandaged " S_COLOR_WHITE "%s" S_COLOR_CYAN "'s wounds.\n", name ); + } else if( clientNum == cg.clientNum ) + { + configstring = CG_ConfigString( healerNum + CS_PLAYERS ); + // isolate the player's name + name = Info_ValueForKey( configstring, "n" ); + + CG_Printf( S_COLOR_WHITE "%s" S_COLOR_CYAN " bandaged your wounds.\n", name ); + } + } + } trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound ); break; diff --git a/src/game/g_active.c b/src/game/g_active.c index fc32ed6..2f7f906 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -425,6 +425,74 @@ void G_TouchTriggers( gentity_t *ent ) static qboolean ClientInactivityTimer( gentity_t *ent, qboolean active ); +/* +============ +G_NeedsMedkit + +============ +*/ +qboolean G_NeedsMedkit( gclient_t *client ) +{ + //not if currently using a medkit or have no need for a medkit now + return !( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X ) && + ( client->ps.stats[ STAT_HEALTH ] < client->ps.stats[ STAT_MAX_HEALTH ] || + ( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ); +} +/* +============ +G_UseMedkit + +============ +*/ +void G_UseMedkit( gentity_t *ent ) +{ + gclient_t *client = ent->client; + gentity_t *targetEnt = NULL; + gclient_t *tclient = NULL; + qboolean clientNeedsMedkit; + + if( client->ps.stats[ STAT_HEALTH ] <= 0 ) + return; + + clientNeedsMedkit = G_NeedsMedkit( client ); + //look for a teammate that would need healing + targetEnt = G_MedkitTarget( ent ); + if( ( targetEnt != NULL ) && + ( ( tclient = targetEnt->client ) != NULL ) && + ( tclient->ps.stats[ STAT_HEALTH ] > 0 ) && + ( tclient->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) && + ( G_NeedsMedkit( tclient ) ) && + ( ( client->ps.stats[ STAT_HEALTH ] >= tclient->ps.stats[ STAT_HEALTH ] ) || + !clientNeedsMedkit ) + ) + ; + else if( clientNeedsMedkit ) + { + targetEnt = ent; + tclient = client; + } else { + BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); + return; + } + + //remove anti toxin + BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); + BG_RemoveUpgradeFromInventory( UP_MEDKIT, client->ps.stats ); + + // don't poison and/or infect the client anymore + tclient->ps.stats[ STAT_STATE ] &= ~( SS_POISONED | SS_INFECTED ); + tclient->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME; + + tclient->ps.stats[ STAT_STATE ] |= SS_HEALING_2X; + tclient->lastMedKitTime = level.time; + tclient->medKitHealthToRestore = + tclient->ps.stats[ STAT_MAX_HEALTH ] - tclient->ps.stats[ STAT_HEALTH ]; + tclient->medKitIncrementTime = level.time + + ( MEDKIT_STARTUP_TIME / MEDKIT_STARTUP_SPEED ); + + G_AddEvent( targetEnt, EV_MEDKIT_USED, ent->s.number ); +} + /* ================= SpectatorThink @@ -1685,38 +1753,7 @@ void ClientThink_real( gentity_t *ent ) if( BG_InventoryContainsUpgrade( UP_MEDKIT, client->ps.stats ) && BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) ) - { - //if currently using a medkit or have no need for a medkit now - if( client->ps.stats[ STAT_STATE ] & SS_HEALING_2X || - ( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] && - !( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) ) - { - BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); - } - else if( client->ps.stats[ STAT_HEALTH ] > 0 ) - { - //remove anti toxin - BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); - BG_RemoveUpgradeFromInventory( UP_MEDKIT, client->ps.stats ); - - // don't poison and/or infect the client anymore - client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; - - if( client->ps.stats[ STAT_STATE ] & SS_INFECTED ) - client->ps.stats[ STAT_STATE ] &= ~SS_INFECTED; - - client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME; - - client->ps.stats[ STAT_STATE ] |= SS_HEALING_2X; - client->lastMedKitTime = level.time; - client->medKitHealthToRestore = - client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ]; - client->medKitIncrementTime = level.time + - ( MEDKIT_STARTUP_TIME / MEDKIT_STARTUP_SPEED ); - - G_AddEvent( ent, EV_MEDKIT_USED, 0 ); - } - } + G_UseMedkit( ent ); if( BG_InventoryContainsUpgrade( UP_CLOAK, client->ps.stats ) && BG_UpgradeIsActive( UP_CLOAK, client->ps.stats ) ) diff --git a/src/game/g_local.h b/src/game/g_local.h index e437349..37971ed 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -1042,6 +1042,7 @@ void G_UnregisterCommands( void ); void FireWeapon( gentity_t *ent ); void FireWeapon2( gentity_t *ent ); void FireWeapon3( gentity_t *ent ); +gentity_t *G_MedkitTarget( gentity_t *ent ); // // g_main.c @@ -1179,6 +1180,8 @@ extern vmCvar_t g_suddenDeathVoteDelay; extern vmCvar_t g_readyPercent; extern vmCvar_t g_armageddonVotePercent; extern vmCvar_t g_armageddonPercent; +extern vmCvar_t g_humanMedkitRange; +extern vmCvar_t g_humanMedkitWidth; extern vmCvar_t g_teamForceBalance; extern vmCvar_t g_smoothClients; extern vmCvar_t pmove_fixed; diff --git a/src/game/g_main.c b/src/game/g_main.c index 45f7b03..c644bdd 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -86,6 +86,8 @@ vmCvar_t g_suddenDeathVotePercent; vmCvar_t g_suddenDeathVoteDelay; vmCvar_t g_armageddonVotePercent; vmCvar_t g_armageddonPercent; +vmCvar_t g_humanMedkitRange; +vmCvar_t g_humanMedkitWidth; vmCvar_t g_readyPercent; vmCvar_t g_teamForceBalance; vmCvar_t g_smoothClients; @@ -217,6 +219,8 @@ static cvarTable_t gameCvarTable[ ] = { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse }, { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, + { &g_humanMedkitRange, "g_humanMedkitRange", "200", CVAR_ARCHIVE, 0, qfalse }, + { &g_humanMedkitWidth, "g_humanMedkitWidth", "20", CVAR_ARCHIVE, 0, qfalse }, { &g_suddenDeathTime, "g_suddenDeathTime", "40", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_armageddonTimeStep, "g_armageddonTimeStep", "5", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_armageddonInitialTimeStep, "g_armageddonInitialTimeStep", "10", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index a64f0f8..feee414 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -1454,6 +1454,37 @@ void G_ClearPlayerZapEffects( gentity_t *player ) } } + +/* +=============== +G_MedkitTarget + +Look for a possible healing target (a client) in the front. +=============== +*/ +gentity_t *G_MedkitTarget( gentity_t *ent ) +{ + trace_t tr; + gentity_t *targetEnt = NULL; + + if( g_humanMedkitRange.value <= 0 || + g_humanMedkitWidth.value <= 0 ) + return NULL; + + // Calculate muzzle point + AngleVectors( ent->client->ps.viewangles, forward, right, up ); + CalcMuzzlePoint( ent, forward, right, up, muzzle ); + + G_WideTrace( &tr, ent, g_humanMedkitRange.value, + g_humanMedkitWidth.value, g_humanMedkitWidth.value, &targetEnt ); + + if( ( targetEnt != NULL ) && + ( targetEnt->client != NULL ) ) + return targetEnt; + else + return NULL; +} + /* =============== areaZapFire -- cgit