diff options
author | Tim Angus <tim@ngus.net> | 2004-06-03 21:09:13 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2004-06-03 21:09:13 +0000 |
commit | b4227be79cccc641a4dd471ff8fb367b79ac84b1 (patch) | |
tree | eb3f55e10c827efaa4358f2a4bd4affb6d6476df | |
parent | 39b9fa4274fee270f9b67f3a7c4a18e0acceb675 (diff) |
* func_trains are now triggerable and optionally stop when blocked
* Added "itemtoggle <any weapon>" command to toggle between blaster and primary
-rw-r--r-- | entities.def | 17 | ||||
-rw-r--r-- | src/game/g_cmds.c | 37 | ||||
-rw-r--r-- | src/game/g_local.h | 1 | ||||
-rw-r--r-- | src/game/g_mover.c | 119 |
4 files changed, 159 insertions, 15 deletions
diff --git a/entities.def b/entities.def index bd58da55..979152f7 100644 --- a/entities.def +++ b/entities.def @@ -687,8 +687,8 @@ When the random key is set, its value is used to calculate a minimum and a maxim //============================================================================= -/*QUAKED func_train (0 .5 .8) ? -Trains are moving solids that follow a string of path_corner entities. Trains in Q3A are very basic, they also require an origin brush (see Notes). +/*QUAKED func_train (0 .5 .8) ? START_OFF BLOCK_STOPS +Trains are moving solids that follow a string of path_corner entities. Trains in Tremulous are less basic than in Q3A, they also require an origin brush (see Notes). -------- KEYS -------- speed: speed of displacement of train (default 100 or overridden by speed value of path). @@ -709,6 +709,11 @@ notteam: when set to 1, entity will not spawn in "Teamplay" and "CTF" modes. notsingle: when set to 1, entity will not spawn in Single Player mode (bot play mode). +-------- SPAWNFLAGS -------- +START_OFF: the train will spawn in the off state + +BLOCK_STOPS: with this set a train simply stops if blocked, instead of killing. + -------- Q3MAP2 KEYS -------- _targetname: Used to attach a misc_model entity to this entity. @@ -728,11 +733,9 @@ _layers OR layers: Integer value is the number unique root shaders that will be _shader OR shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. -------- NOTES -------- -1. Trains always start on in the game. -2. Trains do not damage the player when blocked. -3. Trains cannot emit sound. -4. Trains are not triggerable or toggle-able. -5. Trains cannot be block-stopped just by getting in their way, the player must be wedged between the train and another obstacle to block it. +1. Trains instakill anything in their path by default. +2. Trains cannot emit sound. +3. When BLOCK_STOPS is set, trains cannot be stopped just by getting in their way, the player must be wedged between the train and another obstacle to block it. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value. 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 |