summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2003-09-08 01:47:43 +0000
committerTim Angus <tim@ngus.net>2003-09-08 01:47:43 +0000
commit5a9a825f2d86b000abc9f9f7d337d7c500e00c58 (patch)
tree3dfe245790188caadbe1b3a494d929ee14bf0ae3 /src
parent17839915c9e52528c592565b3d6bee9e36445593 (diff)
* func_door_model -- a model based door
* Removed a bunch of entities not applicable to Tremulous * Wrote an entities.def file for Tremulous (ugh gak horrible syntax) * Updated depend file * Various other small tweaks here and there
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_animmapobj.c123
-rw-r--r--src/cgame/cg_ents.c8
-rw-r--r--src/cgame/cg_local.h3
-rw-r--r--src/game/bg_public.h3
-rw-r--r--src/game/g_local.h8
-rw-r--r--src/game/g_misc.c114
-rw-r--r--src/game/g_mover.c371
-rw-r--r--src/game/g_spawn.c19
-rw-r--r--src/game/g_target.c160
9 files changed, 479 insertions, 330 deletions
diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c
index c7218b00..46b64073 100644
--- a/src/cgame/cg_animmapobj.c
+++ b/src/cgame/cg_animmapobj.c
@@ -74,7 +74,7 @@ static void CG_RunAMOLerpFrame( lerpFrame_t *lf )
if( anim->reversed )
lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
- else if( anim->flipflop && f>=anim->numFrames )
+ else if( anim->flipflop && f >= anim->numFrames )
lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames );
else
lf->frame = anim->firstFrame + f;
@@ -103,6 +103,125 @@ static void CG_RunAMOLerpFrame( lerpFrame_t *lf )
/*
===============
+CG_DoorAnimation
+===============
+*/
+static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp )
+{
+ CG_RunAMOLerpFrame( &cent->lerpFrame );
+
+ *old = cent->lerpFrame.oldFrame;
+ *now = cent->lerpFrame.frame;
+ *backLerp = cent->lerpFrame.backlerp;
+}
+
+
+/*
+===============
+CG_ModelDoor
+===============
+*/
+void CG_ModelDoor( centity_t *cent )
+{
+ refEntity_t ent;
+ entityState_t *es;
+ vec3_t mins, maxs, size;
+ vec3_t cMins, cMaxs, displacement;
+ vec3_t bMaxs, scale;
+ animation_t anim;
+ lerpFrame_t *lf = &cent->lerpFrame;
+
+
+ es = &cent->currentState;
+
+ if( !es->modelindex )
+ return;
+
+ //create the render entity
+ memset( &ent, 0, sizeof( ent ) );
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ VectorCopy( cent->lerpOrigin, ent.oldorigin );
+ AnglesToAxis( cent->lerpAngles, ent.axis );
+
+ ent.renderfx = RF_NOSHADOW;
+
+ //add the door model
+ ent.skinNum = 0;
+ ent.hModel = cgs.gameModels[ es->modelindex ];
+
+ if( es->eFlags & EF_NO_AUTO_SCALE )
+ {
+ //this door is being manually scaled
+ VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] );
+ VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] );
+ VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] );
+ ent.nonNormalizedAxes = qtrue;
+ }
+ else
+ {
+ //automatically scale and position the model
+ trap_R_ModelBounds( ent.hModel, mins, maxs );
+
+ //average of mins and maxs
+ VectorSubtract( maxs, mins, size );
+ VectorScale( size, 0.5f, size );
+
+ //set corrected bbox
+ VectorCopy( size, cMaxs );
+ VectorNegate( size, cMins );
+
+ //calculate the displacement needed to align
+ //the model with the centre of the brush
+ VectorSubtract( cMins, mins, displacement );
+
+ VectorCopy( es->angles2, bMaxs );
+
+ //scale the axis and displacement by the ratio
+ //of the brush to corrected bboxes
+ scale[ 0 ] = bMaxs[ 0 ] / cMaxs[ 0 ];
+ scale[ 1 ] = bMaxs[ 1 ] / cMaxs[ 1 ];
+ scale[ 2 ] = bMaxs[ 2 ] / cMaxs[ 2 ];
+
+ VectorScale( ent.axis[ 0 ], scale[ 0 ], ent.axis[ 0 ] );
+ VectorScale( ent.axis[ 1 ], scale[ 1 ], ent.axis[ 1 ] );
+ VectorScale( ent.axis[ 2 ], scale[ 2 ], ent.axis[ 2 ] );
+ ent.nonNormalizedAxes = qtrue;
+
+ displacement[ 0 ] = scale[ 0 ] * displacement[ 0 ];
+ displacement[ 1 ] = scale[ 1 ] * displacement[ 1 ];
+ displacement[ 2 ] = scale[ 2 ] * displacement[ 2 ];
+
+ VectorAdd( ent.origin, displacement, ent.origin );
+ VectorAdd( ent.oldorigin, displacement, ent.oldorigin );
+ }
+
+ //setup animation
+ anim.firstFrame = es->powerups;
+ anim.numFrames = es->weapon;
+ anim.reversed = !es->legsAnim;
+ anim.flipflop = qfalse;
+ anim.loopFrames = 0;
+ anim.frameLerp = 1000 / es->torsoAnim;
+ anim.initialLerp = 1000 / es->torsoAnim;
+
+ //door changed state
+ if( es->legsAnim != cent->doorState )
+ {
+ lf->animationTime = lf->frameTime + anim.initialLerp;
+ cent->doorState = es->legsAnim;
+ }
+
+ lf->animation = &anim;
+
+ //run animation
+ CG_DoorAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
+
+ trap_R_AddRefEntityToScene( &ent );
+}
+
+
+/*
+===============
CG_AMOAnimation
===============
*/
@@ -144,7 +263,7 @@ void CG_animMapObj( centity_t *cent )
es = &cent->currentState;
// if set to invisible, skip
- if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) )
+ if( !es->modelindex || ( es->eFlags & EF_NODRAW ) )
return;
memset( &ent, 0, sizeof( ent ) );
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 9128597c..6a1fa650 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -438,8 +438,8 @@ static void CG_Mover( centity_t *cent )
// create the render entity
memset( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin);
- VectorCopy( cent->lerpOrigin, ent.oldorigin);
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ VectorCopy( cent->lerpOrigin, ent.oldorigin );
AnglesToAxis( cent->lerpAngles, ent.axis );
ent.renderfx = RF_NOSHADOW;
@@ -929,6 +929,10 @@ static void CG_AddCEntity( centity_t *cent )
CG_animMapObj( cent );
break;
+ case ET_MODELDOOR:
+ CG_ModelDoor( cent );
+ break;
+
case ET_LIGHTFLARE:
CG_LightFlare( cent );
break;
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index df0366d0..941c3d31 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -223,6 +223,8 @@ typedef struct centity_s
float lastFlareRatio; //caching of likely flare ratio
int lastFlareTime; //last time flare was visible/occluded
qboolean flareStatus; //flare is visble?
+
+ qboolean doorState;
} centity_t;
@@ -1283,6 +1285,7 @@ void CG_LaunchSprite( const vec3_t p, const vec3_t vel, const vec3_t acce
// cg_animmapobj.c
//
void CG_animMapObj( centity_t *cent );
+void CG_ModelDoor( centity_t *cent );
//
// cg_predict.c
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index d0ae824f..a519595f 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -281,6 +281,7 @@ typedef enum
#define EF_TEAMVOTED 0x00008000 // already cast a vote
#define EF_OVERDRAW_OFF 0x00010000 // TA: disable overdraw protection on sprites
#define EF_REAL_LIGHT 0x00020000 // TA: light sprites according to ambient light
+#define EF_NO_AUTO_SCALE 0x00040000 // TA: don't auto scale model doors
typedef enum
{
@@ -1132,7 +1133,6 @@ typedef enum
ET_ITEM,
ET_BUILDABLE, //TA: buildable type
- ET_CREEP, //TA: creep type
ET_MISSILE,
ET_MOVER,
@@ -1147,6 +1147,7 @@ typedef enum
ET_CORPSE,
ET_SPRITER,
ET_ANIMMAPOBJ,
+ ET_MODELDOOR,
ET_LIGHTFLARE,
ET_EVENTS // any of the EV_* events can be added freestanding
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 708a0c45..e65d1e69 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -54,7 +54,12 @@ typedef enum
ROTATOR_POS1,
ROTATOR_POS2,
ROTATOR_1TO2,
- ROTATOR_2TO1
+ ROTATOR_2TO1,
+
+ MODEL_POS1,
+ MODEL_POS2,
+ MODEL_1TO2,
+ MODEL_2TO1
} moverState_t;
#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
@@ -112,6 +117,7 @@ struct gentity_s
gentity_t *prevTrain;
vec3_t pos1, pos2;
float rotatorAngle;
+ gentity_t *clipBrush; //TA: clipping brush for model doors
char *message;
diff --git a/src/game/g_misc.c b/src/game/g_misc.c
index d8055f3a..fa7d660f 100644
--- a/src/game/g_misc.c
+++ b/src/game/g_misc.c
@@ -23,15 +23,6 @@ Used to group brushes together just for editor convenience. They are turned int
*/
-/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
-Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
-*/
-void SP_info_camp( gentity_t *self )
-{
- G_SetOrigin( self, self->s.origin );
-}
-
-
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
*/
@@ -246,111 +237,6 @@ void SP_misc_portal_camera( gentity_t *ent )
/*
======================================================================
- SHOOTERS
-
-======================================================================
-*/
-
-void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator )
-{
- vec3_t dir;
- float deg;
- vec3_t up, right;
-
- // see if we have a target
- if( ent->enemy )
- {
- VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
- VectorNormalize( dir );
- }
- else
- VectorCopy( ent->movedir, dir );
-
- // randomize a bit
- PerpendicularVector( up, dir );
- CrossProduct( up, dir, right );
-
- deg = crandom( ) * ent->random;
- VectorMA( dir, deg, up, dir );
-
- deg = crandom( ) * ent->random;
- VectorMA( dir, deg, right, dir );
-
- VectorNormalize( dir );
-
-/* switch ( ent->s.weapon ) {
- case WP_GRENADE_LAUNCHER:
- fire_grenade( ent, ent->s.origin, dir );
- break;
- case WP_ROCKET_LAUNCHER:
- fire_rocket( ent, ent->s.origin, dir );
- break;
- }*/
-
- G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
-}
-
-
-static void InitShooter_Finish( gentity_t *ent )
-{
- ent->enemy = G_PickTarget( ent->target );
- ent->think = 0;
- ent->nextthink = 0;
-}
-
-void InitShooter( gentity_t *ent, int weapon )
-{
- ent->use = Use_Shooter;
- ent->s.weapon = weapon;
-
- /*RegisterItem( BG_FindItemForWeapon( weapon ) );*/
-
- G_SetMovedir( ent->s.angles, ent->movedir );
-
- if( !ent->random )
- ent->random = 1.0;
-
- ent->random = sin( M_PI * ent->random / 180 );
- // target might be a moving object, so we can't set movedir for it
- if( ent->target )
- {
- ent->think = InitShooter_Finish;
- ent->nextthink = level.time + 500;
- }
-
- trap_LinkEntity( ent );
-}
-
-/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_rocket( gentity_t *ent )
-{
- //InitShooter( ent, WP_ROCKET_LAUNCHER );
-}
-
-/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_plasma( gentity_t *ent )
-{
- //InitShooter( ent, WP_PLASMAGUN);
-}
-
-/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
-Fires at either the target or the current direction.
-"random" is the number of degrees of deviance from the taget. (1.0 default)
-*/
-void SP_shooter_grenade( gentity_t *ent )
-{
- //InitShooter( ent, WP_GRENADE_LAUNCHER);
-}
-
-/*
-======================================================================
-
NEAT EFFECTS AND STUFF FOR TREMULOUS
======================================================================
diff --git a/src/game/g_mover.c b/src/game/g_mover.c
index 787af188..ea7f40be 100644
--- a/src/game/g_mover.c
+++ b/src/game/g_mover.c
@@ -431,7 +431,8 @@ void G_RunMover( gentity_t *ent )
return;
// if stationary at one of the positions, don't move anything
- if( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY )
+ if( ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) &&
+ ent->moverState < MODEL_POS1 ) //yuck yuck hack
G_MoverTeam( ent );
// check think function
@@ -516,10 +517,20 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time )
VectorScale( delta, f, ent->s.apos.trDelta );
ent->s.apos.trType = TR_LINEAR_STOP;
break;
+
+ case MODEL_POS1:
+ break;
+
+ case MODEL_POS2:
+ break;
}
- BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
- BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles );
+ if( moverState >= MOVER_POS1 && moverState <= MOVER_2TO1 )
+ BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin );
+
+ if( moverState >= ROTATOR_POS1 && moverState <= ROTATOR_2TO1 )
+ BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles );
+
trap_LinkEntity( ent );
}
@@ -579,6 +590,114 @@ void ReturnToApos1( gentity_t *ent )
/*
================
+Think_ClosedModelDoor
+================
+*/
+void Think_ClosedModelDoor( gentity_t *ent )
+{
+ // play sound
+ if( ent->soundPos1 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 );
+
+ // close areaportals
+ if( ent->teammaster == ent || !ent->teammaster )
+ trap_AdjustAreaPortalState( ent, qfalse );
+
+ ent->moverState = MODEL_POS1;
+}
+
+
+/*
+================
+Think_CloseModelDoor
+================
+*/
+void Think_CloseModelDoor( gentity_t *ent )
+{
+ int entityList[ MAX_GENTITIES ];
+ int numEntities, i;
+ gentity_t *clipBrush = ent->clipBrush;
+ gentity_t *check;
+ qboolean canClose = qtrue;
+
+ numEntities = trap_EntitiesInBox( clipBrush->r.absmin, clipBrush->r.absmax, entityList, MAX_GENTITIES );
+
+ //set brush solid
+ trap_LinkEntity( ent->clipBrush );
+
+ //see if any solid entities are inside the door
+ for( i = 0; i < numEntities; i++ )
+ {
+ check = &g_entities[ entityList[ i ] ];
+
+ //only test items and players
+ if( check->s.eType != ET_ITEM && check->s.eType != ET_BUILDABLE &&
+ check->s.eType != ET_CORPSE && check->s.eType != ET_PLAYER &&
+ !check->physicsObject )
+ continue;
+
+ //test is this entity collides with this door
+ if( G_TestEntityPosition( check ) )
+ canClose = qfalse;
+ }
+
+ //something is blocking this door
+ if( !canClose )
+ {
+ //set brush non-solid
+ trap_UnlinkEntity( ent->clipBrush );
+
+ ent->nextthink = level.time + ent->wait;
+ return;
+ }
+
+ //toggle door state
+ ent->s.legsAnim = qfalse;
+
+ // play sound
+ if( ent->sound2to1 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+
+ ent->moverState = MODEL_2TO1;
+
+ ent->think = Think_ClosedModelDoor;
+ ent->nextthink = level.time + ent->speed;
+}
+
+
+/*
+================
+Think_OpenModelDoor
+================
+*/
+void Think_OpenModelDoor( gentity_t *ent )
+{
+ //set brush non-solid
+ trap_UnlinkEntity( ent->clipBrush );
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // starting sound
+ if( ent->soundPos2 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 );
+
+ ent->moverState = MODEL_POS2;
+
+ // return to pos1 after a delay
+ ent->think = Think_CloseModelDoor;
+ ent->nextthink = level.time + ent->wait;
+
+ // fire targets
+ if( !ent->activator )
+ ent->activator = ent;
+
+ G_UseTargets( ent, ent->activator );
+}
+
+
+/*
+================
Reached_BinaryMover
================
*/
@@ -691,20 +810,15 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
// open areaportal
if( ent->teammaster == ent || !ent->teammaster )
trap_AdjustAreaPortalState( ent, qtrue );
-
- return;
}
-
- // if all the way up, just delay before coming down
- if( ent->moverState == MOVER_POS2 )
+ else if( ent->moverState == MOVER_POS2 )
{
+ // if all the way up, just delay before coming down
ent->nextthink = level.time + ent->wait;
- return;
}
-
- // only partway down before reversing
- if( ent->moverState == MOVER_2TO1 )
+ else if( ent->moverState == MOVER_2TO1 )
{
+ // only partway down before reversing
total = ent->s.pos.trDuration;
partial = level.time - ent->s.pos.trTime;
@@ -715,13 +829,10 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->sound1to2 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
-
- return;
}
-
- // only partway up before reversing
- if( ent->moverState == MOVER_1TO2 )
+ else if( ent->moverState == MOVER_1TO2 )
{
+ // only partway up before reversing
total = ent->s.pos.trDuration;
partial = level.time - ent->s.pos.trTime;
@@ -732,11 +843,8 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->sound2to1 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
-
- return;
}
-
- if( ent->moverState == ROTATOR_POS1 )
+ else if( ent->moverState == ROTATOR_POS1 )
{
// start moving 50 msec later, becase if this was player
// triggered, level.time hasn't been advanced yet
@@ -752,20 +860,15 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
// open areaportal
if( ent->teammaster == ent || !ent->teammaster )
trap_AdjustAreaPortalState( ent, qtrue );
-
- return;
}
-
- // if all the way up, just delay before coming down
- if( ent->moverState == ROTATOR_POS2 )
+ else if( ent->moverState == ROTATOR_POS2 )
{
+ // if all the way up, just delay before coming down
ent->nextthink = level.time + ent->wait;
- return;
}
-
- // only partway down before reversing
- if( ent->moverState == ROTATOR_2TO1 )
+ else if( ent->moverState == ROTATOR_2TO1 )
{
+ // only partway down before reversing
total = ent->s.apos.trDuration;
partial = level.time - ent->s.apos.trTime;
@@ -776,13 +879,10 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->sound1to2 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
-
- return;
}
-
- // only partway up before reversing
- if( ent->moverState == ROTATOR_1TO2 )
+ else if( ent->moverState == ROTATOR_1TO2 )
{
+ // only partway up before reversing
total = ent->s.apos.trDuration;
partial = level.time - ent->s.apos.trTime;
@@ -793,8 +893,32 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator )
if( ent->sound2to1 )
G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 );
+ }
+ else if( ent->moverState == MODEL_POS1 )
+ {
+ //toggle door state
+ ent->s.legsAnim = qtrue;
- return;
+ ent->think = Think_OpenModelDoor;
+ ent->nextthink = level.time + ent->speed;
+
+ // starting sound
+ if( ent->sound1to2 )
+ G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 );
+
+ // looping sound
+ ent->s.loopSound = ent->soundLoop;
+
+ // open areaportal
+ if( ent->teammaster == ent || !ent->teammaster )
+ trap_AdjustAreaPortalState( ent, qtrue );
+
+ ent->moverState = MODEL_1TO2;
+ }
+ else if( ent->moverState == MODEL_POS2 )
+ {
+ // if all the way up, just delay before coming down
+ ent->nextthink = level.time + ent->wait;
}
}
@@ -869,7 +993,7 @@ void InitMover( gentity_t *ent )
// calculate time to reach second position from speed
VectorSubtract( ent->pos2, ent->pos1, move );
distance = VectorLength( move );
- if( ! ent->speed )
+ if( !ent->speed )
ent->speed = 100;
VectorScale( move, ent->speed, ent->s.pos.trDelta );
@@ -1055,7 +1179,11 @@ static void manualDoorTriggerSpectator( gentity_t *door, gentity_t *player )
//don't skip a door that is already open
if( door->moverState == MOVER_1TO2 ||
- door->moverState == MOVER_POS2 )
+ door->moverState == MOVER_POS2 ||
+ door->moverState == ROTATOR_1TO2 ||
+ door->moverState == ROTATOR_POS2 ||
+ door->moverState == MODEL_1TO2 ||
+ door->moverState == MODEL_POS2 )
return;
// find the bounds of everything on the team
@@ -1222,7 +1350,8 @@ void Think_SpawnNewDoorTrigger( gentity_t *ent )
other->count = best;
trap_LinkEntity( other );
- MatchTeam( ent, ent->moverState, level.time );
+ if( ent->moverState < MODEL_POS1 )
+ MatchTeam( ent, ent->moverState, level.time );
}
void Think_MatchTeam( gentity_t *ent )
@@ -1447,6 +1576,170 @@ void SP_func_door_rotating( gentity_t *ent )
}
}
+/*QUAKED func_door_model (0 .5 .8) ? START_OPEN
+TOGGLE wait in both the start and end states for a trigger event.
+START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+NOMONSTER monsters will not trigger this door
+
+"model2" .md3 model to also draw
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"color" constantLight color
+"light" constantLight radius
+"health" if set, the door must be shot open
+*/
+void SP_func_door_model( gentity_t *ent )
+{
+ vec3_t abs_movedir;
+ float distance;
+ vec3_t size;
+ char *s;
+ float light;
+ vec3_t color;
+ qboolean lightSet, colorSet;
+ char *sound;
+ gentity_t *door;
+ gentity_t *clipBrush;
+ vec3_t scale;
+ qboolean dontAutoScale = qfalse;
+
+ G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s );
+ ent->sound2to1 = G_SoundIndex( s );
+ G_SpawnString( "sound1to2", "sound/movers/doors/dr1_strt.wav", &s );
+ ent->sound1to2 = G_SoundIndex( s );
+
+ G_SpawnString( "soundPos2", "sound/movers/doors/dr1_end.wav", &s );
+ ent->soundPos2 = G_SoundIndex( s );
+ G_SpawnString( "soundPos1", "sound/movers/doors/dr1_end.wav", &s );
+ ent->soundPos1 = G_SoundIndex( s );
+
+ //default speed of 100ms
+ if( !ent->speed )
+ ent->speed = 200;
+
+ //default wait of 2 seconds
+ if( ent->wait <= 0 )
+ ent->wait = 2;
+
+ ent->wait *= 1000;
+
+ //brush model
+ clipBrush = ent->clipBrush = G_Spawn( );
+ clipBrush->model = ent->model;
+ trap_SetBrushModel( clipBrush, clipBrush->model );
+ clipBrush->s.eType = ET_INVISIBLE;
+ trap_LinkEntity( clipBrush );
+
+ //copy the bounds back from the clipBrush so the
+ //triggers can be made
+ VectorCopy( clipBrush->r.absmin, ent->r.absmin );
+ VectorCopy( clipBrush->r.absmax, ent->r.absmax );
+ VectorCopy( clipBrush->r.mins, ent->r.mins );
+ VectorCopy( clipBrush->r.maxs, ent->r.maxs );
+
+ if( !VectorLength( ent->s.origin ) )
+ {
+ //calculate the centre of the brush
+ VectorSubtract( ent->r.maxs, ent->r.mins, size );
+ VectorScale( size, 0.5f, size );
+ VectorAdd( size, ent->r.mins, ent->s.origin );
+ }
+ else
+ dontAutoScale = qtrue;
+
+ if( G_SpawnVector( "scale", "1 1 1", scale ) )
+ dontAutoScale = qtrue;
+
+ //let the client know the scaling of the model
+ VectorCopy( scale, ent->s.origin2 );
+
+ //let the client know the bounds of the brush
+ VectorCopy( size, ent->s.angles2 );
+
+ if( dontAutoScale )
+ ent->s.eFlags |= EF_NO_AUTO_SCALE;
+
+ // if the "model2" key is set, use a seperate model
+ // for drawing, but clip against the brushes
+ if( !ent->model2 )
+ G_Printf( S_COLOR_YELLOW "WARNING: func_door_model %d spawned with no model2 key\n", ent->s.number );
+ else
+ ent->s.modelindex = G_ModelIndex( ent->model2 );
+
+ // if the "loopsound" key is set, use a constant looping sound when moving
+ if( G_SpawnString( "noise", "100", &sound ) )
+ ent->s.loopSound = G_SoundIndex( sound );
+
+ // if the "color" or "light" keys are set, setup constantLight
+ lightSet = G_SpawnFloat( "light", "100", &light );
+ colorSet = G_SpawnVector( "color", "1 1 1", color );
+
+ if( lightSet || colorSet )
+ {
+ int r, g, b, i;
+
+ r = color[ 0 ] * 255;
+ if( r > 255 )
+ r = 255;
+
+ g = color[ 1 ] * 255;
+ if( g > 255 )
+ g = 255;
+
+ b = color[ 2 ] * 255;
+ if( b > 255 )
+ b = 255;
+
+ i = light / 4;
+ if( i > 255 )
+ i = 255;
+
+ ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
+ }
+
+ ent->use = Use_BinaryMover;
+
+ ent->moverState = MODEL_POS1;
+ ent->s.eType = ET_MODELDOOR;
+ VectorCopy( ent->s.origin, ent->s.pos.trBase );
+ ent->s.pos.trTime = 0;
+ ent->s.pos.trDuration = 0;
+ VectorClear( ent->s.pos.trDelta );
+ VectorCopy( ent->s.angles, ent->s.apos.trBase );
+ ent->s.apos.trTime = 0;
+ ent->s.apos.trDuration = 0;
+ VectorClear( ent->s.apos.trDelta );
+
+ ent->s.powerups = (int)ent->animation[ 0 ]; //first frame
+ ent->s.weapon = abs( (int)ent->animation[ 1 ] ); //number of frames
+
+ //must be at least one frame -- mapper has forgotten animation key
+ if( ent->s.weapon == 0 )
+ ent->s.weapon = 1;
+
+ ent->s.torsoAnim = ent->s.weapon * ( 1000.0f / ent->speed ); //framerate
+
+ trap_LinkEntity( ent );
+
+ ent->s.pos.trType = TR_STATIONARY;
+
+ if( !( ent->flags & FL_TEAMSLAVE ) )
+ {
+ int health;
+
+ G_SpawnInt( "health", "0", &health );
+ if( health )
+ ent->takedamage = qtrue;
+
+ if( !( ent->targetname || health ) )
+ {
+ ent->nextthink = level.time + FRAMETIME;
+ ent->think = Think_SpawnNewDoorTrigger;
+ }
+ }
+}
+
/*
===============================================================================
diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c
index 71197932..f5790024 100644
--- a/src/game/g_spawn.c
+++ b/src/game/g_spawn.c
@@ -169,6 +169,7 @@ void SP_func_pendulum( gentity_t *ent );
void SP_func_button( gentity_t *ent );
void SP_func_door( gentity_t *ent );
void SP_func_door_rotating( gentity_t *ent ); //TA
+void SP_func_door_model( gentity_t *ent ); //TA
void SP_func_train( gentity_t *ent );
void SP_func_timer( gentity_t *self);
@@ -178,12 +179,9 @@ void SP_trigger_push( gentity_t *ent );
void SP_trigger_teleport( gentity_t *ent );
void SP_trigger_hurt( gentity_t *ent );
-void SP_target_remove_powerups( gentity_t *ent );
-void SP_target_give( gentity_t *ent );
void SP_target_delay( gentity_t *ent );
void SP_target_speaker( gentity_t *ent );
void SP_target_print( gentity_t *ent );
-void SP_target_laser( gentity_t *self);
void SP_target_character( gentity_t *ent );
void SP_target_score( gentity_t *ent );
void SP_target_teleporter( gentity_t *ent );
@@ -227,12 +225,12 @@ spawn_t spawns[ ] =
{"info_null", SP_info_null},
{"info_notnull", SP_info_notnull}, // use target_position instead
- {"info_camp", SP_info_camp},
{"func_plat", SP_func_plat},
{"func_button", SP_func_button},
{"func_door", SP_func_door},
{"func_door_rotating", SP_func_door_rotating}, //TA
+ {"func_door_model", SP_func_door_model}, //TA
{"func_static", SP_func_static},
{"func_rotating", SP_func_rotating},
{"func_bobbing", SP_func_bobbing},
@@ -254,12 +252,9 @@ spawn_t spawns[ ] =
// targets perform no action by themselves, but must be triggered
// by another entity
- {"target_give", SP_target_give},
- {"target_remove_powerups", SP_target_remove_powerups},
{"target_delay", SP_target_delay},
{"target_speaker", SP_target_speaker},
{"target_print", SP_target_print},
- {"target_laser", SP_target_laser},
{"target_score", SP_target_score},
{"target_teleporter", SP_target_teleporter},
{"target_relay", SP_target_relay},
@@ -276,10 +271,6 @@ spawn_t spawns[ ] =
{"misc_portal_surface", SP_misc_portal_surface},
{"misc_portal_camera", SP_misc_portal_camera},
- {"shooter_rocket", SP_shooter_rocket},
- {"shooter_grenade", SP_shooter_grenade},
- {"shooter_plasma", SP_shooter_plasma},
-
{"misc_spriter", SP_misc_spriter},
{"misc_anim_model", SP_misc_anim_model},
{"misc_light_flare", SP_misc_light_flare},
@@ -309,14 +300,16 @@ qboolean G_CallSpawn( gentity_t *ent )
//check buildable spawn functions
if( ( buildable = BG_FindBuildNumForEntityName( ent->classname ) ) != BA_NONE )
{
- if( BG_FindStagesForBuildable( buildable, 1 ) )
+ /*if( BG_FindStagesForBuildable( buildable, 1 ) )*/
+ if( qtrue )
{
G_SpawnBuildable( ent, buildable );
return qtrue;
}
else
{
- G_Printf( "G_CallSpawn: buildable disabled\n" );
+ G_Printf( S_COLOR_YELLOW "WARNING: %s not allowed in stage 1\n",
+ BG_FindHumanNameForBuildable( buildable ) );
return qfalse;
}
}
diff --git a/src/game/g_target.c b/src/game/g_target.c
index 9022eb06..ee2d096f 100644
--- a/src/game/g_target.c
+++ b/src/game/g_target.c
@@ -18,60 +18,6 @@
//==========================================================
-/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
-Gives the activator all the items pointed to.
-*/
-void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator )
-{
- //TA: FIXME: well, this is fucked
- gentity_t *t;
- trace_t trace;
-
- if( !activator->client )
- return;
-
- if( !ent->target )
- return;
-
- memset( &trace, 0, sizeof( trace ) );
- t = NULL;
-
- while( ( t = G_Find( t, FOFS( targetname ), ent->target ) ) != NULL )
- {
- // make sure it isn't going to respawn or show any events
- t->nextthink = 0;
- trap_UnlinkEntity( t );
- }
-}
-
-void SP_target_give( gentity_t *ent )
-{
- ent->use = Use_Target_Give;
-}
-
-
-//==========================================================
-
-/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
-takes away all the activators powerups.
-Used to drop flight powerups into death puts.
-*/
-void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator )
-{
- if( !activator->client )
- return;
-
- memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
-}
-
-void SP_target_remove_powerups( gentity_t *ent )
-{
- ent->use = Use_target_remove_powerups;
-}
-
-
-//==========================================================
-
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
"wait" seconds to pause before firing targets.
"random" delay variance, total delay = delay +/- random seconds
@@ -124,7 +70,7 @@ void SP_target_score( gentity_t *ent )
//==========================================================
-/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
+/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) humanteam alienteam private
"message" text to print
If "private", only the activator gets the message. If no checks, all clients get the message.
*/
@@ -237,108 +183,6 @@ void SP_target_speaker( gentity_t *ent )
trap_LinkEntity( ent );
}
-
-
-//==========================================================
-
-/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
-When triggered, fires a laser. You can either set a target or a direction.
-*/
-void target_laser_think( gentity_t *self )
-{
- vec3_t end;
- trace_t tr;
- vec3_t point;
-
- // if pointed at another entity, set movedir to point at it
- if( self->enemy )
- {
- VectorMA( self->enemy->s.origin, 0.5, self->enemy->r.mins, point );
- VectorMA( point, 0.5, self->enemy->r.maxs, point );
- VectorSubtract( point, self->s.origin, self->movedir );
- VectorNormalize( self->movedir );
- }
-
- // fire forward and see what we hit
- VectorMA( self->s.origin, 2048, self->movedir, end );
-
- trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number,
- CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_CORPSE );
-
- if( tr.entityNum )
- {
- // hurt it if we can
- G_Damage( &g_entities[ tr.entityNum ], self, self->activator, self->movedir,
- tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER );
- }
-
- VectorCopy( tr.endpos, self->s.origin2 );
-
- trap_LinkEntity( self );
- self->nextthink = level.time + FRAMETIME;
-}
-
-void target_laser_on( gentity_t *self )
-{
- if( !self->activator )
- self->activator = self;
-
- target_laser_think( self );
-}
-
-void target_laser_off( gentity_t *self )
-{
- trap_UnlinkEntity( self );
- self->nextthink = 0;
-}
-
-void target_laser_use( gentity_t *self, gentity_t *other, gentity_t *activator )
-{
- self->activator = activator;
- if( self->nextthink > 0 )
- target_laser_off( self );
- else
- target_laser_on( self );
-}
-
-void target_laser_start( gentity_t *self )
-{
- gentity_t *ent;
-
- self->s.eType = ET_BEAM;
-
- if( self->target )
- {
- ent = G_Find( NULL, FOFS( targetname ), self->target );
-
- if( !ent )
- G_Printf ( "%s at %s: %s is a bad target\n", self->classname, vtos( self->s.origin ), self->target );
-
- self->enemy = ent;
- }
- else
- G_SetMovedir( self->s.angles, self->movedir );
-
- self->use = target_laser_use;
- self->think = target_laser_think;
-
- if( !self->damage )
- self->damage = 1;
-
- if( self->spawnflags & 1 )
- target_laser_on( self );
- else
- target_laser_off( self );
-}
-
-void SP_target_laser( gentity_t *self )
-{
- // let everything else get spawned before we start firing
- self->think = target_laser_start;
- self->nextthink = level.time + FRAMETIME;
-}
-
-
//==========================================================
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator )
@@ -399,7 +243,7 @@ void target_relay_use( gentity_t *self, gentity_t *other, gentity_t *activator )
return;
}
- G_UseTargets (self, activator);
+ G_UseTargets( self, activator );
}
void SP_target_relay( gentity_t *self )