diff options
Diffstat (limited to 'src/game/g_combat.c')
-rw-r--r-- | src/game/g_combat.c | 1322 |
1 files changed, 0 insertions, 1322 deletions
diff --git a/src/game/g_combat.c b/src/game/g_combat.c deleted file mode 100644 index d98f74c3..00000000 --- a/src/game/g_combat.c +++ /dev/null @@ -1,1322 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// g_combat.c - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -damageRegion_t g_damageRegions[ PCL_NUM_CLASSES ][ MAX_LOCDAMAGE_REGIONS ]; -int g_numDamageRegions[ PCL_NUM_CLASSES ]; - -armourRegion_t g_armourRegions[ UP_NUM_UPGRADES ][ MAX_ARMOUR_REGIONS ]; -int g_numArmourRegions[ UP_NUM_UPGRADES ]; - -/* -============ -AddScore - -Adds score to both the client and his team -============ -*/ -void AddScore( gentity_t *ent, int score ) -{ - if( !ent->client ) - return; - - // no scoring during pre-match warmup - if( level.warmupTime ) - return; - - ent->client->ps.persistant[ PERS_SCORE ] += score; - CalculateRanks( ); -} - -/* -================== -LookAtKiller -================== -*/ -void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) -{ - vec3_t dir; - - if ( attacker && attacker != self ) - VectorSubtract( attacker->s.pos.trBase, self->s.pos.trBase, dir ); - else if( inflictor && inflictor != self ) - VectorSubtract( inflictor->s.pos.trBase, self->s.pos.trBase, dir ); - else - { - self->client->ps.stats[ STAT_VIEWLOCK ] = self->s.angles[ YAW ]; - return; - } - - self->client->ps.stats[ STAT_VIEWLOCK ] = vectoyaw( dir ); -} - -// these are just for logging, the client prints its own messages -char *modNames[ ] = -{ - "MOD_UNKNOWN", - "MOD_SHOTGUN", - "MOD_BLASTER", - "MOD_PAINSAW", - "MOD_MACHINEGUN", - "MOD_CHAINGUN", - "MOD_PRIFLE", - "MOD_MDRIVER", - "MOD_LASGUN", - "MOD_LCANNON", - "MOD_LCANNON_SPLASH", - "MOD_FLAMER", - "MOD_FLAMER_SPLASH", - "MOD_GRENADE", - "MOD_WATER", - "MOD_SLIME", - "MOD_LAVA", - "MOD_CRUSH", - "MOD_TELEFRAG", - "MOD_FALLING", - "MOD_SUICIDE", - "MOD_TARGET_LASER", - "MOD_TRIGGER_HURT", - - "MOD_ABUILDER_CLAW", - "MOD_LEVEL0_BITE", - "MOD_LEVEL1_CLAW", - "MOD_LEVEL1_PCLOUD", - "MOD_LEVEL3_CLAW", - "MOD_LEVEL3_POUNCE", - "MOD_LEVEL3_BOUNCEBALL", - "MOD_LEVEL2_CLAW", - "MOD_LEVEL2_ZAP", - "MOD_LEVEL4_CLAW", - "MOD_LEVEL4_CHARGE", - - "MOD_SLOWBLOB", - "MOD_POISON", - "MOD_SWARM", - - "MOD_HSPAWN", - "MOD_TESLAGEN", - "MOD_MGTURRET", - "MOD_REACTOR", - - "MOD_ASPAWN", - "MOD_ATUBE", - "MOD_OVERMIND" -}; - -/* -================== -player_die -================== -*/ -void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) -{ - gentity_t *ent; - int anim; - int killer; - int i, j; - char *killerName, *obit; - float totalDamage = 0.0f; - gentity_t *player; - - - if( self->client->ps.pm_type == PM_DEAD ) - return; - - if( level.intermissiontime ) - return; - - // stop any following clients - for( i = 0; i < level.maxclients; i++ ) - { - if( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR && - level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW && - level.clients[ i ].sess.spectatorClient == self->client->ps.clientNum ) - { - if( !G_FollowNewClient( &g_entities[ i ], 1 ) ) - G_StopFollowing( &g_entities[ i ] ); - } - } - - self->client->ps.pm_type = PM_DEAD; - self->suicideTime = 0; - - if( attacker ) - { - killer = attacker->s.number; - - if( attacker->client ) - killerName = attacker->client->pers.netname; - else - killerName = "<non-client>"; - } - else - { - killer = ENTITYNUM_WORLD; - killerName = "<world>"; - } - - if( killer < 0 || killer >= MAX_CLIENTS ) - { - killer = ENTITYNUM_WORLD; - killerName = "<world>"; - } - - if( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) - obit = "<bad obituary>"; - else - obit = modNames[ meansOfDeath ]; - - G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", - killer, self->s.number, meansOfDeath, killerName, - self->client->pers.netname, obit ); - - //TA: close any menus the client has open - G_CloseMenus( self->client->ps.clientNum ); - - //TA: deactivate all upgrades - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - BG_DeactivateUpgrade( i, self->client->ps.stats ); - - // broadcast the death event to everyone - ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY ); - ent->s.eventParm = meansOfDeath; - ent->s.otherEntityNum = self->s.number; - ent->s.otherEntityNum2 = killer; - ent->r.svFlags = SVF_BROADCAST; // send to everyone - - self->enemy = attacker; - - self->client->ps.persistant[ PERS_KILLED ]++; - - if( attacker && attacker->client ) - { - attacker->client->lastkilled_client = self->s.number; - - if( attacker == self || OnSameTeam( self, attacker ) ) - { - AddScore( attacker, -1 ); - - //punish team kills and suicides - if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - G_AddCreditToClient( attacker->client, -1, qtrue ); - else if( attacker->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_AddCreditToClient( attacker->client, -ASPAWN_VALUE, qtrue ); - } - else - { - AddScore( attacker, 1 ); - - attacker->client->lastKillTime = level.time; - } - } - else if( attacker->s.eType != ET_BUILDABLE ) - AddScore( self, -1 ); - - //total up all the damage done by every client - for( i = 0; i < MAX_CLIENTS; i++ ) - totalDamage += (float)self->credits[ i ]; - - // if players did more than DAMAGE_FRACTION_FOR_KILL increment the stage counters - if( totalDamage >= ( self->client->ps.stats[ STAT_MAX_HEALTH ] * DAMAGE_FRACTION_FOR_KILL ) ) - { - if( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - trap_Cvar_Set( "g_alienKills", va( "%d", g_alienKills.integer + 1 ) ); - else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - trap_Cvar_Set( "g_humanKills", va( "%d", g_humanKills.integer + 1 ) ); - } - - if( totalDamage > 0.0f ) - { - if( self->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - //nice simple happy bouncy human land - float classValue = BG_FindValueOfClass( self->client->ps.stats[ STAT_PCLASS ] ); - - for( i = 0; i < MAX_CLIENTS; i++ ) - { - player = g_entities + i; - - if( !player->client ) - continue; - - if( player->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS ) - continue; - - if( !self->credits[ i ] ) - continue; - - //add credit - G_AddCreditToClient( player->client, - (int)( classValue * ( (float)self->credits[ i ] / totalDamage ) ), qtrue ); - } - } - else if( self->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - //horribly complex nasty alien land - float humanValue = BG_GetValueOfHuman( &self->client->ps ); - int frags; - int unclaimedFrags = (int)humanValue; - - for( i = 0; i < MAX_CLIENTS; i++ ) - { - player = g_entities + i; - - if( !player->client ) - continue; - - if( player->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) - continue; - - //this client did no damage - if( !self->credits[ i ] ) - continue; - - //nothing left to claim - if( !unclaimedFrags ) - break; - - frags = (int)floor( humanValue * ( (float)self->credits[ i ] / totalDamage ) ); - - if( frags > 0 ) - { - //add kills - G_AddCreditToClient( player->client, frags, qtrue ); - - //can't revist this account later - self->credits[ i ] = 0; - - //reduce frags left to be claimed - unclaimedFrags -= frags; - } - } - - //there are frags still to be claimed - if( unclaimedFrags ) - { - //the clients remaining at this point do not - //have enough credit to claim even one frag - //so simply give the top <unclaimedFrags> clients - //a frag each - - for( i = 0; i < unclaimedFrags; i++ ) - { - int maximum = 0; - int topClient = 0; - - for( j = 0; j < MAX_CLIENTS; j++ ) - { - //this client did no damage - if( !self->credits[ j ] ) - continue; - - if( self->credits[ j ] > maximum ) - { - maximum = self->credits[ j ]; - topClient = j; - } - } - - if( maximum > 0 ) - { - player = g_entities + topClient; - - //add kills - G_AddCreditToClient( player->client, 1, qtrue ); - - //can't revist this account again - self->credits[ topClient ] = 0; - } - } - } - } - } - - Cmd_Score_f( self ); // show scores - - // send updated scores to any clients that are following this one, - // or they would get stale scoreboards - for( i = 0 ; i < level.maxclients ; i++ ) - { - gclient_t *client; - - client = &level.clients[ i ]; - if( client->pers.connected != CON_CONNECTED ) - continue; - - if( client->sess.sessionTeam != TEAM_SPECTATOR ) - continue; - - if( client->sess.spectatorClient == self->s.number ) - Cmd_Score_f( g_entities + i ); - } - - self->client->pers.classSelection = PCL_NONE; //TA: reset the classtype - VectorCopy( self->s.origin, self->client->pers.lastDeathLocation ); - - self->takedamage = qfalse; // can still be gibbed - - self->s.weapon = WP_NONE; - self->r.contents = CONTENTS_CORPSE; - - self->s.angles[ PITCH ] = 0; - self->s.angles[ ROLL ] = 0; - self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ]; - LookAtKiller( self, inflictor, attacker ); - - VectorCopy( self->s.angles, self->client->ps.viewangles ); - - self->s.loopSound = 0; - - self->r.maxs[ 2 ] = -8; - - // don't allow respawn until the death anim is done - // g_forcerespawn may force spawning at some later time - self->client->respawnTime = level.time + 1700; - - // remove powerups - memset( self->client->ps.powerups, 0, sizeof( self->client->ps.powerups ) ); - - { - // normal death - static int i; - - if( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - switch( i ) - { - case 0: - anim = BOTH_DEATH1; - break; - case 1: - anim = BOTH_DEATH2; - break; - case 2: - default: - anim = BOTH_DEATH3; - break; - } - } - else - { - switch( i ) - { - case 0: - anim = NSPA_DEATH1; - break; - case 1: - anim = NSPA_DEATH2; - break; - case 2: - default: - anim = NSPA_DEATH3; - break; - } - } - - self->client->ps.legsAnim = - ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - - if( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - self->client->ps.torsoAnim = - ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - } - - G_AddEvent( self, EV_DEATH1 + i, killer ); - - // globally cycle through the different death animations - i = ( i + 1 ) % 3; - } - - trap_LinkEntity( self ); -} - - -////////TA: locdamage - -/* -=============== -G_ParseArmourScript -=============== -*/ -void G_ParseArmourScript( char *buf, int upgrade ) -{ - char *token; - int count; - - count = 0; - - while( 1 ) - { - token = COM_Parse( &buf ); - - if( !token[0] ) - break; - - if( strcmp( token, "{" ) ) - { - G_Printf( "Missing { in armour file\n" ); - break; - } - - if( count == MAX_ARMOUR_REGIONS ) - { - G_Printf( "Max armour regions exceeded in locdamage file\n" ); - break; - } - - //default - g_armourRegions[ upgrade ][ count ].minHeight = 0.0; - g_armourRegions[ upgrade ][ count ].maxHeight = 1.0; - g_armourRegions[ upgrade ][ count ].minAngle = 0; - g_armourRegions[ upgrade ][ count ].maxAngle = 360; - g_armourRegions[ upgrade ][ count ].modifier = 1.0; - g_armourRegions[ upgrade ][ count ].crouch = qfalse; - - while( 1 ) - { - token = COM_ParseExt( &buf, qtrue ); - - if( !token[0] ) - { - G_Printf( "Unexpected end of armour file\n" ); - break; - } - - if( !Q_stricmp( token, "}" ) ) - { - break; - } - else if( !strcmp( token, "minHeight" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "0" ); - - g_armourRegions[ upgrade ][ count ].minHeight = atof( token ); - } - else if( !strcmp( token, "maxHeight" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "100" ); - - g_armourRegions[ upgrade ][ count ].maxHeight = atof( token ); - } - else if( !strcmp( token, "minAngle" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "0" ); - - g_armourRegions[ upgrade ][ count ].minAngle = atoi( token ); - } - else if( !strcmp( token, "maxAngle" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "360" ); - - g_armourRegions[ upgrade ][ count ].maxAngle = atoi( token ); - } - else if( !strcmp( token, "modifier" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "1.0" ); - - g_armourRegions[ upgrade ][ count ].modifier = atof( token ); - } - else if( !strcmp( token, "crouch" ) ) - { - g_armourRegions[ upgrade ][ count ].crouch = qtrue; - } - } - - g_numArmourRegions[ upgrade ]++; - count++; - } -} - - -/* -=============== -G_ParseDmgScript -=============== -*/ -void G_ParseDmgScript( char *buf, int class ) -{ - char *token; - int count; - - count = 0; - - while( 1 ) - { - token = COM_Parse( &buf ); - - if( !token[0] ) - break; - - if( strcmp( token, "{" ) ) - { - G_Printf( "Missing { in locdamage file\n" ); - break; - } - - if( count == MAX_LOCDAMAGE_REGIONS ) - { - G_Printf( "Max damage regions exceeded in locdamage file\n" ); - break; - } - - //default - g_damageRegions[ class ][ count ].minHeight = 0.0; - g_damageRegions[ class ][ count ].maxHeight = 1.0; - g_damageRegions[ class ][ count ].minAngle = 0; - g_damageRegions[ class ][ count ].maxAngle = 360; - g_damageRegions[ class ][ count ].modifier = 1.0; - g_damageRegions[ class ][ count ].crouch = qfalse; - - while( 1 ) - { - token = COM_ParseExt( &buf, qtrue ); - - if( !token[0] ) - { - G_Printf( "Unexpected end of locdamage file\n" ); - break; - } - - if( !Q_stricmp( token, "}" ) ) - { - break; - } - else if( !strcmp( token, "minHeight" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "0" ); - - g_damageRegions[ class ][ count ].minHeight = atof( token ); - } - else if( !strcmp( token, "maxHeight" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "100" ); - - g_damageRegions[ class ][ count ].maxHeight = atof( token ); - } - else if( !strcmp( token, "minAngle" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "0" ); - - g_damageRegions[ class ][ count ].minAngle = atoi( token ); - } - else if( !strcmp( token, "maxAngle" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "360" ); - - g_damageRegions[ class ][ count ].maxAngle = atoi( token ); - } - else if( !strcmp( token, "modifier" ) ) - { - token = COM_ParseExt( &buf, qfalse ); - - if ( !token[0] ) - strcpy( token, "1.0" ); - - g_damageRegions[ class ][ count ].modifier = atof( token ); - } - else if( !strcmp( token, "crouch" ) ) - { - g_damageRegions[ class ][ count ].crouch = qtrue; - } - } - - g_numDamageRegions[ class ]++; - count++; - } -} - - -/* -============ -G_CalcDamageModifier -============ -*/ -static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *attacker, int class, int dflags ) -{ - vec3_t bulletPath; - vec3_t bulletAngle; - vec3_t pMINUSfloor, floor, normal; - - float clientHeight, hitRelative, hitRatio; - int bulletRotation, clientRotation, hitRotation; - float modifier = 1.0f; - int i, j; - - if( point == NULL ) - return 1.0f; - - clientHeight = targ->r.maxs[ 2 ] - targ->r.mins[ 2 ]; - - if( targ->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorCopy( targ->client->ps.grapplePoint, normal ); - else - VectorSet( normal, 0, 0, 1 ); - - VectorMA( targ->r.currentOrigin, targ->r.mins[ 2 ], normal, floor ); - VectorSubtract( point, floor, pMINUSfloor ); - - hitRelative = DotProduct( normal, pMINUSfloor ) / VectorLength( normal ); - - if( hitRelative < 0.0f ) - hitRelative = 0.0f; - - if( hitRelative > clientHeight ) - hitRelative = clientHeight; - - hitRatio = hitRelative / clientHeight; - - VectorSubtract( targ->r.currentOrigin, point, bulletPath ); - vectoangles( bulletPath, bulletAngle ); - - clientRotation = targ->client->ps.viewangles[ YAW ]; - bulletRotation = bulletAngle[ YAW ]; - - hitRotation = abs( clientRotation - bulletRotation ); - - hitRotation = hitRotation % 360; // Keep it in the 0-359 range - - if( dflags & DAMAGE_NO_LOCDAMAGE ) - { - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - float totalModifier = 0.0f; - float averageModifier = 1.0f; - - //average all of this upgrade's armour regions together - if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) ) - { - for( j = 0; j < g_numArmourRegions[ i ]; j++ ) - totalModifier += g_armourRegions[ i ][ j ].modifier; - - if( g_numArmourRegions[ i ] ) - averageModifier = totalModifier / g_numArmourRegions[ i ]; - else - averageModifier = 1.0f; - } - - modifier *= averageModifier; - } - } - else - { - for( i = 0; i < g_numDamageRegions[ class ]; i++ ) - { - qboolean rotationBound; - - if( g_damageRegions[ class ][ i ].minAngle > - g_damageRegions[ class ][ i ].maxAngle ) - { - rotationBound = ( hitRotation >= g_damageRegions[ class ][ i ].minAngle && - hitRotation <= 360 ) || ( hitRotation >= 0 && - hitRotation <= g_damageRegions[ class ][ i ].maxAngle ); - } - else - { - rotationBound = ( hitRotation >= g_damageRegions[ class ][ i ].minAngle && - hitRotation <= g_damageRegions[ class ][ i ].maxAngle ); - } - - if( rotationBound && - hitRatio >= g_damageRegions[ class ][ i ].minHeight && - hitRatio <= g_damageRegions[ class ][ i ].maxHeight && - ( g_damageRegions[ class ][ i ].crouch == - ( targ->client->ps.pm_flags & PMF_DUCKED ) ) ) - modifier *= g_damageRegions[ class ][ i ].modifier; - } - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) ) - { - for( j = 0; j < g_numArmourRegions[ i ]; j++ ) - { - qboolean rotationBound; - - if( g_armourRegions[ i ][ j ].minAngle > - g_armourRegions[ i ][ j ].maxAngle ) - { - rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle && - hitRotation <= 360 ) || ( hitRotation >= 0 && - hitRotation <= g_armourRegions[ i ][ j ].maxAngle ); - } - else - { - rotationBound = ( hitRotation >= g_armourRegions[ i ][ j ].minAngle && - hitRotation <= g_armourRegions[ i ][ j ].maxAngle ); - } - - if( rotationBound && - hitRatio >= g_armourRegions[ i ][ j ].minHeight && - hitRatio <= g_armourRegions[ i ][ j ].maxHeight && - ( g_armourRegions[ i ][ j ].crouch == - ( targ->client->ps.pm_flags & PMF_DUCKED ) ) ) - modifier *= g_armourRegions[ i ][ j ].modifier; - } - } - } - } - - return modifier; -} - - -/* -============ -G_InitDamageLocations -============ -*/ -void G_InitDamageLocations( void ) -{ - char *modelName; - char filename[ MAX_QPATH ]; - int i; - int len; - fileHandle_t fileHandle; - char buffer[ MAX_LOCDAMAGE_TEXT ]; - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - modelName = BG_FindModelNameForClass( i ); - Com_sprintf( filename, sizeof( filename ), "models/players/%s/locdamage.cfg", modelName ); - - len = trap_FS_FOpenFile( filename, &fileHandle, FS_READ ); - if ( !fileHandle ) - { - G_Printf( va( S_COLOR_RED "file not found: %s\n", filename ) ); - continue; - } - - if( len >= MAX_LOCDAMAGE_TEXT ) - { - G_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_LOCDAMAGE_TEXT ) ); - trap_FS_FCloseFile( fileHandle ); - continue; - } - - trap_FS_Read( buffer, len, fileHandle ); - buffer[len] = 0; - trap_FS_FCloseFile( fileHandle ); - - G_ParseDmgScript( buffer, i ); - } - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - modelName = BG_FindNameForUpgrade( i ); - Com_sprintf( filename, sizeof( filename ), "armour/%s.armour", modelName ); - - len = trap_FS_FOpenFile( filename, &fileHandle, FS_READ ); - - //no file - no parsage - if ( !fileHandle ) - continue; - - if( len >= MAX_LOCDAMAGE_TEXT ) - { - G_Printf( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_LOCDAMAGE_TEXT ) ); - trap_FS_FCloseFile( fileHandle ); - continue; - } - - trap_FS_Read( buffer, len, fileHandle ); - buffer[len] = 0; - trap_FS_FCloseFile( fileHandle ); - - G_ParseArmourScript( buffer, i ); - } -} - -////////TA: locdamage - - -/* -============ -T_Damage - -targ entity that is being damaged -inflictor entity that is causing the damage -attacker entity that caused the inflictor to damage targ - example: targ=monster, inflictor=rocket, attacker=player - -dir direction of the attack for knockback -point point at which the damage is being inflicted, used for headshots -damage amount of damage being inflicted -knockback force to be applied against targ as a result of the damage - -inflictor, attacker, dir, and point can be NULL for environmental effects - -dflags these flags are used to control how T_Damage works - DAMAGE_RADIUS damage was indirect (from a nearby explosion) - DAMAGE_NO_ARMOR armor does not protect from this damage - DAMAGE_NO_KNOCKBACK do not affect velocity, just view angles - DAMAGE_NO_PROTECTION kills godmode, armor, everything -============ -*/ - -//TA: team is the team that is immune to this damage -void G_SelectiveDamage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, - vec3_t dir, vec3_t point, int damage, int dflags, int mod, int team ) -{ - if( targ->client && ( team != targ->client->ps.stats[ STAT_PTEAM ] ) ) - G_Damage( targ, inflictor, attacker, dir, point, damage, dflags, mod ); -} - -void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, - vec3_t dir, vec3_t point, int damage, int dflags, int mod ) -{ - gclient_t *client; - int take; - int save; - int asave = 0; - int knockback; - - if( !targ->takedamage ) - return; - - // the intermission has allready been qualified for, so don't - // allow any extra scoring - if( level.intermissionQueued ) - return; - - if( !inflictor ) - inflictor = &g_entities[ ENTITYNUM_WORLD ]; - - if( !attacker ) - attacker = &g_entities[ ENTITYNUM_WORLD ]; - - // shootable doors / buttons don't actually have any health - if( targ->s.eType == ET_MOVER ) - { - if( targ->use && ( targ->moverState == MOVER_POS1 || - targ->moverState == ROTATOR_POS1 ) ) - targ->use( targ, inflictor, attacker ); - - return; - } - - client = targ->client; - - if( client ) - { - if( client->noclip ) - return; - } - - if( !dir ) - dflags |= DAMAGE_NO_KNOCKBACK; - else - VectorNormalize( dir ); - - knockback = damage; - - // silly hack to give norf his knockbacking teslas - if( !strcmp( inflictor->classname, "team_human_tesla" ) ) - knockback *= 4; - - if( targ->client ) - { - knockback = (int)( (float)knockback * - BG_FindKnockbackScaleForClass( targ->client->ps.stats[ STAT_PCLASS ] ) ); - } - - if( knockback > 200 ) - knockback = 200; - - if( targ->flags & FL_NO_KNOCKBACK ) - knockback = 0; - - if( dflags & DAMAGE_NO_KNOCKBACK ) - knockback = 0; - - // figure momentum add, even if the damage won't be taken - if( knockback && targ->client ) - { - vec3_t kvel; - float mass; - - mass = 200; - - VectorScale( dir, g_knockback.value * (float)knockback / mass, kvel ); - VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity ); - - // set the timer so that the other client can't cancel - // out the movement immediately - if( !targ->client->ps.pm_time ) - { - int t; - - t = knockback * 2; - if( t < 50 ) - t = 50; - - if( t > 200 ) - t = 200; - - targ->client->ps.pm_time = t; - targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - } - } - - // check for completely getting out of the damage - if( !( dflags & DAMAGE_NO_PROTECTION ) ) - { - - // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target - // if the attacker was on the same team - if( targ != attacker && OnSameTeam( targ, attacker ) ) - { - if( !g_friendlyFire.integer ) - return; - } - - // check for godmode - if ( targ->flags & FL_GODMODE ) - return; - } - - // add to the attacker's hit counter - if( attacker->client && targ != attacker && targ->health > 0 - && targ->s.eType != ET_MISSILE - && targ->s.eType != ET_GENERAL ) - { - if( OnSameTeam( targ, attacker ) ) - attacker->client->ps.persistant[ PERS_HITS ]--; - else - attacker->client->ps.persistant[ PERS_HITS ]++; - } - - take = damage; - save = 0; - - // add to the damage inflicted on a player this frame - // the total will be turned into screen blends and view angle kicks - // at the end of the frame - if( client ) - { - if( attacker ) - client->ps.persistant[ PERS_ATTACKER ] = attacker->s.number; - else - client->ps.persistant[ PERS_ATTACKER ] = ENTITYNUM_WORLD; - - client->damage_armor += asave; - client->damage_blood += take; - client->damage_knockback += knockback; - - if( dir ) - { - VectorCopy ( dir, client->damage_from ); - client->damage_fromWorld = qfalse; - } - else - { - VectorCopy ( targ->r.currentOrigin, client->damage_from ); - client->damage_fromWorld = qtrue; - } - - // set the last client who damaged the target - targ->client->lasthurt_client = attacker->s.number; - targ->client->lasthurt_mod = mod; - take = (int)( (float)take * G_CalcDamageModifier( point, targ, attacker, - client->ps.stats[ STAT_PCLASS ], dflags ) ); - - //if boosted poison every attack - if( attacker->client && attacker->client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) - { - if( !( targ->client->ps.stats[ STAT_STATE ] & SS_POISONED ) && - !BG_InventoryContainsUpgrade( UP_BATTLESUIT, targ->client->ps.stats ) && - mod != MOD_LEVEL2_ZAP && - targ->client->poisonImmunityTime < level.time ) - { - targ->client->ps.stats[ STAT_STATE ] |= SS_POISONED; - targ->client->lastPoisonTime = level.time; - targ->client->lastPoisonClient = attacker; - } - } - } - - if( take < 1 ) - take = 1; - - if( g_debugDamage.integer ) - { - G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, - targ->health, take, asave ); - } - - // do the damage - if( take ) - { - targ->health = targ->health - take; - - if( targ->client ) - targ->client->ps.stats[ STAT_HEALTH ] = targ->health; - - targ->lastDamageTime = level.time; - - //TA: add to the attackers "account" on the target - if( targ->client && attacker->client ) - { - if( attacker != targ && !OnSameTeam( targ, attacker ) ) - targ->credits[ attacker->client->ps.clientNum ] += take; - } - - if( targ->health <= 0 ) - { - if( client ) - targ->flags |= FL_NO_KNOCKBACK; - - if( targ->health < -999 ) - targ->health = -999; - - targ->enemy = attacker; - targ->die( targ, inflictor, attacker, take, mod ); - return; - } - else if( targ->pain ) - targ->pain( targ, attacker, take ); - } -} - - -/* -============ -CanDamage - -Returns qtrue if the inflictor can directly damage the target. Used for -explosions and melee attacks. -============ -*/ -qboolean CanDamage( gentity_t *targ, vec3_t origin ) -{ - vec3_t dest; - trace_t tr; - vec3_t midpoint; - - // use the midpoint of the bounds instead of the origin, because - // bmodels may have their origin is 0,0,0 - VectorAdd( targ->r.absmin, targ->r.absmax, midpoint ); - VectorScale( midpoint, 0.5, midpoint ); - - VectorCopy( midpoint, dest ); - trap_Trace( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID ); - if( tr.fraction == 1.0 || tr.entityNum == targ->s.number ) - return qtrue; - - // this should probably check in the plane of projection, - // rather than in world coordinate, and also include Z - VectorCopy( midpoint, dest ); - dest[ 0 ] += 15.0; - dest[ 1 ] += 15.0; - trap_Trace( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID ); - if( tr.fraction == 1.0 ) - return qtrue; - - VectorCopy( midpoint, dest ); - dest[ 0 ] += 15.0; - dest[ 1 ] -= 15.0; - trap_Trace( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID ); - if( tr.fraction == 1.0 ) - return qtrue; - - VectorCopy( midpoint, dest ); - dest[ 0 ] -= 15.0; - dest[ 1 ] += 15.0; - trap_Trace( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID ); - if( tr.fraction == 1.0 ) - return qtrue; - - VectorCopy( midpoint, dest ); - dest[ 0 ] -= 15.0; - dest[ 1 ] -= 15.0; - trap_Trace( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID ); - if( tr.fraction == 1.0 ) - return qtrue; - - return qfalse; -} - - -//TA: -/* -============ -G_SelectiveRadiusDamage -============ -*/ -qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, - float radius, gentity_t *ignore, int mod, int team ) -{ - float points, dist; - gentity_t *ent; - int entityList[ MAX_GENTITIES ]; - int numListedEntities; - vec3_t mins, maxs; - vec3_t v; - vec3_t dir; - int i, e; - qboolean hitClient = qfalse; - - if( radius < 1 ) - radius = 1; - - for( i = 0; i < 3; i++ ) - { - mins[ i ] = origin[ i ] - radius; - maxs[ i ] = origin[ i ] + radius; - } - - numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - - for( e = 0; e < numListedEntities; e++ ) - { - ent = &g_entities[ entityList[ e ] ]; - - if( ent == ignore ) - continue; - - if( !ent->takedamage ) - continue; - - // find the distance from the edge of the bounding box - for( i = 0 ; i < 3 ; i++ ) - { - if( origin[ i ] < ent->r.absmin[ i ] ) - v[ i ] = ent->r.absmin[ i ] - origin[ i ]; - else if( origin[ i ] > ent->r.absmax[ i ] ) - v[ i ] = origin[ i ] - ent->r.absmax[ i ]; - else - v[ i ] = 0; - } - - dist = VectorLength( v ); - if( dist >= radius ) - continue; - - points = damage * ( 1.0 - dist / radius ); - - if( CanDamage( ent, origin ) ) - { - VectorSubtract( ent->r.currentOrigin, origin, dir ); - // push the center of mass higher than the origin so players - // get knocked into the air more - dir[ 2 ] += 24; - G_SelectiveDamage( ent, NULL, attacker, dir, origin, - (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod, team ); - } - } - - return hitClient; -} - - -/* -============ -G_RadiusDamage -============ -*/ -qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage, - float radius, gentity_t *ignore, int mod ) -{ - float points, dist; - gentity_t *ent; - int entityList[ MAX_GENTITIES ]; - int numListedEntities; - vec3_t mins, maxs; - vec3_t v; - vec3_t dir; - int i, e; - qboolean hitClient = qfalse; - - if( radius < 1 ) - radius = 1; - - for( i = 0; i < 3; i++ ) - { - mins[ i ] = origin[ i ] - radius; - maxs[ i ] = origin[ i ] + radius; - } - - numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - - for( e = 0; e < numListedEntities; e++ ) - { - ent = &g_entities[ entityList[ e ] ]; - - if( ent == ignore ) - continue; - - if( !ent->takedamage ) - continue; - - // find the distance from the edge of the bounding box - for( i = 0; i < 3; i++ ) - { - if( origin[ i ] < ent->r.absmin[ i ] ) - v[ i ] = ent->r.absmin[ i ] - origin[ i ]; - else if( origin[ i ] > ent->r.absmax[ i ] ) - v[ i ] = origin[ i ] - ent->r.absmax[ i ]; - else - v[ i ] = 0; - } - - dist = VectorLength( v ); - if( dist >= radius ) - continue; - - points = damage * ( 1.0 - dist / radius ); - - if( CanDamage( ent, origin ) ) - { - VectorSubtract( ent->r.currentOrigin, origin, dir ); - // push the center of mass higher than the origin so players - // get knocked into the air more - dir[ 2 ] += 24; - G_Damage( ent, NULL, attacker, dir, origin, - (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod ); - } - } - - return hitClient; -} |