From b4227be79cccc641a4dd471ff8fb367b79ac84b1 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Thu, 3 Jun 2004 21:09:13 +0000 Subject: * func_trains are now triggerable and optionally stop when blocked * Added "itemtoggle " command to toggle between blaster and primary --- src/game/g_cmds.c | 37 +++++++++++++++-- src/game/g_local.h | 1 + src/game/g_mover.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 149 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 20a58e84..27341b94 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1373,15 +1373,46 @@ Cmd_ToggleItem_f void Cmd_ToggleItem_f( gentity_t *ent ) { char s[ MAX_TOKEN_CHARS ]; - int upgrade; + int upgrade, weapon, i; trap_Argv( 1, s, sizeof( s ) ); upgrade = BG_FindUpgradeNumForName( s ); + weapon = BG_FindWeaponNumForName( s ); if( ent->client->pers.teamSelection != PTE_HUMANS ) return; - - if( BG_gotItem( upgrade, ent->client->ps.stats ) ) + + if( weapon == WP_NONE ) + { + //special case to allow switching between + //the blaster and the primary weapon + + if( ent->client->ps.weapon != WP_BLASTER ) + weapon = WP_BLASTER; + else + { + //find a held weapon which isn't the blaster + for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) + { + if( i == WP_BLASTER ) + continue; + + if( BG_gotWeapon( i, ent->client->ps.stats ) ) + { + weapon = i; + break; + } + } + + if( i == WP_NUM_WEAPONS ) + weapon = WP_BLASTER; + } + + //force a weapon change + ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; + trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) ); + } + else if( BG_gotItem( upgrade, ent->client->ps.stats ) ) { if( BG_activated( upgrade, ent->client->ps.stats ) ) BG_deactivateItem( upgrade, ent->client->ps.stats ); diff --git a/src/game/g_local.h b/src/game/g_local.h index 82681dc5..33379dfd 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -132,6 +132,7 @@ struct gentity_s gentity_t *target_ent; float speed; + float lastSpeed; //TA: used by trains that have been restarted vec3_t movedir; //TA: acceleration evaluation diff --git a/src/game/g_mover.c b/src/game/g_mover.c index b3c01069..192a46cc 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -1979,9 +1979,8 @@ TRAIN */ -#define TRAIN_START_ON 1 -#define TRAIN_TOGGLE 2 -#define TRAIN_BLOCK_STOPS 4 +#define TRAIN_START_OFF 1 +#define TRAIN_BLOCK_STOPS 2 /* =============== @@ -2035,6 +2034,8 @@ void Reached_Train( gentity_t *ent ) if( speed < 1 ) speed = 1; + ent->lastSpeed = speed; + // calculate duration VectorSubtract( ent->pos2, ent->pos1, move ); length = VectorLength( move ); @@ -2047,6 +2048,12 @@ void Reached_Train( gentity_t *ent ) // start it going SetMoverState( ent, MOVER_1TO2, level.time ); + if( ent->spawnflags & TRAIN_START_OFF ) + { + ent->s.pos.trType = TR_STATIONARY; + return; + } + // if there is a "wait" value on the target, don't start moving yet if( next->wait ) { @@ -2056,6 +2063,59 @@ void Reached_Train( gentity_t *ent ) } } +/* +================ +Start_Train +================ +*/ +void Start_Train( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + vec3_t move; + + //recalculate duration as the mover is highly + //unlikely to be right on a path_corner + VectorSubtract( ent->pos2, ent->pos1, move ); + ent->s.pos.trDuration = VectorLength( move ) * 1000 / ent->lastSpeed; + SetMoverState( ent, MOVER_1TO2, level.time ); + + ent->spawnflags &= ~TRAIN_START_OFF; +} + +/* +================ +Stop_Train +================ +*/ +void Stop_Train( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + vec3_t origin; + + //get current origin + BG_EvaluateTrajectory( &ent->s.pos, level.time, origin ); + VectorCopy( origin, ent->pos1 ); + SetMoverState( ent, MOVER_POS1, level.time ); + + ent->spawnflags |= TRAIN_START_OFF; +} + +/* +================ +Use_Train +================ +*/ +void Use_Train( gentity_t *ent, gentity_t *other, gentity_t *activator ) +{ + if( ent->spawnflags & TRAIN_START_OFF ) + { + //train is currently not moving so start it + Start_Train( ent, other, activator ); + } + else + { + //train is moving so stop it + Stop_Train( ent, other, activator ); + } +} /* =============== @@ -2132,6 +2192,55 @@ void SP_path_corner( gentity_t *self ) // path corners don't need to be linked in } +/* +================ +Blocked_Train +================ +*/ +void Blocked_Train( gentity_t *self, gentity_t *other ) +{ + if( self->spawnflags & TRAIN_BLOCK_STOPS ) + Stop_Train( self, other, other ); + else + { + if( !other->client ) + { + //whatever is blocking the train isn't a client + + //KILL!!1!!! + G_Damage( other, self, self, NULL, NULL, 10000, 0, MOD_CRUSH ); + + //buildables need to be handled differently since even when + //dealth fatal amounts of damage they won't instantly become non-solid + if( other->s.eType == ET_BUILDABLE && other->spawned ) + { + vec3_t dir; + gentity_t *tent; + + if( other->biteam == BIT_ALIENS ) + { + VectorCopy( other->s.origin2, dir ); + tent = G_TempEntity( other->s.origin, EV_ALIEN_BUILDABLE_EXPLOSION ); + tent->s.eventParm = DirToByte( dir ); + } + else if( other->biteam == BIT_HUMANS ) + { + VectorSet( dir, 0.0f, 0.0f, 1.0f ); + tent = G_TempEntity( other->s.origin, EV_HUMAN_BUILDABLE_EXPLOSION ); + tent->s.eventParm = DirToByte( dir ); + } + } + + //if it's still around free it + if( other ) + G_FreeEntity( other ); + + return; + } + + G_Damage( other, self, self, NULL, NULL, 10000, 0, MOD_CRUSH ); + } +} /*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS @@ -2151,9 +2260,7 @@ void SP_func_train( gentity_t *self ) VectorClear( self->s.angles ); if( self->spawnflags & TRAIN_BLOCK_STOPS ) - { self->damage = 0; - } else if( !self->damage ) self->damage = 2; @@ -2171,6 +2278,8 @@ void SP_func_train( gentity_t *self ) InitMover( self ); self->reached = Reached_Train; + self->use = Use_Train; + self->blocked = Blocked_Train; // start trains on the second frame, to make sure their targets have had // a chance to spawn -- cgit