diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | src/cgame/cg_animmapobj.c | 208 | ||||
-rw-r--r-- | src/cgame/cg_buildable.c | 6 | ||||
-rw-r--r-- | src/cgame/cg_ents.c | 3 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 5 | ||||
-rw-r--r-- | src/game/bg_public.h | 4 | ||||
-rw-r--r-- | src/game/g_buildable.c | 16 | ||||
-rw-r--r-- | src/game/g_local.h | 7 | ||||
-rw-r--r-- | src/game/g_misc.c | 45 | ||||
-rw-r--r-- | src/game/g_spawn.c | 25 |
10 files changed, 313 insertions, 7 deletions
@@ -47,6 +47,7 @@ CGOBJ = \ $(GDIRNAME)/q_shared.o \ $(CGDIRNAME)/cg_consolecmds.o \ $(CGDIRNAME)/cg_buildable.o \ + $(CGDIRNAME)/cg_animmapobj.o \ $(CGDIRNAME)/cg_spriter.o \ $(CGDIRNAME)/cg_draw.o \ $(CGDIRNAME)/cg_drawtools.o \ diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c new file mode 100644 index 00000000..7baba305 --- /dev/null +++ b/src/cgame/cg_animmapobj.c @@ -0,0 +1,208 @@ +/* + * 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" + +/* +=============== +CG_RunAMOLerpFrame + +Sets cg.snap, cg.oldFrame, and cg.backlerp +cg.time should be between oldFrameTime and frameTime after exit +=============== +*/ +static void CG_RunAMOLerpFrame( lerpFrame_t *lf ) +{ + 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; + } + + // 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_AMOAnimation +=============== +*/ +static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLerp ) +{ + if( !( cent->currentState.eFlags & EF_MOVER_STOP ) ) + CG_RunAMOLerpFrame( ¢->lerpFrame ); + else + { + //FIXME: fiddle with params so that when anim is resumed the lerp doesn't freak + // cos of the time differential +/* cent->lerpFrame.oldFrameTime = cg.time; + cent->lerpFrame.frameTime = cg.time + 50;*/ + } + + *old = cent->lerpFrame.oldFrame; + *now = cent->lerpFrame.frame; + *backLerp = cent->lerpFrame.backlerp; +} + + +/* +================== +CG_animMapObj +================== +*/ +void CG_animMapObj( centity_t *cent ) +{ + refEntity_t ent; + entityState_t *es; + float scale; + animation_t anim; + + es = ¢->currentState; + + // if set to invisible, skip + if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) + return; + + memset( &ent, 0, sizeof( ent ) ); + + VectorCopy( es->angles, cent->lerpAngles ); + AnglesToAxis( cent->lerpAngles, ent.axis ); + + ent.hModel = cgs.gameModels[ es->modelindex ]; + + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + + ent.nonNormalizedAxes = qfalse; + + //scale the model + if( es->angles2[ 0 ] ) + { + scale = es->angles2[ 0 ]; + 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; + } + + //setup animation + anim.firstFrame = es->powerups; + anim.numFrames = es->weapon; + anim.reversed = qfalse; + anim.flipflop = qfalse; + + // if numFrames is negative the animation is reversed + if( anim.numFrames < 0 ) + { + anim.numFrames = -anim.numFrames; + anim.reversed = qtrue; + } + + anim.loopFrames = es->torsoAnim; + + if( !es->legsAnim ) + { + anim.frameLerp = 1000; + anim.initialLerp = 1000; + } + else + { + anim.frameLerp = 1000 / es->legsAnim; + anim.initialLerp = 1000 / es->legsAnim; + } + + cent->lerpFrame.animation = &anim; + + //run animation + CG_AMOAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); + + // add to refresh list + trap_R_AddRefEntityToScene(&ent); +} diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c index 0bba94ec..9a63b477 100644 --- a/src/cgame/cg_buildable.c +++ b/src/cgame/cg_buildable.c @@ -32,7 +32,7 @@ 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 +models/buildables/hivemind/animation.cfg, etc ====================== */ static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_t buildable ) @@ -347,9 +347,13 @@ void CG_Buildable( centity_t *cent ) { ent2.nonNormalizedAxes = qfalse; + CG_BuildableAnimation( cent, &ent2.oldframe, &ent2.frame, &ent2.backlerp ); + trap_R_AddRefEntityToScene( &ent2 ); } + CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); + // add to refresh list trap_R_AddRefEntityToScene(&ent); } diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c index d145f387..dc65015b 100644 --- a/src/cgame/cg_ents.c +++ b/src/cgame/cg_ents.c @@ -956,6 +956,9 @@ static void CG_AddCEntity( centity_t *cent ) { case ET_SPRITER: CG_Spriter( cent ); break; + case ET_ANIMMAPOBJ: + CG_animMapObj( cent ); + break; } } diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index cd6ae57c..e37cb644 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1342,6 +1342,11 @@ void CG_InitBuildables( ); void CG_Spriter( centity_t *cent ); // +// cg_animmapobj.c +// +void CG_animMapObj( centity_t *cent ); + +// // cg_predict.c // void CG_BuildSolidList( void ); diff --git a/src/game/bg_public.h b/src/game/bg_public.h index 8886f74a..09f5ecf3 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -636,6 +636,9 @@ typedef enum ATTACK1, ATTACK2, + SPAWN1, + SPAWN2, + PAIN1, PAIN2, @@ -1007,6 +1010,7 @@ typedef enum { ET_TORCH, //TA: torch type ET_CORPSE, ET_SPRITER, + ET_ANIMMAPOBJ, ET_EVENTS // any of the EV_* events can be added freestanding // by setting eType to ET_EVENTS + eventNum diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index de0700ed..c9c5fdb7 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -28,6 +28,18 @@ /* ================ +G_setBuildableAnim + +Triggers an animation client side +================ +*/ +void G_setBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim ) +{ + ent->s.torsoAnim = anim; +} + +/* +================ findPower attempt to find power for self, return qtrue if successful @@ -1284,7 +1296,9 @@ gentity_t *Build_Item( gentity_t *ent, buildable_t buildable, int distance ) { built->s.pos.trType = TR_GRAVITY; built->s.pos.trTime = level.time; - trap_LinkEntity (built); + G_setBuildableAnim( built, CONSTRUCT1 ); + + trap_LinkEntity( built ); return built; } diff --git a/src/game/g_local.h b/src/game/g_local.h index c8273e4c..64d3f3de 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -189,6 +189,8 @@ struct gentity_s { int credits[ MAX_CLIENTS ]; //TA: human credits for each client qboolean creditsHash[ MAX_CLIENTS ]; //TA: track who has claimed credit int killedBy; //TA: clientNum of killer + + vec4_t animation; //TA: animated map objects }; typedef enum { @@ -540,8 +542,9 @@ typedef enum IBE_MAXERRORS } itemBuildError_t; -itemBuildError_t itemFits( gentity_t *ent, buildable_t buildable, int distance ); -gentity_t *Build_Item( gentity_t *ent, buildable_t buildable, int distance ); +itemBuildError_t itemFits( gentity_t *ent, buildable_t buildable, int distance ); +gentity_t *Build_Item( gentity_t *ent, buildable_t buildable, int distance ); +void G_setBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim ); // // g_utils.c diff --git a/src/game/g_misc.c b/src/game/g_misc.c index 27f0450b..03530500 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -375,7 +375,7 @@ void SP_use_spriter( gentity_t *self, gentity_t *other, gentity_t *activator ) } //TA: spawn function for spriter -void SP_spriter( gentity_t *self ) +void SP_misc_spriter( gentity_t *self ) { vec3_t accel; @@ -416,3 +416,46 @@ void SP_spriter( gentity_t *self ) trap_LinkEntity( self ); } + +//TA: use function for anim model +void SP_use_anim_model( gentity_t *self, gentity_t *other, gentity_t *activator ) +{ + if( self->spawnflags & 1 ) + { + //if spawnflag 1 is set + //toggle EF_NODRAW + if( self->s.eFlags & EF_NODRAW ) + self->s.eFlags &= ~EF_NODRAW; + else + self->s.eFlags |= EF_NODRAW; + } + else + { + //if the animation loops then toggle the animation + //toggle EF_MOVER_STOP + if( self->s.eFlags & EF_MOVER_STOP ) + self->s.eFlags &= ~EF_MOVER_STOP; + else + self->s.eFlags |= EF_MOVER_STOP; + } +} + +//TA: spawn function for anim model +void SP_misc_anim_model( gentity_t *self ) +{ + self->s.powerups = (int)self->animation[ 0 ]; + self->s.weapon = (int)self->animation[ 1 ]; + self->s.torsoAnim = (int)self->animation[ 2 ]; + self->s.legsAnim = (int)self->animation[ 3 ]; + + self->s.angles2[ 0 ] = self->pos2[ 0 ]; + + //add the model to the client precache list + self->s.modelindex = G_ModelIndex( self->model ); + + self->use = SP_use_anim_model; + + self->s.eType = ET_ANIMMAPOBJ; + + trap_LinkEntity( self ); +} diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 37dbc82e..7655e442 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -73,6 +73,15 @@ qboolean G_SpawnVector( const char *key, const char *defaultString, float *out return present; } +qboolean G_SpawnVector4( const char *key, const char *defaultString, float *out ) { + char *s; + qboolean present; + + present = G_SpawnString( key, defaultString, &s ); + sscanf( s, "%f %f %f %f", &out[0], &out[1], &out[2], &out[3] ); + return present; +} + // @@ -84,6 +93,7 @@ typedef enum { F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL F_GSTRING, // string on disk, pointer in memory, TAG_GAME F_VECTOR, + F_VECTOR4, //TA F_ANGLEHACK, F_ENTITY, // index on disk, pointer in memory F_ITEM, // index on disk, pointer in memory @@ -123,6 +133,7 @@ field_t fields[] = { {"alpha", FOFS(pos1), F_VECTOR}, {"radius", FOFS(pos2), F_VECTOR}, {"acceleration", FOFS(acceleration), F_VECTOR}, + {"animation", FOFS(animation), F_VECTOR4}, //TA {"targetShaderName", FOFS(targetShaderName), F_LSTRING}, {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING}, @@ -202,7 +213,8 @@ void SP_team_CTF_redspawn( gentity_t *ent ); void SP_team_CTF_bluespawn( gentity_t *ent ); //TA: -void SP_spriter( gentity_t *ent ); +void SP_misc_spriter( gentity_t *ent ); +void SP_misc_anim_model( gentity_t *ent ); spawn_t spawns[] = { // info entities don't do anything at all, but provide positional @@ -275,7 +287,8 @@ spawn_t spawns[] = { {"team_CTF_redspawn", SP_team_CTF_redspawn}, {"team_CTF_bluespawn", SP_team_CTF_bluespawn}, - {"spriter", SP_spriter}, + {"misc_spriter", SP_misc_spriter}, + {"misc_anim_model", SP_misc_anim_model}, {0, 0} }; @@ -372,6 +385,7 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { byte *b; float v; vec3_t vec; + vec4_t vec4; for ( f=fields ; f->name ; f++ ) { if ( !Q_stricmp(f->name, key) ) { @@ -388,6 +402,13 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { ((float *)(b+f->ofs))[1] = vec[1]; ((float *)(b+f->ofs))[2] = vec[2]; break; + case F_VECTOR4: + sscanf (value, "%f %f %f %f", &vec4[0], &vec4[1], &vec4[2], &vec4[3]); + ((float *)(b+f->ofs))[0] = vec4[0]; + ((float *)(b+f->ofs))[1] = vec4[1]; + ((float *)(b+f->ofs))[2] = vec4[2]; + ((float *)(b+f->ofs))[3] = vec4[3]; + break; case F_INT: *(int *)(b+f->ofs) = atoi(value); break; |