summaryrefslogtreecommitdiff
path: root/src/cgame/cg_buildable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgame/cg_buildable.c')
-rw-r--r--src/cgame/cg_buildable.c410
1 files changed, 233 insertions, 177 deletions
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index e678ebd..7d7596b 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
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,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,12 +17,11 @@ 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
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
-
#include "cg_local.h"
char *cg_buildableSoundNames[ MAX_BUILDABLE_ANIMATIONS ] =
@@ -95,6 +95,7 @@ void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir )
#define CREEP_SIZE 64.0f
+#define CREEP_DISTANCE 64.0f
/*
==================
@@ -107,7 +108,7 @@ static void CG_Creep( centity_t *cent )
float size, frac;
trace_t tr;
vec3_t temp, origin;
- int scaleUpTime = BG_FindBuildTimeForBuildable( cent->currentState.modelindex );
+ int scaleUpTime = BG_Buildable( cent->currentState.modelindex )->buildTime;
int time;
time = cent->currentState.time;
@@ -121,7 +122,7 @@ static void CG_Creep( centity_t *cent )
else
frac = 1.0f;
}
- else
+ else if( time < 0 )
{
msec = cg.time + time;
if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME )
@@ -131,7 +132,7 @@ static void CG_Creep( centity_t *cent )
}
VectorCopy( cent->currentState.origin2, temp );
- VectorScale( temp, -4096, temp );
+ VectorScale( temp, -CREEP_DISTANCE, temp );
VectorAdd( temp, cent->lerpOrigin, temp );
CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_PLAYERSOLID );
@@ -140,7 +141,7 @@ static void CG_Creep( centity_t *cent )
size = CREEP_SIZE * frac;
- if( size > 0.0f )
+ if( size > 0.0f && tr.fraction < 1.0f )
CG_ImpactMark( cgs.media.creepShader, origin, cent->currentState.origin2,
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue );
}
@@ -168,12 +169,13 @@ static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if( len <= 0 )
+ if( len < 0 )
return qfalse;
- if( len >= sizeof( text ) - 1 )
+ if( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -258,12 +260,13 @@ static qboolean CG_ParseBuildableSoundFile( const char *filename, buildable_t bu
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 )
+ if ( len < 0 )
return qfalse;
- if ( len >= sizeof( text ) - 1 )
+ if ( len == 0 || len >= sizeof( text ) - 1 )
{
- CG_Printf( "File %s too long\n", filename );
+ trap_FS_FCloseFile( f );
+ CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" );
return qfalse;
}
@@ -335,7 +338,7 @@ void CG_InitBuildables( void )
for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
{
- buildableName = BG_FindNameForBuildable( i );
+ buildableName = BG_Buildable( i )->name;
//animation.cfg
Com_sprintf( filename, sizeof( filename ), "models/buildables/%s/animation.cfg", buildableName );
@@ -350,7 +353,8 @@ void CG_InitBuildables( void )
//models
for( j = 0; j <= 3; j++ )
{
- if( ( modelFile = BG_FindModelsForBuildable( i, j ) ) )
+ modelFile = BG_BuildableConfig( i )->models[ j ];
+ if( strlen( modelFile ) > 0 )
cg_buildables[ i ].models[ j ] = trap_R_RegisterModel( modelFile );
}
@@ -372,7 +376,7 @@ void CG_InitBuildables( void )
else
{
//file doesn't exist - use default
- if( BG_FindTeamForBuildable( i ) == BIT_ALIENS )
+ if( BG_Buildable( i )->team == TEAM_ALIENS )
cg_buildables[ i ].sounds[ j ].sound = defaultAlienSounds[ j ];
else
cg_buildables[ i ].sounds[ j ].sound = defaultHumanSounds[ j ];
@@ -426,24 +430,15 @@ cg.time should be between oldFrameTime and frameTime after exit
*/
static void CG_RunBuildableLerpFrame( centity_t *cent )
{
- int f, numFrames;
buildable_t buildable = cent->currentState.modelindex;
lerpFrame_t *lf = &cent->lerpFrame;
- animation_t *anim;
buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT );
- // debugging tool to get no animations
- if( cg_animSpeed.integer == 0 )
- {
- lf->oldFrame = lf->frame = lf->backlerp = 0;
- return;
- }
-
// see if the animation sequence is switching
if( newAnimation != lf->animationNumber || !lf->animation )
{
if( cg_debugRandom.integer )
- CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n",
+ CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: 0x%p\n",
newAnimation, lf->animationNumber, lf->animation );
CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation );
@@ -453,7 +448,7 @@ static void CG_RunBuildableLerpFrame( centity_t *cent )
{
if( cg_debugRandom.integer )
CG_Printf( "Sound for animation %d for a %s\n",
- newAnimation, BG_FindHumanNameForBuildable( buildable ) );
+ newAnimation, BG_Buildable( buildable )->humanName );
trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO,
cg_buildables[ buildable ].sounds[ newAnimation ].sound );
@@ -465,72 +460,14 @@ static void CG_RunBuildableLerpFrame( centity_t *cent )
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin,
cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound );
- // if we have passed the current frame, move it to
- // oldFrame and calculate a new frame
- if( cg.time >= lf->frameTime )
- {
- lf->oldFrame = lf->frame;
- lf->oldFrameTime = lf->frameTime;
+ CG_RunLerpFrame( lf, 1.0f );
- // get the next frame based on the animation
- anim = lf->animation;
- if( !anim->frameLerp )
- return; // shouldn't happen
-
- if ( cg.time < lf->animationTime )
- lf->frameTime = lf->animationTime; // initial lerp
- else
- lf->frameTime = lf->oldFrameTime + anim->frameLerp;
-
- f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
- numFrames = anim->numFrames;
- if(anim->flipflop)
- numFrames *= 2;
-
- if( f >= numFrames )
- {
- f -= numFrames;
- if( anim->loopFrames )
- {
- f %= anim->loopFrames;
- f += anim->numFrames - anim->loopFrames;
- }
- else
- {
- f = numFrames - 1;
- // the animation is stuck at the end, so it
- // can immediately transition to another sequence
- lf->frameTime = cg.time;
- cent->buildableAnim = cent->currentState.torsoAnim;
- }
- }
-
- if( anim->reversed )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- else if( anim->flipflop && f >= anim->numFrames )
- lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
- else
- lf->frame = anim->firstFrame + f;
-
- if( cg.time > lf->frameTime )
- {
- lf->frameTime = cg.time;
- if( cg_debugAnim.integer )
- CG_Printf( "Clamp lf->frameTime\n");
- }
+ // animation ended
+ if( lf->frameTime == cg.time )
+ {
+ cent->buildableAnim = cent->currentState.torsoAnim;
+ cent->buildableIdleAnim = qtrue;
}
-
- if( lf->frameTime > cg.time + 200 )
- lf->frameTime = cg.time;
-
- if( lf->oldFrameTime > cg.time )
- lf->oldFrameTime = cg.time;
-
- // calculate current lerp value
- if( lf->frameTime == lf->oldFrameTime )
- lf->backlerp = 0;
- else
- lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
}
/*
@@ -544,10 +481,13 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
//if no animation is set default to idle anim
if( cent->buildableAnim == BANIM_NONE )
+ {
cent->buildableAnim = es->torsoAnim;
+ cent->buildableIdleAnim = qtrue;
+ }
//display the first frame of the construction anim if not yet spawned
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
{
animation_t *anim = &cg_buildables[ es->modelindex ].animations[ BANIM_CONSTRUCT1 ];
@@ -572,12 +512,23 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
CG_Printf( "%d->%d l:%d t:%d %s(%d)\n",
cent->oldBuildableAnim, cent->buildableAnim,
es->legsAnim, es->torsoAnim,
- BG_FindHumanNameForBuildable( es->modelindex ), es->number );
+ BG_Buildable( es->modelindex )->humanName, es->number );
if( cent->buildableAnim == es->torsoAnim || es->legsAnim & ANIM_FORCEBIT )
+ {
cent->buildableAnim = cent->oldBuildableAnim = es->legsAnim;
+ cent->buildableIdleAnim = qfalse;
+ }
else
+ {
cent->buildableAnim = cent->oldBuildableAnim = es->torsoAnim;
+ cent->buildableIdleAnim = qtrue;
+ }
+ }
+ else if( cent->buildableIdleAnim == qtrue &&
+ cent->buildableAnim != es->torsoAnim )
+ {
+ cent->buildableAnim = es->torsoAnim;
}
CG_RunBuildableLerpFrame( cent );
@@ -588,7 +539,7 @@ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *b
}
}
-#define TRACE_DEPTH 64.0f
+#define TRACE_DEPTH 15.0f
/*
===============
@@ -600,8 +551,9 @@ static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t
const vec3_t mins, const vec3_t maxs,
vec3_t outAxis[ 3 ], vec3_t outOrigin )
{
- vec3_t forward, start, end;
+ vec3_t forward, end;
trace_t tr;
+ float fraction;
AngleVectors( angles, forward, NULL, NULL );
VectorCopy( normal, outAxis[ 2 ] );
@@ -620,16 +572,21 @@ static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t
outAxis[ 1 ][ 2 ] = -outAxis[ 1 ][ 2 ];
VectorMA( inOrigin, -TRACE_DEPTH, normal, end );
- VectorMA( inOrigin, 1.0f, normal, start );
- CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
- if( tr.fraction == 1.0f )
+ CG_CapTrace( &tr, inOrigin, mins, maxs, end, skipNumber,
+ CONTENTS_SOLID | CONTENTS_PLAYERCLIP );
+
+ fraction = tr.fraction;
+ if( tr.startsolid )
+ fraction = 0;
+ else if( tr.fraction == 1.0f )
{
- //erm we missed completely - try again with a box trace
- CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_PLAYERSOLID );
+ // this is either too far off of the bbox to be useful for gameplay purposes
+ // or the model is positioned in thin air anyways.
+ fraction = 0;
}
- VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin );
+ VectorMA( inOrigin, fraction * -TRACE_DEPTH, normal, outOrigin );
}
/*
@@ -650,15 +607,18 @@ void CG_GhostBuildable( buildable_t buildable )
memset( &ent, 0, sizeof( ent ) );
- BG_FindBBoxForBuildable( buildable, mins, maxs );
+ BG_BuildableBoundingBox( buildable, mins, maxs );
BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, CG_Trace, entity_origin, angles, &tr );
+ if( cg_rangeMarkerForBlueprint.integer && tr.entityNum != ENTITYNUM_NONE )
+ CG_GhostBuildableRangeMarker( buildable, entity_origin, tr.plane.normal );
+
CG_PositionAndOrientateBuildable( ps->viewangles, entity_origin, tr.plane.normal, ps->clientNum,
mins, maxs, ent.axis, ent.origin );
//offset on the Z axis if required
- VectorMA( ent.origin, BG_FindZOffsetForBuildable( buildable ), tr.plane.normal, ent.origin );
+ VectorMA( ent.origin, BG_BuildableConfig( buildable )->zOffset, tr.plane.normal, ent.origin );
VectorCopy( ent.origin, ent.lightingOrigin );
VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
@@ -671,7 +631,7 @@ void CG_GhostBuildable( buildable_t buildable )
ent.customShader = cgs.media.redBuildShader;
//rescale the model
- scale = BG_FindModelScaleForBuildable( buildable );
+ scale = BG_BuildableConfig( buildable )->modelScale;
if( scale != 1.0f )
{
@@ -696,14 +656,14 @@ CG_BuildableParticleEffects
static void CG_BuildableParticleEffects( centity_t *cent )
{
entityState_t *es = &cent->currentState;
- buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
- int health = es->generic1 & B_HEALTH_MASK;
- float healthFrac = (float)health / B_HEALTH_MASK;
+ team_t team = BG_Buildable( es->modelindex )->team;
+ int health = es->misc;
+ float healthFrac = (float)health / BG_Buildable( es->modelindex )->health;
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
return;
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
{
@@ -718,7 +678,7 @@ static void CG_BuildableParticleEffects( centity_t *cent )
else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( &cent->buildablePS ) )
CG_DestroyParticleSystem( &cent->buildablePS );
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
{
if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
{
@@ -736,7 +696,11 @@ static void CG_BuildableParticleEffects( centity_t *cent )
}
}
-
+/*
+==================
+CG_BuildableStatusParse
+==================
+*/
void CG_BuildableStatusParse( const char *filename, buildStat_t *bs )
{
pc_token_t token;
@@ -866,10 +830,12 @@ void CG_BuildableStatusParse( const char *filename, buildStat_t *bs )
Com_Printf("CG_BuildableStatusParse: unknown token %s in %s\n",
token.string, filename );
bs->loaded = qfalse;
+ trap_Parse_FreeSource( handle );
return;
}
}
bs->loaded = qtrue;
+ trap_Parse_FreeSource( handle );
}
#define STATUS_FADE_TIME 200
@@ -899,23 +865,30 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
qboolean visible = qfalse;
vec3_t mins, maxs;
entityState_t *hit;
+ int anim;
- if( BG_FindTeamForBuildable( es->modelindex ) == BIT_ALIENS )
+ if( BG_Buildable( es->modelindex )->team == TEAM_ALIENS )
bs = &cgs.alienBuildStat;
else
bs = &cgs.humanBuildStat;
if( !bs->loaded )
return;
-
+
d = Distance( cent->lerpOrigin, cg.refdef.vieworg );
if( d > STATUS_MAX_VIEW_DIST )
return;
-
+
Vector4Copy( bs->foreColor, color );
- // trace for center point
- BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
+ // trace for center point
+ BG_BuildableBoundingBox( es->modelindex, mins, maxs );
+
+ // hack for shrunken barricades
+ anim = es->torsoAnim & ~( ANIM_FORCEBIT | ANIM_TOGGLEBIT );
+ if( es->modelindex == BA_A_BARRICADE &&
+ ( anim == BANIM_DESTROYED || !( es->eFlags & EF_B_SPAWNED ) ) )
+ maxs[ 2 ] = (int)( maxs[ 2 ] * BARRICADE_SHRINKPROP );
VectorCopy( cent->lerpOrigin, origin );
@@ -960,8 +933,8 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
hit = &cg_entities[ tr.entityNum ].currentState;
if( tr.entityNum < MAX_CLIENTS || ( hit->eType == ET_BUILDABLE &&
- ( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ||
- BG_FindTransparentTestForBuildable( hit->modelindex ) ) ) )
+ ( !( es->eFlags & EF_B_SPAWNED ) ||
+ BG_Buildable( hit->modelindex )->transparentTest ) ) )
{
entNum = tr.entityNum;
VectorCopy( tr.endpos, trOrigin );
@@ -972,7 +945,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
}
// hack to make the kit obscure view
if( cg_drawGun.integer && visible &&
- cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS &&
+ cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS &&
CG_WorldToScreen( origin, &x, &y ) )
{
if( x > 450 && y > 290 )
@@ -1006,8 +979,8 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
return;
}
- health = es->generic1 & B_HEALTH_MASK;
- healthScale = (float)health / B_HEALTH_MASK;
+ health = es->misc;
+ healthScale = (float)health / BG_Buildable( es->modelindex )->health;
if( health > 0 && healthScale < 0.01f )
healthScale = 0.01f;
@@ -1024,13 +997,14 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
float picY = y;
float scale;
float subH, subY;
+ float clipX, clipY, clipW, clipH;
vec4_t frameColor;
// this is fudged to get the width/height in the cfg to be more realistic
scale = ( picH / d ) * 3;
- powered = es->generic1 & B_POWERED_TOGGLEBIT;
- marked = es->generic1 & B_MARKED_TOGGLEBIT;
+ powered = es->eFlags & EF_B_POWERED;
+ marked = es->eFlags & EF_B_MARKED;
picH *= scale;
picW *= scale;
@@ -1041,6 +1015,12 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
subH = picH - ( picH * bs->verticalMargin );
subY = picY + ( picH * 0.5f ) - ( subH * 0.5f );
+ clipW = ( 640.0f * cg_viewsize.integer ) / 100.0f;
+ clipH = ( 480.0f * cg_viewsize.integer ) / 100.0f;
+ clipX = 320.0f - ( clipW * 0.5f );
+ clipY = 240.0f - ( clipH * 0.5f );
+ CG_SetClipRegion( clipX, clipY, clipW, clipH );
+
if( bs->frameShader )
{
Vector4Copy( bs->backColor, frameColor );
@@ -1073,7 +1053,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
healthColor[ 3 ] = color[ 3 ];
trap_R_SetColor( healthColor );
-
+
CG_DrawPic( hX, hY, hW, hH, cgs.media.whiteShader );
trap_R_SetColor( NULL );
}
@@ -1089,7 +1069,7 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
oW *= scale;
oX -= ( oW * 0.5f );
oY -= ( oH * 0.5f );
-
+
trap_R_SetColor( frameColor );
CG_DrawPic( oX, oY, oW, oH, bs->overlayShader );
trap_R_SetColor( NULL );
@@ -1117,12 +1097,12 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
int healthMax;
int healthPoints;
- healthMax = BG_FindHealthForBuildable( es->modelindex );
+ healthMax = BG_Buildable( es->modelindex )->health;
healthPoints = (int)( healthScale * healthMax );
if( health > 0 && healthPoints < 1 )
healthPoints = 1;
- nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f );
-
+ nX = picX + ( picW * 0.5f ) - 2.0f - ( ( subH * 4 ) * 0.5f );
+
if( healthPoints > 999 )
nX -= 0.0f;
else if( healthPoints > 99 )
@@ -1131,14 +1111,21 @@ static void CG_BuildableStatusDisplay( centity_t *cent )
nX -= subH * 1.0f;
else
nX -= subH * 1.5f;
-
+
CG_DrawField( nX, subY, 4, subH, subH, healthPoints );
}
+
trap_R_SetColor( NULL );
+ CG_ClearClipRegion( );
}
}
-static int QDECL CG_SortDistance( const void *a, const void *b )
+/*
+==================
+CG_SortDistance
+==================
+*/
+static int CG_SortDistance( const void *a, const void *b )
{
centity_t *aent, *bent;
float adist, bdist;
@@ -1157,6 +1144,48 @@ static int QDECL CG_SortDistance( const void *a, const void *b )
/*
==================
+CG_PlayerIsBuilder
+==================
+*/
+static qboolean CG_PlayerIsBuilder( buildable_t buildable )
+{
+ switch( cg.predictedPlayerState.weapon )
+ {
+ case WP_ABUILD:
+ case WP_ABUILD2:
+ case WP_HBUILD:
+ return BG_Buildable( buildable )->team ==
+ BG_Weapon( cg.predictedPlayerState.weapon )->team;
+
+ default:
+ return qfalse;
+ }
+}
+
+/*
+==================
+CG_BuildableRemovalPending
+==================
+*/
+static qboolean CG_BuildableRemovalPending( int entityNum )
+{
+ int i;
+ playerState_t *ps = &cg.snap->ps;
+
+ if( !( ps->stats[ STAT_BUILDABLE ] & SB_VALID_TOGGLEBIT ) )
+ return qfalse;
+
+ for( i = 0; i < MAX_MISC; i++ )
+ {
+ if( ps->misc[ i ] == entityNum )
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+==================
CG_DrawBuildableStatus
==================
*/
@@ -1168,30 +1197,18 @@ void CG_DrawBuildableStatus( void )
int buildableList[ MAX_ENTITIES_IN_SNAPSHOT ];
int buildables = 0;
- switch( cg.predictedPlayerState.weapon )
+ for( i = 0; i < cg.snap->numEntities; i++ )
{
- case WP_ABUILD:
- case WP_ABUILD2:
- case WP_HBUILD:
- case WP_HBUILD2:
- for( i = 0; i < cg.snap->numEntities; i++ )
- {
- cent = &cg_entities[ cg.snap->entities[ i ].number ];
- es = &cent->currentState;
-
- if( es->eType == ET_BUILDABLE &&
- BG_FindTeamForBuildable( es->modelindex ) ==
- BG_FindTeamForWeapon( cg.predictedPlayerState.weapon ) )
- buildableList[ buildables++ ] = cg.snap->entities[ i ].number;
- }
- qsort( buildableList, buildables, sizeof( int ), CG_SortDistance );
- for( i = 0; i < buildables; i++ )
- CG_BuildableStatusDisplay( &cg_entities[ buildableList[ i ] ] );
- break;
+ cent = &cg_entities[ cg.snap->entities[ i ].number ];
+ es = &cent->currentState;
- default:
- break;
+ if( es->eType == ET_BUILDABLE && CG_PlayerIsBuilder( es->modelindex ) )
+ buildableList[ buildables++ ] = cg.snap->entities[ i ].number;
}
+
+ qsort( buildableList, buildables, sizeof( int ), CG_SortDistance );
+ for( i = 0; i < buildables; i++ )
+ CG_BuildableStatusDisplay( &cg_entities[ buildableList[ i ] ] );
}
#define BUILDABLE_SOUND_PERIOD 500
@@ -1205,17 +1222,15 @@ void CG_Buildable( centity_t *cent )
{
refEntity_t ent;
entityState_t *es = &cent->currentState;
- vec3_t angles;
vec3_t surfNormal, xNormal, mins, maxs;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float rotAngle;
- buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
+ team_t team = BG_Buildable( es->modelindex )->team;
float scale;
int health;
- float healthScale;
//must be before EF_NODRAW check
- if( team == BIT_ALIENS )
+ if( team == TEAM_ALIENS )
CG_Creep( cent );
// if set to invisible, skip
@@ -1229,37 +1244,63 @@ void CG_Buildable( centity_t *cent )
memset ( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( cent->lerpOrigin, ent.oldorigin );
- VectorCopy( cent->lerpOrigin, ent.lightingOrigin );
-
VectorCopy( es->origin2, surfNormal );
- VectorCopy( es->angles, angles );
- BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
+ BG_BuildableBoundingBox( es->modelindex, mins, maxs );
if( es->pos.trType == TR_STATIONARY )
- CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number,
- mins, maxs, ent.axis, ent.origin );
+ {
+ // seeing as buildables rarely move, we cache the results and recalculate
+ // only if the buildable moves or changes orientation
+ if( VectorCompare( cent->buildableCache.cachedOrigin, cent->lerpOrigin ) &&
+ VectorCompare( cent->buildableCache.cachedAngles, cent->lerpAngles ) &&
+ VectorCompare( cent->buildableCache.cachedNormal, surfNormal ) &&
+ cent->buildableCache.cachedType == es->modelindex )
+ {
+ VectorCopy( cent->buildableCache.axis[ 0 ], ent.axis[ 0 ] );
+ VectorCopy( cent->buildableCache.axis[ 1 ], ent.axis[ 1 ] );
+ VectorCopy( cent->buildableCache.axis[ 2 ], ent.axis[ 2 ] );
+ VectorCopy( cent->buildableCache.origin, ent.origin );
+ }
+ else
+ {
+ CG_PositionAndOrientateBuildable( cent->lerpAngles, cent->lerpOrigin, surfNormal,
+ es->number, mins, maxs, ent.axis,
+ ent.origin );
+ VectorCopy( ent.axis[ 0 ], cent->buildableCache.axis[ 0 ] );
+ VectorCopy( ent.axis[ 1 ], cent->buildableCache.axis[ 1 ] );
+ VectorCopy( ent.axis[ 2 ], cent->buildableCache.axis[ 2 ] );
+ VectorCopy( ent.origin, cent->buildableCache.origin );
+ VectorCopy( cent->lerpOrigin, cent->buildableCache.cachedOrigin );
+ VectorCopy( cent->lerpAngles, cent->buildableCache.cachedAngles );
+ VectorCopy( surfNormal, cent->buildableCache.cachedNormal );
+ cent->buildableCache.cachedType = es->modelindex;
+ }
+ }
+ else
+ {
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+ }
//offset on the Z axis if required
- VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin );
+ VectorMA( ent.origin, BG_BuildableConfig( es->modelindex )->zOffset, surfNormal, ent.origin );
VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
VectorCopy( ent.origin, ent.lightingOrigin );
ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ];
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
{
sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild;
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
ent.customShader = cgs.media.humanSpawningShader;
prebuildSound = cgs.media.humanBuildablePrebuild;
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
prebuildSound = cgs.media.alienBuildablePrebuild;
trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
@@ -1268,7 +1309,7 @@ void CG_Buildable( centity_t *cent )
CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
//rescale the model
- scale = BG_FindModelScaleForBuildable( es->modelindex );
+ scale = BG_BuildableConfig( es->modelindex )->modelScale;
if( scale != 1.0f )
{
@@ -1281,6 +1322,8 @@ void CG_Buildable( centity_t *cent )
else
ent.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ ent.customShader = cgs.media.redBuildShader;
//add to refresh list
trap_R_AddRefEntityToScene( &ent );
@@ -1324,6 +1367,9 @@ void CG_Buildable( centity_t *cent )
else
turretBarrel.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ turretBarrel.customShader = cgs.media.redBuildShader;
+
trap_R_AddRefEntityToScene( &turretBarrel );
}
@@ -1366,6 +1412,9 @@ void CG_Buildable( centity_t *cent )
else
turretTop.nonNormalizedAxes = qfalse;
+ if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
+ turretTop.customShader = cgs.media.redBuildShader;
+
trap_R_AddRefEntityToScene( &turretTop );
}
@@ -1375,7 +1424,7 @@ void CG_Buildable( centity_t *cent )
weaponInfo_t *weapon = &cg_weapons[ es->weapon ];
if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ||
- BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN )
+ BG_Buildable( es->modelindex )->turretProjType == WP_TESLAGEN )
{
if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] ||
weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] ||
@@ -1397,27 +1446,34 @@ void CG_Buildable( centity_t *cent )
trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound );
}
- health = es->generic1 & B_HEALTH_MASK;
- healthScale = (float)health / B_HEALTH_MASK;
+ health = es->misc;
- if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ if( health < cent->lastBuildableHealth &&
+ ( es->eFlags & EF_B_SPAWNED ) )
{
if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
{
- if( team == BIT_HUMANS )
+ if( team == TEAM_HUMANS )
{
int i = rand( ) % 4;
trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
}
- else if( team == BIT_ALIENS )
+ else if( team == TEAM_ALIENS )
trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
cent->lastBuildableDamageSoundTime = cg.time;
}
}
- cent->lastBuildableHealthScale = healthScale;
+ cent->lastBuildableHealth = health;
//smoke etc for damaged buildables
CG_BuildableParticleEffects( cent );
+
+ if ( cg_rangeMarkerForBlueprint.integer )
+ {
+ // only light up the powered buildables.
+ if ( es->eFlags & EF_B_POWERED )
+ CG_GhostBuildableRangeMarker( es->modelindex, ent.origin, surfNormal );
+ }
}