summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2001-08-17 00:15:12 +0000
committerTim Angus <tim@ngus.net>2001-08-17 00:15:12 +0000
commit19fb544e1df363411b176f7f45af79f52a6d90d2 (patch)
tree9a1d2c0c0a6b5e9aa15a0b590f0f64d736eec1e6
parentbb6827e851b1b412240d813706789233c1ffdb6e (diff)
Animated map object entity
-rw-r--r--Makefile1
-rw-r--r--src/cgame/cg_animmapobj.c208
-rw-r--r--src/cgame/cg_buildable.c6
-rw-r--r--src/cgame/cg_ents.c3
-rw-r--r--src/cgame/cg_local.h5
-rw-r--r--src/game/bg_public.h4
-rw-r--r--src/game/g_buildable.c16
-rw-r--r--src/game/g_local.h7
-rw-r--r--src/game/g_misc.c45
-rw-r--r--src/game/g_spawn.c25
10 files changed, 313 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 4a2893bd..8666d44d 100644
--- a/Makefile
+++ b/Makefile
@@ -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( &cent->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 = &cent->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;