summaryrefslogtreecommitdiff
path: root/src/game/g_combat.c.orig
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_combat.c.orig')
-rw-r--r--src/game/g_combat.c.orig1468
1 files changed, 0 insertions, 1468 deletions
diff --git a/src/game/g_combat.c.orig b/src/game/g_combat.c.orig
deleted file mode 100644
index f4e89ee..0000000
--- a/src/game/g_combat.c.orig
+++ /dev/null
@@ -1,1468 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2009 Darklegion Development
-
-This file is part of Tremulous.
-
-Tremulous is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Tremulous 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. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-#include "g_local.h"
-
-damageRegion_t g_damageRegions[ PCL_NUM_CLASSES ][ MAX_DAMAGE_REGIONS ];
-int g_numDamageRegions[ PCL_NUM_CLASSES ];
-
-damageRegion_t g_armourRegions[ UP_NUM_UPGRADES ][ MAX_DAMAGE_REGIONS ];
-int g_numArmourRegions[ UP_NUM_UPGRADES ];
-
-/*
-============
-AddScore
-
-Adds score to the client
-============
-*/
-void AddScore( gentity_t *ent, int score )
-{
- if( !ent->client )
- return;
-
- // make alien and human scores equivalent
- if ( ent->client->pers.teamSelection == TEAM_ALIENS )
- {
- score = rint( ((float)score) / 2.0f );
- }
-
- // scale values down to fit the scoreboard better
- score = rint( ((float)score) / 50.0f );
-
- ent->client->ps.persistant[ PERS_SCORE ] += score;
- CalculateRanks( );
-}
-
-/*
-==================
-LookAtKiller
-==================
-*/
-void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker )
-{
-
- if ( attacker && attacker != self )
- self->client->ps.stats[ STAT_VIEWLOCK ] = attacker - g_entities;
- else if( inflictor && inflictor != self )
- self->client->ps.stats[ STAT_VIEWLOCK ] = inflictor - g_entities;
- else
- self->client->ps.stats[ STAT_VIEWLOCK ] = self - g_entities;
-}
-
-// 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_TRAMPLE",
- "MOD_LEVEL4_CRUSH",
-
- "MOD_SLOWBLOB",
- "MOD_POISON",
- "MOD_SWARM",
-
- "MOD_HSPAWN",
- "MOD_TESLAGEN",
- "MOD_MGTURRET",
- "MOD_REACTOR",
-
- "MOD_ASPAWN",
- "MOD_ATUBE",
- "MOD_OVERMIND",
- "MOD_DECONSTRUCT",
- "MOD_REPLACE",
- "MOD_NOCREEP"
-};
-
-/*
-==================
-G_RewardAttackers
-
-Function to distribute rewards to entities that killed this one.
-Returns the total damage dealt.
-==================
-*/
-float G_RewardAttackers( gentity_t *self )
-{
- float value, totalDamage = 0;
- int team, i, maxHealth = 0;
- int alienCredits = 0, humanCredits = 0;
- gentity_t *player;
-
- // Total up all the damage done by non-teammates
- for( i = 0; i < level.maxclients; i++ )
- {
- player = g_entities + i;
-
- if( !OnSameTeam( self, player ) ||
- self->buildableTeam != player->client->ps.stats[ STAT_TEAM ] )
- totalDamage += (float)self->credits[ i ];
- }
-
- if( totalDamage <= 0.0f )
- return 0.0f;
-
- // Only give credits for killing players and buildables
- if( self->client )
- {
- value = BG_GetValueOfPlayer( &self->client->ps );
- team = self->client->pers.teamSelection;
- maxHealth = self->client->ps.stats[ STAT_MAX_HEALTH ];
- }
- else if( self->s.eType == ET_BUILDABLE )
- {
- value = BG_Buildable( self->s.modelindex, self->cuboidSize )->value;
-
- // only give partial credits for a buildable not yet completed
- if( !self->spawned )
- {
- value *= (float)( level.time - self->buildTime ) /
- BG_Buildable( self->s.modelindex, self->cuboidSize )->buildTime;
- }
-
- team = self->buildableTeam;
- maxHealth = BG_Buildable( self->s.modelindex, self->cuboidSize )->health;
- }
- else
- return totalDamage;
-
- // Give credits and empty the array
- for( i = 0; i < level.maxclients; i++ )
- {
- int stageValue = value * self->credits[ i ] / totalDamage;
- player = g_entities + i;
-
- if( player->client->pers.teamSelection != team )
- {
- if( totalDamage < maxHealth )
- stageValue *= totalDamage / maxHealth;
-
- if( !self->credits[ i ] || player->client->ps.stats[ STAT_TEAM ] == team )
- continue;
-
- AddScore( player, stageValue );
-
- // killing buildables earns score, but not credits
- if( self->s.eType != ET_BUILDABLE )
- {
- G_AddCreditToClient( player->client, stageValue, qtrue );
-
- // add to stage counters
- if( player->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
- alienCredits += stageValue;
- else if( player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
- humanCredits += stageValue;
- }
- }
- self->credits[ i ] = 0;
- }
-
- if( alienCredits )
- {
- trap_Cvar_Set( "g_alienCredits",
- va( "%d", g_alienCredits.integer + alienCredits ) );
- trap_Cvar_Update( &g_alienCredits );
- }
- if( humanCredits )
- {
- trap_Cvar_Set( "g_humanCredits",
- va( "%d", g_humanCredits.integer + humanCredits ) );
- trap_Cvar_Update( &g_humanCredits );
- }
-
- return totalDamage;
-}
-
-/*
-==================
-player_die
-==================
-*/
-void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath )
-{
- gentity_t *ent, *ent2;
- int anim;
- int killer;
- int i;
- char *killerName, *obit;
- vec3_t dir;
-
- if( self->client->ps.pm_type == PM_DEAD )
- return;
-
- if( level.intermissiontime )
- return;
-
- 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 = "<world>";
- }
- else
- {
- killer = ENTITYNUM_WORLD;
- killerName = "<world>";
- }
-
- if( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) )
- // fall back on the number
- obit = va( "%d", meansOfDeath );
- else
- obit = modNames[ meansOfDeath ];
-
- G_LogPrintf( "Die: %d %d %s: %s" S_COLOR_WHITE " killed %s\n",
- killer,
- self - g_entities,
- obit,
- killerName,
- self->client->pers.netname );
-
- // deactivate all upgrades
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- BG_DeactivateUpgrade( i, self->client->ps.stats );
-
- // kill all player's buildables if they havent spawned yet
- // this should eliminate build timer hacks for ever
- dir[0] = dir[1] = 0.0f;
- dir[2] = 1.0f;
-
- for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- if( ent == self )
- continue;
-
- if( ent->spawned )
- continue;
-
- if( ent->builtBy != self->client->ps.clientNum )
- continue;
-
- G_Damage( ent, self, attacker, dir, dir, ent->health, 0, MOD_DECONSTRUCT );
- }
-
- // 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 ) ) && meansOfDeath != MOD_HSPAWN )
- {
- //punish team kills and suicides
- if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
- {
- G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, qtrue );
- AddScore( attacker, -ALIEN_TK_SUICIDE_PENALTY );
- }
- else if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
- {
- G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, qtrue );
- AddScore( attacker, -HUMAN_TK_SUICIDE_PENALTY );
- }
- }
- }
- else if( attacker->s.eType != ET_BUILDABLE )
- {
- if( self->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
- AddScore( self, -ALIEN_TK_SUICIDE_PENALTY );
- else if( self->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
- AddScore( self, -HUMAN_TK_SUICIDE_PENALTY );
- }
-
- // give credits for killing this player
- G_RewardAttackers( self );
-
- ScoreboardMessage( 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.spectatorState == SPECTATOR_NOT )
- continue;
-
- if( client->sess.spectatorClient == self->s.number )
- ScoreboardMessage( g_entities + i );
- }
-
- 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;
-
- // clear misc
- memset( self->client->ps.misc, 0, sizeof( self->client->ps.misc ) );
-
- {
- // 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;
- }
-
- // 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 );
-
- // globally cycle through the different death animations
- i = ( i + 1 ) % 3;
- }
-
- trap_LinkEntity( self );
-}
-
-/*
-===============
-G_ParseDmgScript
-===============
-*/
-static int G_ParseDmgScript( damageRegion_t *regions, char *buf )
-{
- char *token;
- float angleSpan, heightSpan;
- int count;
-
- for( count = 0; ; count++ )
- {
- token = COM_Parse( &buf );
- if( !token[ 0 ] )
- break;
-
- if( strcmp( token, "{" ) )
- {
- COM_ParseError( "Missing {" );
- break;
- }
-
- if( count >= MAX_DAMAGE_REGIONS )
- {
- COM_ParseError( "Max damage regions exceeded" );
- break;
- }
-
- // defaults
- regions[ count ].name[ 0 ] = '\0';
- regions[ count ].minHeight = 0.0f;
- regions[ count ].maxHeight = 1.0f;
- regions[ count ].minAngle = 0.0f;
- regions[ count ].maxAngle = 360.0f;
- regions[ count ].modifier = 1.0f;
- regions[ count ].crouch = qfalse;
-
- while( 1 )
- {
- token = COM_ParseExt( &buf, qtrue );
-
- if( !token[ 0 ] )
- {
- COM_ParseError( "Unexpected end of file" );
- break;
- }
-
- if( !Q_stricmp( token, "}" ) )
- {
- break;
- }
- else if( !strcmp( token, "name" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( token[ 0 ] )
- Q_strncpyz( regions[ count ].name, token,
- sizeof( regions[ count ].name ) );
- }
- else if( !strcmp( token, "minHeight" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( !token[ 0 ] )
- strcpy( token, "0" );
- regions[ count ].minHeight = atof( token );
- }
- else if( !strcmp( token, "maxHeight" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( !token[ 0 ] )
- strcpy( token, "100" );
- regions[ count ].maxHeight = atof( token );
- }
- else if( !strcmp( token, "minAngle" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( !token[ 0 ] )
- strcpy( token, "0" );
- regions[ count ].minAngle = atoi( token );
- }
- else if( !strcmp( token, "maxAngle" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( !token[ 0 ] )
- strcpy( token, "360" );
- regions[ count ].maxAngle = atoi( token );
- }
- else if( !strcmp( token, "modifier" ) )
- {
- token = COM_ParseExt( &buf, qfalse );
- if( !token[ 0 ] )
- strcpy( token, "1.0" );
- regions[ count ].modifier = atof( token );
- }
- else if( !strcmp( token, "crouch" ) )
- {
- regions[ count ].crouch = qtrue;
- }
- else
- {
- COM_ParseWarning("Unknown token \"%s\"", token);
- }
- }
-
- // Angle portion covered
- angleSpan = regions[ count ].maxAngle - regions[ count ].minAngle;
- if( angleSpan < 0.0f )
- angleSpan += 360.0f;
- angleSpan /= 360.0f;
-
- // Height portion covered
- heightSpan = regions[ count ].maxHeight - regions[ count ].minHeight;
- if( heightSpan < 0.0f )
- heightSpan = -heightSpan;
- if( heightSpan > 1.0f )
- heightSpan = 1.0f;
-
- regions[ count ].area = angleSpan * heightSpan;
- if( !regions[ count ].area )
- regions[ count ].area = 0.00001f;
- }
-
- return count;
-}
-
-/*
-============
-GetRegionDamageModifier
-============
-*/
-static float GetRegionDamageModifier( gentity_t *targ, int class, int piece )
-{
- damageRegion_t *regions, *overlap;
- float modifier = 0.0f, areaSum = 0.0f;
- int j, i;
- qboolean crouch;
-
- crouch = targ->client->ps.pm_flags & PMF_DUCKED;
- overlap = &g_damageRegions[ class ][ piece ];
-
- if( g_debugDamage.integer > 2 )
- G_Printf( "GetRegionDamageModifier():\n"
- ". bodyRegion = [%d %d %f %f] (%s)\n"
- ". modifier = %f\n",
- overlap->minAngle, overlap->maxAngle,
- overlap->minHeight, overlap->maxHeight,
- overlap->name, overlap->modifier );
-
- // Find the armour layer modifier, assuming that none of the armour regions
- // overlap and that any areas that are not covered have a modifier of 1.0
- for( j = UP_NONE + 1; j < UP_NUM_UPGRADES; j++ )
- {
- if( !BG_InventoryContainsUpgrade( j, targ->client->ps.stats ) ||
- !g_numArmourRegions[ j ] )
- continue;
- regions = g_armourRegions[ j ];
-
- for( i = 0; i < g_numArmourRegions[ j ]; i++ )
- {
- float overlapMaxA, regionMinA, regionMaxA, angleSpan, heightSpan, area;
-
- if( regions[ i ].crouch != crouch )
- continue;
-
- // Convert overlap angle to 0 to max
- overlapMaxA = overlap->maxAngle - overlap->minAngle;
- if( overlapMaxA < 0.0f )
- overlapMaxA += 360.0f;
-
- // Convert region angles to match overlap
- regionMinA = regions[ i ].minAngle - overlap->minAngle;
- if( regionMinA < 0.0f )
- regionMinA += 360.0f;
- regionMaxA = regions[ i ].maxAngle - overlap->minAngle;
- if( regionMaxA < 0.0f )
- regionMaxA += 360.0f;
-
- // Overlapping Angle portion
- if( regionMinA <= regionMaxA )
- {
- angleSpan = 0.0f;
- if( regionMinA < overlapMaxA )
- {
- if( regionMaxA > overlapMaxA )
- regionMaxA = overlapMaxA;
- angleSpan = regionMaxA - regionMinA;
- }
- }
- else
- {
- if( regionMaxA > overlapMaxA )
- regionMaxA = overlapMaxA;
- angleSpan = regionMaxA;
- if( regionMinA < overlapMaxA )
- angleSpan += overlapMaxA - regionMinA;
- }
- angleSpan /= 360.0f;
-
- // Overlapping height portion
- heightSpan = MIN( overlap->maxHeight, regions[ i ].maxHeight ) -
- MAX( overlap->minHeight, regions[ i ].minHeight );
- if( heightSpan < 0.0f )
- heightSpan = 0.0f;
- if( heightSpan > 1.0f )
- heightSpan = 1.0f;
-
- if( g_debugDamage.integer > 2 )
- G_Printf( ". armourRegion = [%d %d %f %f] (%s)\n"
- ". . modifier = %f\n"
- ". . angleSpan = %f\n"
- ". . heightSpan = %f\n",
- regions[ i ].minAngle, regions[ i ].maxAngle,
- regions[ i ].minHeight, regions[ i ].maxHeight,
- regions[ i ].name, regions[ i ].modifier,
- angleSpan, heightSpan );
-
- areaSum += area = angleSpan * heightSpan;
- modifier += regions[ i ].modifier * area;
- }
- }
-
- if( g_debugDamage.integer > 2 )
- G_Printf( ". areaSum = %f\n"
- ". armourModifier = %f\n", areaSum, modifier );
-
- return overlap->modifier * ( overlap->area + modifier - areaSum );
-}
-
-/*
-============
-GetNonLocDamageModifier
-============
-*/
-static float GetNonLocDamageModifier( gentity_t *targ, int class )
-{
- float modifier = 0.0f, area = 0.0f, scale = 0.0f;
- int i;
- qboolean crouch;
-
- // For every body region, use stretch-armor formula to apply armour modifier
- // for any overlapping area that armour shares with the body region
- crouch = targ->client->ps.pm_flags & PMF_DUCKED;
- for( i = 0; i < g_numDamageRegions[ class ]; i++ )
- {
- damageRegion_t *region;
-
- region = &g_damageRegions[ class ][ i ];
-
- if( region->crouch != crouch )
- continue;
-
- modifier += GetRegionDamageModifier( targ, class, i );
-
- scale += region->modifier * region->area;
- area += region->area;
-
- }
-
- modifier = !scale ? 1.0f : 1.0f + ( modifier / scale - 1.0f ) * area;
-
- if( g_debugDamage.integer > 1 )
- G_Printf( "GetNonLocDamageModifier() modifier:%f, area:%f, scale:%f\n",
- modifier, area, scale );
-
- return modifier;
-}
-
-/*
-============
-GetPointDamageModifier
-
-Returns the damage region given an angle and a height proportion
-============
-*/
-static float GetPointDamageModifier( gentity_t *targ, damageRegion_t *regions,
- int len, float angle, float height )
-{
- float modifier = 1.0f;
- int i;
-
- for( i = 0; i < len; i++ )
- {
- if( regions[ i ].crouch != ( targ->client->ps.pm_flags & PMF_DUCKED ) )
- continue;
-
- // Angle must be within range
- if( ( regions[ i ].minAngle <= regions[ i ].maxAngle &&
- ( angle < regions[ i ].minAngle ||
- angle > regions[ i ].maxAngle ) ) ||
- ( regions[ i ].minAngle > regions[ i ].maxAngle &&
- angle > regions[ i ].maxAngle && angle < regions[ i ].minAngle ) )
- continue;
-
- // Height must be within range
- if( height < regions[ i ].minHeight || height > regions[ i ].maxHeight )
- continue;
-
- modifier *= regions[ i ].modifier;
- }
-
- if( g_debugDamage.integer )
- G_Printf( "GetDamageRegionModifier(angle = %f, height = %f): %f\n",
- angle, height, modifier );
-
- return modifier;
-}
-
-/*
-============
-G_CalcDamageModifier
-============
-*/
-static float G_CalcDamageModifier( vec3_t point, gentity_t *targ, gentity_t *attacker, int class, int dflags )
-{
- vec3_t targOrigin, bulletPath, bulletAngle, pMINUSfloor, floor, normal;
- float clientHeight, hitRelative, hitRatio, modifier;
- int hitRotation, i;
-
- if( point == NULL )
- return 1.0f;
-
- // Don't need to calculate angles and height for non-locational damage
- if( dflags & DAMAGE_NO_LOCDAMAGE )
- return GetNonLocDamageModifier( targ, class );
-
- // Get the point location relative to the floor under the target
- if( g_unlagged.integer && targ->client && targ->client->unlaggedCalc.used )
- VectorCopy( targ->client->unlaggedCalc.origin, targOrigin );
- else
- VectorCopy( targ->r.currentOrigin, targOrigin );
-
- BG_GetClientNormal( &targ->client->ps, normal );
- VectorMA( targOrigin, targ->r.mins[ 2 ], normal, floor );
- VectorSubtract( point, floor, pMINUSfloor );
-
- // Get the proportion of the target height where the hit landed
- clientHeight = targ->r.maxs[ 2 ] - targ->r.mins[ 2 ];
-
- if( !clientHeight )
- clientHeight = 1.0f;
-
- hitRelative = DotProduct( normal, pMINUSfloor ) / VectorLength( normal );
-
- if( hitRelative < 0.0f )
- hitRelative = 0.0f;
-
- if( hitRelative > clientHeight )
- hitRelative = clientHeight;
-
- hitRatio = hitRelative / clientHeight;
-
- // Get the yaw of the attack relative to the target's view yaw
- VectorSubtract( point, targOrigin, bulletPath );
- vectoangles( bulletPath, bulletAngle );
-
- hitRotation = AngleNormalize360( targ->client->ps.viewangles[ YAW ] -
- bulletAngle[ YAW ] );
-
- // Get modifiers from the target's damage regions
- modifier = GetPointDamageModifier( targ, g_damageRegions[ class ],
- g_numDamageRegions[ class ],
- hitRotation, hitRatio );
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- if( BG_InventoryContainsUpgrade( i, targ->client->ps.stats ) )
- {
- modifier *= GetPointDamageModifier( targ, g_armourRegions[ i ],
- g_numArmourRegions[ i ],
- hitRotation, hitRatio );
- }
- }
-
- return modifier;
-}
-
-
-/*
-============
-G_InitDamageLocations
-============
-*/
-void G_InitDamageLocations( void )
-{
- char *modelName;
- char filename[ MAX_QPATH ];
- int i;
- int len;
- fileHandle_t fileHandle;
- char buffer[ MAX_DAMAGE_REGION_TEXT ];
-
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
- {
- modelName = BG_ClassConfig( i )->modelName;
- Com_sprintf( filename, sizeof( filename ),
- "models/players/%s/locdamage.cfg", modelName );
-
- len = trap_FS_FOpenFile( filename, &fileHandle, FS_READ );
- if ( !fileHandle )
- {
- G_Printf( S_COLOR_RED "file not found: %s\n", filename );
- continue;
- }
-
- if( len >= MAX_DAMAGE_REGION_TEXT )
- {
- G_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i",
- filename, len, MAX_DAMAGE_REGION_TEXT );
- trap_FS_FCloseFile( fileHandle );
- continue;
- }
-
- COM_BeginParseSession( filename );
-
- trap_FS_Read( buffer, len, fileHandle );
- buffer[len] = 0;
- trap_FS_FCloseFile( fileHandle );
-
- g_numDamageRegions[ i ] = G_ParseDmgScript( g_damageRegions[ i ], buffer );
- }
-
- for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
- {
- modelName = BG_Upgrade( i )->name;
- 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_DAMAGE_REGION_TEXT )
- {
- G_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i",
- filename, len, MAX_DAMAGE_REGION_TEXT );
- trap_FS_FCloseFile( fileHandle );
- continue;
- }
-
- COM_BeginParseSession( filename );
-
- trap_FS_Read( buffer, len, fileHandle );
- buffer[len] = 0;
- trap_FS_FCloseFile( fileHandle );
-
- g_numArmourRegions[ i ] = G_ParseDmgScript( g_armourRegions[ i ], buffer );
- }
-}
-
-
-/*
-============
-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
-============
-*/
-
-// 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_TEAM ] ) )
- 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 asave = 0;
- int knockback;
-
- // Can't deal damage sometimes
- if( !targ->takedamage || targ->health <= 0 || 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 && client->noclip )
- return;
-
- if( !dir )
- dflags |= DAMAGE_NO_KNOCKBACK;
- else
- VectorNormalize( dir );
-
- knockback = damage;
-
- if( inflictor->s.weapon != WP_NONE )
- {
- knockback = (int)( (float)knockback *
- BG_Weapon( inflictor->s.weapon )->knockbackScale );
- }
-
- if( targ->client )
- {
- knockback = (int)( (float)knockback *
- BG_Class( targ->client->ps.stats[ STAT_CLASS ] )->knockbackScale );
- }
-
- // Too much knockback from falling really far makes you "bounce" and
- // looks silly. However, none at all also looks bad. Cap it.
- if( mod == MOD_FALLING && knockback > 50 )
- knockback = 50;
-
- 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;
- }
- }
-
- // don't do friendly fire on movement attacks
- if( ( mod == MOD_LEVEL4_TRAMPLE || mod == MOD_LEVEL3_POUNCE ||
- mod == MOD_LEVEL4_CRUSH ) &&
- targ->s.eType == ET_BUILDABLE && targ->buildableTeam == TEAM_ALIENS )
- {
- return;
- }
-
- // 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 ) )
- {
- // don't do friendly fire on movement attacks
- if( mod == MOD_LEVEL4_TRAMPLE || mod == MOD_LEVEL3_POUNCE ||
- mod == MOD_LEVEL4_CRUSH )
- return;
-
- // if dretchpunt is enabled and this is a dretch, do dretchpunt instead of damage
- if( g_dretchPunt.integer &&
- targ->client->ps.stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL0 )
- {
- vec3_t dir, push;
-
- VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, dir );
- VectorNormalizeFast( dir );
- VectorScale( dir, ( damage * 10.0f ), push );
- push[2] = 64.0f;
- VectorAdd( targ->client->ps.velocity, push, targ->client->ps.velocity );
- return;
- }
-
- // check if friendly fire has been disabled
- if( !g_friendlyFire.integer )
- {
- return;
- }
- }
-
- if( targ->s.eType == ET_BUILDABLE && attacker->client &&
- mod != MOD_DECONSTRUCT && mod != MOD_SUICIDE &&
- mod != MOD_REPLACE && mod != MOD_NOCREEP )
- {
- if( targ->buildableTeam == attacker->client->pers.teamSelection &&
- !g_friendlyBuildableFire.integer )
- {
- return;
- }
-
- // base is under attack warning if DCC'd
- if( targ->buildableTeam == TEAM_HUMANS && G_FindDCC( targ ) &&
- level.time > level.humanBaseAttackTimer )
- {
- level.humanBaseAttackTimer = level.time + DC_ATTACK_PERIOD;
- G_BroadcastEvent( EV_DCC_ATTACK, 0 );
- }
- }
-
- // 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;
-
- // 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)( take * G_CalcDamageModifier( point, targ, attacker,
- client->ps.stats[ STAT_CLASS ],
- dflags ) + 0.5f );
-
- //if boosted poison every attack
- if( attacker->client && attacker->client->ps.stats[ STAT_STATE ] & SS_BOOSTED )
- {
- if( (targ->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) &&
- mod != MOD_LEVEL2_ZAP && mod != MOD_POISON &&
- mod != MOD_LEVEL1_PCLOUD && mod != MOD_HSPAWN &&
- mod != MOD_ASPAWN && 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;
- targ->nextRegenTime = level.time + ALIEN_REGEN_DAMAGE_TIME;
-
- // add to the attackers "account" on the target
- if( attacker->client && attacker != targ )
- 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 )
- {
- //if(targ->s.eType==ET_BUILDABLE&&BG_Buildable(targ->s.modelindex,NULL)->cuboid)
- // VectorCopy(point,targ->s.angles2);
- 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;
-}
-
-/*
-============
-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;
-
- if( ent->flags & FL_NOTARGET )
- 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 ) && ent->client &&
- ent->client->ps.stats[ STAT_TEAM ] != team )
- {
- 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;
- hitClient = qtrue;
- G_Damage( ent, NULL, attacker, dir, origin,
- (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod );
- }
- }
-
- 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;
- hitClient = qtrue;
- G_Damage( ent, NULL, attacker, dir, origin,
- (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod );
- }
- }
-
- return hitClient;
-}
-
-/*
-================
-G_LogDestruction
-
-Log deconstruct/destroy events
-================
-*/
-void G_LogDestruction( gentity_t *self, gentity_t *actor, int mod )
-{
- buildFate_t fate;
-
- switch( mod )
- {
- case MOD_DECONSTRUCT:
- fate = BF_DECONSTRUCT;
- break;
- case MOD_REPLACE:
- fate = BF_REPLACE;
- break;
- case MOD_NOCREEP:
- fate = ( actor->client ) ? BF_UNPOWER : BF_AUTO;
- break;
- default:
- if( actor->client )
- {
- if( actor->client->pers.teamSelection ==
- BG_Buildable( self->s.modelindex, NULL )->team )
- {
- fate = BF_TEAMKILL;
- }
- else
- fate = BF_DESTROY;
- }
- else
- fate = BF_AUTO;
- break;
- }
- G_BuildLogAuto( actor, self, fate );
-
- // don't log when marked structures are removed
- if( mod == MOD_REPLACE )
- return;
-
- G_LogPrintf( S_COLOR_YELLOW "Deconstruct: %d %d %s %s: %s %s by %s\n",
- actor - g_entities,
- self - g_entities,
- BG_Buildable( self->s.modelindex, NULL )->name,
- modNames[ mod ],
- G_CuboidName(self->s.modelindex,self->cuboidSize,qtrue),
- mod == MOD_DECONSTRUCT ? "deconstructed" : "destroyed",
- actor->client ? actor->client->pers.netname : "<world>" );
-
- // No-power deaths for humans come after some minutes and it's confusing
- // when the messages appear attributed to the deconner. Just don't print them.
- if( mod == MOD_NOCREEP && actor->client &&
- actor->client->pers.teamSelection == TEAM_HUMANS )
- return;
-
- if( actor->client && actor->client->pers.teamSelection ==
- BG_Buildable( self->s.modelindex, NULL )->team )
- {
- G_TeamCommand( actor->client->ps.stats[ STAT_TEAM ],
- va( "print \"%s ^3%s^7 by %s\n\"",
- G_CuboidName(self->s.modelindex,self->cuboidSize,qfalse),
- mod == MOD_DECONSTRUCT ? "DECONSTRUCTED" : "DESTROYED",
- actor->client->pers.netname ) );
- }
-
-}