summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2004-06-03 21:09:13 +0000
committerTim Angus <tim@ngus.net>2004-06-03 21:09:13 +0000
commitb4227be79cccc641a4dd471ff8fb367b79ac84b1 (patch)
treeeb3f55e10c827efaa4358f2a4bd4affb6d6476df
parent39b9fa4274fee270f9b67f3a7c4a18e0acceb675 (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.def17
-rw-r--r--src/game/g_cmds.c37
-rw-r--r--src/game/g_local.h1
-rw-r--r--src/game/g_mover.c119
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