summaryrefslogtreecommitdiff
path: root/mod/src/cgame/cg_buildable.c
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2005-12-10 03:23:37 +0000
committerTim Angus <tim@ngus.net>2005-12-10 03:23:37 +0000
commitbf23ecf17f432cf8e47302ef7464612c17be9bbe (patch)
tree6e3d28ecaa038199d6ba63830e81f05270b199c3 /mod/src/cgame/cg_buildable.c
parent22f322884cf7715c01500ef0b4579b87b1cb1973 (diff)
* Move the game source from mod/src/ to src/
Diffstat (limited to 'mod/src/cgame/cg_buildable.c')
-rw-r--r--mod/src/cgame/cg_buildable.c1051
1 files changed, 0 insertions, 1051 deletions
diff --git a/mod/src/cgame/cg_buildable.c b/mod/src/cgame/cg_buildable.c
deleted file mode 100644
index 348bb433..00000000
--- a/mod/src/cgame/cg_buildable.c
+++ /dev/null
@@ -1,1051 +0,0 @@
-/*
- * 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 "cg_local.h"
-
-char *cg_buildableSoundNames[ MAX_BUILDABLE_ANIMATIONS ] =
-{
- "construct1.wav",
- "construct2.wav",
- "idle1.wav",
- "idle2.wav",
- "idle3.wav",
- "attack1.wav",
- "attack2.wav",
- "spawn1.wav",
- "spawn2.wav",
- "pain1.wav",
- "pain2.wav",
- "destroy1.wav",
- "destroy2.wav",
- "destroyed.wav"
-};
-
-static sfxHandle_t defaultAlienSounds[ MAX_BUILDABLE_ANIMATIONS ];
-static sfxHandle_t defaultHumanSounds[ MAX_BUILDABLE_ANIMATIONS ];
-
-/*
-===================
-CG_AlienBuildableExplosion
-
-Generated a bunch of gibs launching out from a location
-===================
-*/
-void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir )
-{
- particleSystem_t *ps;
-
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.alienBuildableExplosion );
-
- //particle system
- ps = CG_SpawnNewParticleSystem( cgs.media.alienBuildableDestroyedPS );
-
- if( CG_IsParticleSystemValid( &ps ) )
- {
- CG_SetAttachmentPoint( &ps->attachment, origin );
- CG_SetParticleSystemNormal( ps, dir );
- CG_AttachToPoint( &ps->attachment );
- }
-}
-
-/*
-=================
-CG_HumanBuildableExplosion
-
-Called for human buildables as they are destroyed
-=================
-*/
-void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir )
-{
- particleSystem_t *ps;
-
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.humanBuildableExplosion );
-
- //particle system
- ps = CG_SpawnNewParticleSystem( cgs.media.humanBuildableDestroyedPS );
-
- if( CG_IsParticleSystemValid( &ps ) )
- {
- CG_SetAttachmentPoint( &ps->attachment, origin );
- CG_SetParticleSystemNormal( ps, dir );
- CG_AttachToPoint( &ps->attachment );
- }
-}
-
-
-#define CREEP_SIZE 64.0f
-
-/*
-==================
-CG_Creep
-==================
-*/
-static void CG_Creep( centity_t *cent )
-{
- int msec;
- float size, frac;
- trace_t tr;
- vec3_t temp, origin;
- int scaleUpTime = BG_FindBuildTimeForBuildable( cent->currentState.modelindex );
- int time;
-
- time = cent->currentState.time;
-
- //should the creep be growing or receding?
- if( time >= 0 )
- {
- msec = cg.time - time;
- if( msec >= 0 && msec < scaleUpTime )
- frac = (float)msec / scaleUpTime;
- else
- frac = 1.0f;
- }
- else if( time < 0 )
- {
- msec = cg.time + time;
- if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME )
- frac = 1.0f - ( (float)msec / CREEP_SCALEDOWN_TIME );
- else
- frac = 0.0f;
- }
-
- VectorCopy( cent->currentState.origin2, temp );
- VectorScale( temp, -4096, temp );
- VectorAdd( temp, cent->lerpOrigin, temp );
-
- CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_SOLID );
-
- VectorCopy( tr.endpos, origin );
-
- size = CREEP_SIZE * frac;
-
- if( size > 0.0f )
- CG_ImpactMark( cgs.media.creepShader, origin, cent->currentState.origin2,
- 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue );
-}
-
-/*
-======================
-CG_ParseBuildableAnimationFile
-
-Read a configuration file containing animation counts and rates
-models/buildables/hivemind/animation.cfg, etc
-======================
-*/
-static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_t buildable )
-{
- char *text_p;
- int len;
- int i;
- char *token;
- float fps;
- char text[ 20000 ];
- fileHandle_t f;
- animation_t *animations;
-
- animations = cg_buildables[ buildable ].animations;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if( len <= 0 )
- return qfalse;
-
- if( len >= sizeof( text ) - 1 )
- {
- CG_Printf( "File %s too long\n", filename );
- return qfalse;
- }
-
- trap_FS_Read( text, len, f );
- text[ len ] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
-
- // read information for each frame
- for( i = BANIM_NONE + 1; i < MAX_BUILDABLE_ANIMATIONS; i++ )
- {
-
- token = COM_Parse( &text_p );
- if( !*token )
- break;
-
- animations[ i ].firstFrame = atoi( token );
-
- token = COM_Parse( &text_p );
- if( !*token )
- break;
-
- animations[ i ].numFrames = atoi( token );
- animations[ i ].reversed = qfalse;
- animations[ i ].flipflop = qfalse;
-
- // if numFrames is negative the animation is reversed
- if( animations[ i ].numFrames < 0 )
- {
- animations[ i ].numFrames = -animations[ i ].numFrames;
- animations[ i ].reversed = qtrue;
- }
-
- token = COM_Parse( &text_p );
- if ( !*token )
- break;
-
- animations[i].loopFrames = atoi( token );
-
- token = COM_Parse( &text_p );
- if( !*token )
- break;
-
- fps = atof( token );
- if( fps == 0 )
- fps = 1;
-
- animations[ i ].frameLerp = 1000 / fps;
- animations[ i ].initialLerp = 1000 / fps;
- }
-
- if( i != MAX_BUILDABLE_ANIMATIONS )
- {
- CG_Printf( "Error parsing animation file: %s\n", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-======================
-CG_ParseBuildableSoundFile
-
-Read a configuration file containing sound properties
-sound/buildables/hivemind/sound.cfg, etc
-======================
-*/
-static qboolean CG_ParseBuildableSoundFile( const char *filename, buildable_t buildable )
-{
- char *text_p;
- int len;
- int i;
- char *token;
- char text[ 20000 ];
- fileHandle_t f;
- sound_t *sounds;
-
- sounds = cg_buildables[ buildable ].sounds;
-
- // load the file
- len = trap_FS_FOpenFile( filename, &f, FS_READ );
- if ( len <= 0 )
- return qfalse;
-
- if ( len >= sizeof( text ) - 1 )
- {
- CG_Printf( "File %s too long\n", filename );
- return qfalse;
- }
-
- trap_FS_Read( text, len, f );
- text[len] = 0;
- trap_FS_FCloseFile( f );
-
- // parse the text
- text_p = text;
-
- // read information for each frame
- for( i = BANIM_NONE + 1; i < MAX_BUILDABLE_ANIMATIONS; i++ )
- {
-
- token = COM_Parse( &text_p );
- if ( !*token )
- break;
-
- sounds[ i ].enabled = atoi( token );
-
- token = COM_Parse( &text_p );
- if ( !*token )
- break;
-
- sounds[ i ].looped = atoi( token );
-
- }
-
- if( i != MAX_BUILDABLE_ANIMATIONS )
- {
- CG_Printf( "Error parsing sound file: %s\n", filename );
- return qfalse;
- }
-
- return qtrue;
-}
-/*
-===============
-CG_InitBuildables
-
-Initialises the animation db
-===============
-*/
-void CG_InitBuildables( void )
-{
- char filename[ MAX_QPATH ];
- char soundfile[ MAX_QPATH ];
- char *buildableName;
- char *modelFile;
- int i;
- int j;
- fileHandle_t f;
-
- memset( cg_buildables, 0, sizeof( cg_buildables ) );
-
- //default sounds
- for( j = BANIM_NONE + 1; j < MAX_BUILDABLE_ANIMATIONS; j++ )
- {
- strcpy( soundfile, cg_buildableSoundNames[ j - 1 ] );
-
- Com_sprintf( filename, sizeof( filename ), "sound/buildables/alien/%s", soundfile );
- defaultAlienSounds[ j ] = trap_S_RegisterSound( filename, qfalse );
-
- Com_sprintf( filename, sizeof( filename ), "sound/buildables/human/%s", soundfile );
- defaultHumanSounds[ j ] = trap_S_RegisterSound( filename, qfalse );
- }
-
- cg.buildablesFraction = 0.0f;
-
- for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
- {
- buildableName = BG_FindNameForBuildable( i );
-
- //animation.cfg
- Com_sprintf( filename, sizeof( filename ), "models/buildables/%s/animation.cfg", buildableName );
- if ( !CG_ParseBuildableAnimationFile( filename, i ) )
- Com_Printf( S_COLOR_YELLOW "WARNING: failed to load animation file %s\n", filename );
-
- //sound.cfg
- Com_sprintf( filename, sizeof( filename ), "sound/buildables/%s/sound.cfg", buildableName );
- if ( !CG_ParseBuildableSoundFile( filename, i ) )
- Com_Printf( S_COLOR_YELLOW "WARNING: failed to load sound file %s\n", filename );
-
- //models
- for( j = 0; j <= 3; j++ )
- {
- if( ( modelFile = BG_FindModelsForBuildable( i, j ) ) )
- cg_buildables[ i ].models[ j ] = trap_R_RegisterModel( modelFile );
- }
-
- //sounds
- for( j = BANIM_NONE + 1; j < MAX_BUILDABLE_ANIMATIONS; j++ )
- {
- strcpy( soundfile, cg_buildableSoundNames[ j - 1 ] );
- Com_sprintf( filename, sizeof( filename ), "sound/buildables/%s/%s", buildableName, soundfile );
-
- if( cg_buildables[ i ].sounds[ j ].enabled )
- {
- if( trap_FS_FOpenFile( filename, &f, FS_READ ) > 0 )
- {
- //file exists so close it
- trap_FS_FCloseFile( f );
-
- cg_buildables[ i ].sounds[ j ].sound = trap_S_RegisterSound( filename, qfalse );
- }
- else
- {
- //file doesn't exist - use default
- if( BG_FindTeamForBuildable( i ) == BIT_ALIENS )
- cg_buildables[ i ].sounds[ j ].sound = defaultAlienSounds[ j ];
- else
- cg_buildables[ i ].sounds[ j ].sound = defaultHumanSounds[ j ];
- }
- }
- }
-
- cg.buildablesFraction = (float)i / (float)( BA_NUM_BUILDABLES - 1 );
- trap_UpdateScreen( );
- }
-
- cgs.media.teslaZapTS = CG_RegisterTrailSystem( "models/buildables/tesla/zap" );
-}
-
-/*
-===============
-CG_SetBuildableLerpFrameAnimation
-
-may include ANIM_TOGGLEBIT
-===============
-*/
-static void CG_SetBuildableLerpFrameAnimation( buildable_t buildable, lerpFrame_t *lf, int newAnimation )
-{
- animation_t *anim;
-
- lf->animationNumber = newAnimation;
-
- if( newAnimation < 0 || newAnimation >= MAX_BUILDABLE_ANIMATIONS )
- CG_Error( "Bad animation number: %i", newAnimation );
-
- anim = &cg_buildables[ buildable ].animations[ newAnimation ];
-
- //this item has just spawned so lf->frameTime will be zero
- if( !lf->animation )
- lf->frameTime = cg.time + 1000; //1 sec delay before starting the spawn anim
-
- lf->animation = anim;
- lf->animationTime = lf->frameTime + anim->initialLerp;
-
- if( cg_debugAnim.integer )
- CG_Printf( "Anim: %i\n", newAnimation );
-}
-
-/*
-===============
-CG_RunBuildableLerpFrame
-
-Sets cg.snap, cg.oldFrame, and cg.backlerp
-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",
- newAnimation, lf->animationNumber, lf->animation );
-
- CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation );
-
- if( !cg_buildables[ buildable ].sounds[ newAnimation ].looped &&
- cg_buildables[ buildable ].sounds[ newAnimation ].enabled )
- {
- if( cg_debugRandom.integer )
- CG_Printf( "Sound for animation %d for a %s\n",
- newAnimation, BG_FindHumanNameForBuildable( buildable ) );
-
- trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO,
- cg_buildables[ buildable ].sounds[ newAnimation ].sound );
- }
- }
-
- if( cg_buildables[ buildable ].sounds[ lf->animationNumber ].looped &&
- cg_buildables[ buildable ].sounds[ lf->animationNumber ].enabled )
- 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;
-
- // 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");
- }
- }
-
- 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 );
-}
-
-/*
-===============
-CG_BuildableAnimation
-===============
-*/
-static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *backLerp )
-{
- entityState_t *es = &cent->currentState;
-
- //if no animation is set default to idle anim
- if( cent->buildableAnim == BANIM_NONE )
- cent->buildableAnim = es->torsoAnim;
-
- //display the first frame of the construction anim if not yet spawned
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
- {
- animation_t *anim = &cg_buildables[ es->modelindex ].animations[ BANIM_CONSTRUCT1 ];
-
- //so that when animation starts for real it has sensible numbers
- cent->lerpFrame.oldFrameTime =
- cent->lerpFrame.frameTime =
- cent->lerpFrame.animationTime =
- cg.time;
-
- *old = cent->lerpFrame.oldFrame = anim->firstFrame;
- *now = cent->lerpFrame.frame = anim->firstFrame;
- *backLerp = cent->lerpFrame.backlerp = 0.0f;
-
- //ensure that an animation is triggered once the buildable has spawned
- cent->oldBuildableAnim = BANIM_NONE;
- }
- else
- {
- if( ( cent->oldBuildableAnim ^ es->legsAnim ) & ANIM_TOGGLEBIT )
- {
- if( cg_debugAnim.integer )
- 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 );
-
- if( cent->buildableAnim == es->torsoAnim || es->legsAnim & ANIM_FORCEBIT )
- cent->buildableAnim = cent->oldBuildableAnim = es->legsAnim;
- else
- cent->buildableAnim = cent->oldBuildableAnim = es->torsoAnim;
- }
-
- CG_RunBuildableLerpFrame( cent );
-
- *old = cent->lerpFrame.oldFrame;
- *now = cent->lerpFrame.frame;
- *backLerp = cent->lerpFrame.backlerp;
- }
-}
-
-#define TRACE_DEPTH 64.0f
-
-/*
-===============
-CG_PositionAndOrientateBuildable
-===============
-*/
-static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t inOrigin,
- const vec3_t normal, const int skipNumber,
- const vec3_t mins, const vec3_t maxs,
- vec3_t outAxis[ 3 ], vec3_t outOrigin )
-{
- vec3_t forward, start, end;
- trace_t tr;
-
- AngleVectors( angles, forward, NULL, NULL );
- VectorCopy( normal, outAxis[ 2 ] );
- ProjectPointOnPlane( outAxis[ 0 ], forward, outAxis[ 2 ] );
-
- if( !VectorNormalize( outAxis[ 0 ] ) )
- {
- AngleVectors( angles, NULL, NULL, forward );
- ProjectPointOnPlane( outAxis[ 0 ], forward, outAxis[ 2 ] );
- VectorNormalize( outAxis[ 0 ] );
- }
-
- CrossProduct( outAxis[ 0 ], outAxis[ 2 ], outAxis[ 1 ] );
- outAxis[ 1 ][ 0 ] = -outAxis[ 1 ][ 0 ];
- outAxis[ 1 ][ 1 ] = -outAxis[ 1 ][ 1 ];
- 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_SOLID );
-
- if( tr.fraction == 1.0f )
- {
- //erm we missed completely - try again with a box trace
- CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID );
- }
-
- VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin );
-}
-
-/*
-==================
-CG_GhostBuildable
-==================
-*/
-void CG_GhostBuildable( buildable_t buildable )
-{
- refEntity_t ent;
- playerState_t *ps;
- vec3_t angles, entity_origin;
- vec3_t mins, maxs;
- trace_t tr;
- float scale;
-
- ps = &cg.predictedPlayerState;
-
- memset( &ent, 0, sizeof( ent ) );
-
- BG_FindBBoxForBuildable( buildable, mins, maxs );
-
- BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, CG_Trace, entity_origin, angles, &tr );
-
- 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 );
-
- VectorCopy( ent.origin, ent.lightingOrigin );
- VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
-
- ent.hModel = cg_buildables[ buildable ].models[ 0 ];
-
- if( ps->stats[ STAT_BUILDABLE ] & SB_VALID_TOGGLEBIT )
- ent.customShader = cgs.media.greenBuildShader;
- else
- ent.customShader = cgs.media.redBuildShader;
-
- //rescale the model
- scale = BG_FindModelScaleForBuildable( buildable );
-
- if( scale != 1.0f )
- {
- VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] );
-
- ent.nonNormalizedAxes = qtrue;
- }
- else
- ent.nonNormalizedAxes = qfalse;
-
- // add to refresh list
- trap_R_AddRefEntityToScene( &ent );
-}
-
-/*
-==================
-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_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
- float healthFrac = (float)health / B_HEALTH_SCALE;
-
- if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
- return;
-
- if( team == BIT_HUMANS )
- {
- if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
- {
- cent->buildablePS = CG_SpawnNewParticleSystem( cgs.media.humanBuildableDamagedPS );
-
- if( CG_IsParticleSystemValid( &cent->buildablePS ) )
- {
- CG_SetAttachmentCent( &cent->buildablePS->attachment, cent );
- CG_AttachToCent( &cent->buildablePS->attachment );
- }
- }
- else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( &cent->buildablePS ) )
- CG_DestroyParticleSystem( &cent->buildablePS );
- }
- else if( team == BIT_ALIENS )
- {
- if( healthFrac < 0.33f && !CG_IsParticleSystemValid( &cent->buildablePS ) )
- {
- cent->buildablePS = CG_SpawnNewParticleSystem( cgs.media.alienBuildableDamagedPS );
-
- if( CG_IsParticleSystemValid( &cent->buildablePS ) )
- {
- CG_SetAttachmentCent( &cent->buildablePS->attachment, cent );
- CG_SetParticleSystemNormal( cent->buildablePS, es->origin2 );
- CG_AttachToCent( &cent->buildablePS->attachment );
- }
- }
- else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( &cent->buildablePS ) )
- CG_DestroyParticleSystem( &cent->buildablePS );
- }
-}
-
-
-#define HEALTH_BAR_WIDTH 50.0f
-#define HEALTH_BAR_HEIGHT 5.0f
-
-/*
-==================
-CG_BuildableHealthBar
-==================
-*/
-static void CG_BuildableHealthBar( centity_t *cent )
-{
- vec3_t origin, origin2, down, right, back, downLength, rightLength;
- float rimWidth = HEALTH_BAR_HEIGHT / 15.0f;
- float doneWidth, leftWidth, progress;
- int health;
- qhandle_t shader;
- entityState_t *es;
- vec3_t mins, maxs;
-
- es = &cent->currentState;
-
- health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
- progress = (float)health / B_HEALTH_SCALE;
-
- if( progress < 0.0f )
- progress = 0.0f;
- else if( progress > 1.0f )
- progress = 1.0f;
-
- if( progress < 0.33f )
- shader = cgs.media.redBuildShader;
- else
- shader = cgs.media.greenBuildShader;
-
- doneWidth = ( HEALTH_BAR_WIDTH - 2 * rimWidth ) * progress;
- leftWidth = ( HEALTH_BAR_WIDTH - 2 * rimWidth ) - doneWidth;
-
- VectorCopy( cg.refdef.viewaxis[ 2 ], down );
- VectorInverse( down );
- VectorCopy( cg.refdef.viewaxis[ 1 ], right );
- VectorInverse( right );
- VectorSubtract( cg.refdef.vieworg, cent->lerpOrigin, back );
- VectorNormalize( back );
- VectorCopy( cent->lerpOrigin, origin );
-
- BG_FindBBoxForBuildable( es->modelindex, mins, maxs );
- VectorMA( origin, 48.0f, es->origin2, origin );
- VectorMA( origin, -HEALTH_BAR_WIDTH / 2.0f, right, origin );
- VectorMA( origin, maxs[ 0 ] + 8.0f, back, origin );
-
- VectorCopy( origin, origin2 );
- VectorScale( right, rimWidth + doneWidth, rightLength );
- VectorScale( down, HEALTH_BAR_HEIGHT, downLength );
- CG_DrawPlane( origin2, downLength, rightLength, shader );
-
- VectorMA( origin, rimWidth + doneWidth, right, origin2 );
- VectorScale( right, leftWidth, rightLength );
- VectorScale( down, rimWidth, downLength );
- CG_DrawPlane( origin2, downLength, rightLength, shader );
-
- VectorMA( origin, rimWidth + doneWidth, right, origin2 );
- VectorMA( origin2, HEALTH_BAR_HEIGHT - rimWidth, down, origin2 );
- VectorScale( right, leftWidth, rightLength );
- VectorScale( down, rimWidth, downLength );
- CG_DrawPlane( origin2, downLength, rightLength, shader );
-
- VectorMA( origin, HEALTH_BAR_WIDTH - rimWidth, right, origin2 );
- VectorScale( right, rimWidth, rightLength );
- VectorScale( down, HEALTH_BAR_HEIGHT, downLength );
- CG_DrawPlane( origin2, downLength, rightLength, shader );
-
- if( !( es->generic1 & B_POWERED_TOGGLEBIT ) &&
- BG_FindTeamForBuildable( es->modelindex ) == BIT_HUMANS )
- {
- VectorMA( origin, 15.0f, right, origin2 );
- VectorMA( origin2, HEALTH_BAR_HEIGHT + 5.0f, down, origin2 );
- VectorScale( right, HEALTH_BAR_WIDTH / 2.0f - 5.0f, rightLength );
- VectorScale( down, HEALTH_BAR_WIDTH / 2.0f - 5.0f, downLength );
- CG_DrawPlane( origin2, downLength, rightLength, cgs.media.noPowerShader );
- }
-}
-
-#define BUILDABLE_SOUND_PERIOD 500
-
-/*
-==================
-CG_Buildable
-==================
-*/
-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 );
- float scale;
- int health;
- float healthScale;
-
- //must be before EF_NODRAW check
- if( team == BIT_ALIENS )
- CG_Creep( cent );
-
- // if set to invisible, skip
- if( es->eFlags & EF_NODRAW )
- {
- if( CG_IsParticleSystemValid( &cent->buildablePS ) )
- CG_DestroyParticleSystem( &cent->buildablePS );
-
- return;
- }
-
- 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 );
-
- if( es->pos.trType == TR_STATIONARY )
- CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number,
- mins, maxs, ent.axis, ent.origin );
-
- //offset on the Z axis if required
- VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), 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 ) )
- {
- sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild;
-
- if( team == BIT_HUMANS )
- {
- ent.customShader = cgs.media.humanSpawningShader;
- prebuildSound = cgs.media.humanBuildablePrebuild;
- }
- else if( team == BIT_ALIENS )
- prebuildSound = cgs.media.alienBuildablePrebuild;
-
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
- }
-
- CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
-
- //rescale the model
- scale = BG_FindModelScaleForBuildable( es->modelindex );
-
- if( scale != 1.0f )
- {
- VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] );
-
- ent.nonNormalizedAxes = qtrue;
- }
- else
- ent.nonNormalizedAxes = qfalse;
-
-
- //add to refresh list
- trap_R_AddRefEntityToScene( &ent );
-
- CrossProduct( surfNormal, refNormal, xNormal );
- VectorNormalize( xNormal );
- rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) );
-
- //turret barrel bit
- if( cg_buildables[ es->modelindex ].models[ 1 ] )
- {
- refEntity_t turretBarrel;
- vec3_t flatAxis[ 3 ];
-
- memset( &turretBarrel, 0, sizeof( turretBarrel ) );
-
- turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ];
-
- CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" );
- VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin );
- AnglesToAxis( es->angles2, flatAxis );
-
- RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
- RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
- RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
-
- turretBarrel.oldframe = ent.oldframe;
- turretBarrel.frame = ent.frame;
- turretBarrel.backlerp = ent.backlerp;
-
- turretBarrel.customShader = ent.customShader;
-
- if( scale != 1.0f )
- {
- VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] );
- VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] );
- VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] );
-
- turretBarrel.nonNormalizedAxes = qtrue;
- }
- else
- turretBarrel.nonNormalizedAxes = qfalse;
-
- trap_R_AddRefEntityToScene( &turretBarrel );
- }
-
- //turret barrel bit
- if( cg_buildables[ es->modelindex ].models[ 2 ] )
- {
- refEntity_t turretTop;
- vec3_t flatAxis[ 3 ];
- vec3_t swivelAngles;
-
- memset( &turretTop, 0, sizeof( turretTop ) );
-
- VectorCopy( es->angles2, swivelAngles );
- swivelAngles[ PITCH ] = 0.0f;
-
- turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ];
-
- CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" );
- VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin );
- AnglesToAxis( swivelAngles, flatAxis );
-
- RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
- RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
- RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
-
- turretTop.oldframe = ent.oldframe;
- turretTop.frame = ent.frame;
- turretTop.backlerp = ent.backlerp;
-
- turretTop.customShader = ent.customShader;
-
- if( scale != 1.0f )
- {
- VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] );
- VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] );
- VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] );
-
- turretTop.nonNormalizedAxes = qtrue;
- }
- else
- turretTop.nonNormalizedAxes = qfalse;
-
- trap_R_AddRefEntityToScene( &turretTop );
- }
-
- switch( cg.predictedPlayerState.weapon )
- {
- case WP_ABUILD:
- case WP_ABUILD2:
- case WP_HBUILD:
- case WP_HBUILD2:
- if( BG_FindTeamForBuildable( es->modelindex ) ==
- BG_FindTeamForWeapon( cg.predictedPlayerState.weapon ) )
- CG_BuildableHealthBar( cent );
- break;
-
- default:
- break;
- }
-
- //weapon effects for turrets
- if( es->eFlags & EF_FIRING )
- {
- weaponInfo_t *weapon = &cg_weapons[ es->weapon ];
-
- if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ||
- BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN )
- {
- if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] ||
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] ||
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] )
- {
- trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ),
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ],
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ],
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] );
- }
- }
-
- if( weapon->wim[ WPM_PRIMARY ].firingSound )
- {
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin,
- weapon->wim[ WPM_PRIMARY ].firingSound );
- }
- else if( weapon->readySound )
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
-
- health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
- healthScale = (float)health / B_HEALTH_SCALE;
-
- if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
- {
- if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
- {
- if( team == BIT_HUMANS )
- {
- int i = rand( ) % 4;
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
- }
- else if( team == BIT_ALIENS )
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
-
- cent->lastBuildableDamageSoundTime = cg.time;
- }
- }
-
- cent->lastBuildableHealthScale = healthScale;
-
- //smoke etc for damaged buildables
- CG_BuildableParticleEffects( cent );
-}