diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | src/cgame/cg_buildable.c | 355 | ||||
-rw-r--r-- | src/cgame/cg_ents.c | 90 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 9 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 3 | ||||
-rw-r--r-- | src/cgame/cg_players.c | 6 | ||||
-rw-r--r-- | src/game/bg_public.h | 13 | ||||
-rw-r--r-- | src/game/g_buildable.c | 1 |
8 files changed, 381 insertions, 97 deletions
@@ -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, + ¢->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 = ¢->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 = ¢->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 ); |