summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--src/cgame/cg_buildable.c355
-rw-r--r--src/cgame/cg_ents.c90
-rw-r--r--src/cgame/cg_local.h9
-rw-r--r--src/cgame/cg_main.c3
-rw-r--r--src/cgame/cg_players.c6
-rw-r--r--src/game/bg_public.h13
-rw-r--r--src/game/g_buildable.c1
8 files changed, 381 insertions, 97 deletions
diff --git a/Makefile b/Makefile
index c750db24..63b56761 100644
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,7 @@ CGOBJ = \
$(GDIRNAME)/q_math.o \
$(GDIRNAME)/q_shared.o \
$(CGDIRNAME)/cg_consolecmds.o \
+ $(CGDIRNAME)/cg_buildable.o \
$(CGDIRNAME)/cg_draw.o \
$(CGDIRNAME)/cg_drawtools.o \
$(CGDIRNAME)/cg_effects.o \
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
new file mode 100644
index 00000000..ec7d2858
--- /dev/null
+++ b/src/cgame/cg_buildable.c
@@ -0,0 +1,355 @@
+/*
+ * 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 GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, or (at your option)
+ * any later version.
+ *
+ * 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. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* To assertain which portions are licensed under the LGPL and which are
+ * licensed by Id Software, Inc. please run a diff between the equivalent
+ * versions of the "Tremulous" modification and the unmodified "Quake3"
+ * game source code.
+ */
+
+#include "cg_local.h"
+
+//if it ends up this is needed outwith this file i'll make it a bit more tidy
+animation_t buildAnimations[ BA_NUM_BUILDABLES ][ MAX_BUILDABLE_ANIMATIONS ];
+
+/*
+======================
+CG_ParseBuildableAnimationFile
+
+Read a configuration file containing animation coutns and rates
+models/players/visor/animation.cfg, etc
+======================
+*/
+static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_t buildable )
+{
+ char *text_p, *prev;
+ int len;
+ int i;
+ char *token;
+ float fps;
+ int skip;
+ char text[20000];
+ fileHandle_t f;
+ animation_t *animations;
+
+ animations = buildAnimations[ buildable ];
+
+ // 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;
+ skip = 0; // quite the compiler warning
+
+ // read information for each frame
+ for ( i = 0; 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", filename );
+ return qfalse;
+ }*/
+
+ return qtrue;
+}
+
+/*
+===============
+CG_InitBuildables
+
+Initialises the animation db
+===============
+*/
+void CG_InitBuildables( )
+{
+ char filename[MAX_QPATH];
+ char *buildableName;
+ int i;
+
+ for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
+ {
+ buildableName = BG_FindNameForBuildable( i );
+
+ Com_sprintf( filename, sizeof( filename ), "models/buildables/%s/animation.cfg", buildableName );
+ if ( !CG_ParseBuildableAnimationFile( filename, i ) )
+ Com_Printf( "Failed to load animation file %s\n", filename );
+ }
+}
+
+/*
+===============
+CG_SetBuildableLerpFrameAnimation
+
+may include ANIM_TOGGLEBIT
+===============
+*/
+static void CG_SetBuildableLerpFrameAnimation( buildable_t buildable, lerpFrame_t *lf, int newAnimation ) {
+ animation_t *anim;
+
+ lf->animationNumber = newAnimation;
+ newAnimation &= ~ANIM_TOGGLEBIT;
+
+ if ( newAnimation < 0 || newAnimation >= MAX_BUILDABLE_ANIMATIONS ) {
+ CG_Error( "Bad animation number: %i", newAnimation );
+ }
+
+ anim = buildAnimations[ buildable ];
+
+ 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( buildable_t buildable, lerpFrame_t *lf, int newAnimation ) {
+ int f, numFrames;
+ animation_t *anim;
+
+ // 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 ) {
+ CG_SetLerpFrameAnimation( buildable, lf, newAnimation );
+ }
+
+ // 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;
+ }
+ }
+ 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 ) {
+
+ CG_RunBuildableLerpFrame( cent->currentState.clientNum,
+ &cent->lerpFrame, cent->currentState.torsoAnim );
+
+ *old = cent->lerpFrame.oldFrame;
+ *now = cent->lerpFrame.frame;
+ *backLerp = cent->lerpFrame.backlerp;
+}
+
+
+/*
+==================
+CG_Buildable
+==================
+*/
+void CG_Buildable( centity_t *cent ) {
+ refEntity_t ent;
+ refEntity_t ent2;
+ entityState_t *es;
+ gitem_t *item;
+ int msec;
+ float frac;
+ float scale;
+
+ es = &cent->currentState;
+ if ( es->modelindex >= bg_numItems ) {
+ CG_Error( "Bad item index %i on entity", es->modelindex );
+ }
+
+ //add creep
+ if( es->modelindex2 == BIT_DROIDS )
+ CG_Creep( cent );
+
+ // if set to invisible, skip
+ if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
+ return;
+ }
+
+ item = &bg_itemlist[ es->modelindex ];
+
+ memset (&ent, 0, sizeof(ent));
+
+ VectorCopy( es->angles, cent->lerpAngles );
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ ent.hModel = cg_items[es->modelindex].models[0];
+
+ VectorCopy( cent->lerpOrigin, ent.origin);
+ VectorCopy( cent->lerpOrigin, ent.oldorigin);
+
+ ent.nonNormalizedAxes = qfalse;
+
+ // if just respawned, slowly scale up
+ msec = cg.time - cent->miscTime;
+ if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
+ frac = (float)msec / ITEM_SCALEUP_TIME;
+ VectorScale( ent.axis[0], frac, ent.axis[0] );
+ VectorScale( ent.axis[1], frac, ent.axis[1] );
+ VectorScale( ent.axis[2], frac, ent.axis[2] );
+ ent.nonNormalizedAxes = qtrue;
+ } else {
+ frac = 1.0;
+ }
+
+ //turret barrel bit
+ if( cg_items[ es->modelindex ].models[ 1 ] != 0 )
+ {
+ vec3_t turretOrigin;
+
+ memset( &ent2, 0, sizeof( ent2 ) );
+
+ AnglesToAxis( es->angles2, ent2.axis );
+
+ ent2.hModel = cg_items[ es->modelindex ].models[ 1 ];
+
+ VectorCopy( cent->lerpOrigin, turretOrigin );
+ turretOrigin[ 2 ] += 5;
+
+ VectorCopy( turretOrigin, ent2.origin );
+ VectorCopy( turretOrigin, ent2.oldorigin );
+
+ ent2.nonNormalizedAxes = qfalse;
+
+ trap_R_AddRefEntityToScene( &ent2 );
+ }
+
+ // add to refresh list
+ trap_R_AddRefEntityToScene(&ent);
+}
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 9b8c10e5..66e6e8f9 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -370,96 +370,6 @@ static void CG_Item( centity_t *cent ) {
}
-/*
-==================
-CG_Buildable
-==================
-*/
-static void CG_Buildable( centity_t *cent ) {
- refEntity_t ent;
- refEntity_t ent2;
- entityState_t *es;
- gitem_t *item;
- int msec;
- float frac;
- float scale;
-
- es = &cent->currentState;
- if ( es->modelindex >= bg_numItems ) {
- CG_Error( "Bad item index %i on entity", es->modelindex );
- }
-
- //add creep
- if( es->modelindex2 == BIT_DROIDS )
- CG_Creep( cent );
-
- // if set to invisible, skip
- if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) {
- return;
- }
-
- item = &bg_itemlist[ es->modelindex ];
-
- memset (&ent, 0, sizeof(ent));
-
- VectorCopy( es->angles, cent->lerpAngles );
- AnglesToAxis( cent->lerpAngles, ent.axis );
-
- ent.hModel = cg_items[es->modelindex].models[0];
-
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
-
- ent.nonNormalizedAxes = qfalse;
-
- // if just respawned, slowly scale up
- msec = cg.time - cent->miscTime;
- if ( msec >= 0 && msec < ITEM_SCALEUP_TIME ) {
- frac = (float)msec / ITEM_SCALEUP_TIME;
- VectorScale( ent.axis[0], frac, ent.axis[0] );
- VectorScale( ent.axis[1], frac, ent.axis[1] );
- VectorScale( ent.axis[2], frac, ent.axis[2] );
- ent.nonNormalizedAxes = qtrue;
- } else {
- frac = 1.0;
- }
-
-
- //TA: might be useful later:
- // items without glow textures need to keep a minimum light value
- // so they are always visible
- /*if ( ( item->giType == IT_WEAPON ) ||
- ( item->giType == IT_ARMOR ) ) {
- ent.renderfx |= RF_MINLIGHT;
- }*/
-
- //turret barrel bit
- if( cg_items[ es->modelindex ].models[ 1 ] != 0 )
- {
- vec3_t turretOrigin;
-
- memset( &ent2, 0, sizeof( ent2 ) );
-
- AnglesToAxis( es->angles2, ent2.axis );
-
- ent2.hModel = cg_items[ es->modelindex ].models[ 1 ];
-
- VectorCopy( cent->lerpOrigin, turretOrigin );
- turretOrigin[ 2 ] += 5;
-
- VectorCopy( turretOrigin, ent2.origin );
- VectorCopy( turretOrigin, ent2.oldorigin );
-
- ent2.nonNormalizedAxes = qfalse;
-
- trap_R_AddRefEntityToScene( &ent2 );
- }
-
- // add to refresh list
- trap_R_AddRefEntityToScene(&ent);
-}
-
-
//============================================================================
/*
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 883c7ef7..d7c6c560 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -195,6 +195,7 @@ typedef struct centity_s {
//TA: value to store corpse number
int corpseNum;
+ lerpFrame_t lerpFrame;
} centity_t;
@@ -360,7 +361,7 @@ typedef struct {
qhandle_t modelIcon;
- animation_t animations[MAX_TOTALANIMATIONS];
+ animation_t animations[MAX_PLAYER_TOTALANIMATIONS];
sfxHandle_t sounds[MAX_CUSTOM_SOUNDS];
} clientInfo_t;
@@ -1292,6 +1293,12 @@ void CG_PrecacheClientInfo( int clientNum );
sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
//
+// cg_buildable.c
+//
+void CG_Buildable( centity_t *cent );
+void CG_InitBuildables( );
+
+//
// cg_predict.c
//
void CG_BuildSolidList( void );
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index fee26036..91129958 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -1079,6 +1079,9 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) {
CG_RegisterGraphics();
+ //TA:
+ CG_InitBuildables( );
+
CG_LoadingString( "clients" );
CG_RegisterClients(); // if low on memory, some clients will be deferred
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c
index fcd464d1..68fd1d71 100644
--- a/src/cgame/cg_players.c
+++ b/src/cgame/cg_players.c
@@ -185,7 +185,7 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci )
}
// read information for each frame
- for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
+ for ( i = 0 ; i < MAX_PLAYER_ANIMATIONS ; i++ ) {
token = COM_Parse( &text_p );
if ( !*token ) {
@@ -243,7 +243,7 @@ static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci )
animations[i].initialLerp = 1000 / fps;
}
- if ( i != MAX_ANIMATIONS ) {
+ if ( i != MAX_PLAYER_ANIMATIONS ) {
CG_Printf( "Error parsing animation file: %s", filename );
return qfalse;
}
@@ -902,7 +902,7 @@ static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int new
lf->animationNumber = newAnimation;
newAnimation &= ~( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING );
- if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
+ if ( newAnimation < 0 || newAnimation >= MAX_PLAYER_TOTALANIMATIONS ) {
CG_Error( "Bad animation number: %i", newAnimation );
}
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 4d6fc8a6..73e0699c 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -584,7 +584,7 @@ typedef enum {
TORSO_NEGATIVE,
#endif
- MAX_ANIMATIONS,
+ MAX_PLAYER_ANIMATIONS,
LEGS_BACKCR,
LEGS_BACKWALK,
@@ -592,9 +592,16 @@ typedef enum {
FLAG_STAND,
FLAG_STAND2RUN,
- MAX_TOTALANIMATIONS
-} animNumber_t;
+ MAX_PLAYER_TOTALANIMATIONS
+} playerAnimNumber_t;
+//TA: for buildable animations
+typedef enum
+{
+ BUILD_CONSTRUCT,
+ BUILD_DESTROY,
+ MAX_BUILDABLE_ANIMATIONS
+} buildableAnimNumber_t;
typedef struct animation_s {
int firstFrame;
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index ef210767..051c2209 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -752,6 +752,7 @@ gentity_t *Build_Item( gentity_t *ent, buildable_t buildable, int distance ) {
built->item = BG_FindItemForBuildable( buildable );
built->s.modelindex = built->item - bg_itemlist; // store item number in modelindex
+ built->s.clientNum = buildable; //so we can tell what this is on the client side
BG_FindBBoxForBuildable( buildable, built->r.mins, built->r.maxs );
built->biteam = built->s.modelindex2 = BG_FindTeamForBuildable( buildable );