summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/g_active.c8
-rw-r--r--src/game/g_cmds.c2
-rw-r--r--src/game/g_local.h7
-rw-r--r--src/game/g_spawn.c14
-rw-r--r--src/game/g_target.c70
-rw-r--r--src/game/g_trigger.c609
-rw-r--r--src/game/tremulous.h4
7 files changed, 708 insertions, 6 deletions
diff --git a/src/game/g_active.c b/src/game/g_active.c
index f01e2379..acd6a4f1 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1096,6 +1096,11 @@ void ClientThink_real( gentity_t *ent )
VectorCopy( client->ps.origin, client->oldOrigin );
+ // moved from after Pmove -- potentially the cause of
+ // future triggering bugs
+ if( !ent->client->noclip )
+ G_TouchTriggers( ent );
+
Pmove( &pm );
// save results of pmove
@@ -1129,9 +1134,6 @@ void ClientThink_real( gentity_t *ent )
// link entity now, after any personal teleporters have been used
trap_LinkEntity( ent );
- if( !ent->client->noclip )
- G_TouchTriggers( ent );
-
// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 27341b94..cbd10555 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -1382,7 +1382,7 @@ void Cmd_ToggleItem_f( gentity_t *ent )
if( ent->client->pers.teamSelection != PTE_HUMANS )
return;
- if( weapon == WP_NONE )
+ if( weapon != WP_NONE )
{
//special case to allow switching between
//the blaster and the primary weapon
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 33379dfd..5972c356 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -217,6 +217,13 @@ struct gentity_s
gentity_t *builder; //TA: occupant of this hovel
qboolean nonSegModel; //TA: this entity uses a nonsegmented player model
+
+ buildable_t bTriggers[ BA_NUM_BUILDABLES ]; //TA: which buildables are triggers
+ pClass_t cTriggers[ PCL_NUM_CLASSES ]; //TA: which classes are triggers
+ weapon_t wTriggers[ WP_NUM_WEAPONS ]; //TA: which weapons are triggers
+ upgrade_t uTriggers[ UP_NUM_UPGRADES ]; //TA: which upgrades are triggers
+
+ int triggerGravity; //TA: gravity for this trigger
};
typedef enum
diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c
index 29967e1c..ebd6dc45 100644
--- a/src/game/g_spawn.c
+++ b/src/game/g_spawn.c
@@ -179,6 +179,12 @@ void SP_trigger_push( gentity_t *ent );
void SP_trigger_teleport( gentity_t *ent );
void SP_trigger_hurt( gentity_t *ent );
void SP_trigger_stage( gentity_t *ent );
+void SP_trigger_buildable( gentity_t *ent );
+void SP_trigger_class( gentity_t *ent );
+void SP_trigger_equipment( gentity_t *ent );
+void SP_trigger_gravity( gentity_t *ent );
+void SP_trigger_heal( gentity_t *ent );
+void SP_trigger_ammo( gentity_t *ent );
void SP_target_delay( gentity_t *ent );
void SP_target_speaker( gentity_t *ent );
@@ -191,6 +197,7 @@ void SP_target_kill( gentity_t *ent );
void SP_target_position( gentity_t *ent );
void SP_target_location( gentity_t *ent );
void SP_target_push( gentity_t *ent );
+void SP_target_rumble( gentity_t *ent );
void SP_light( gentity_t *self );
void SP_info_null( gentity_t *self );
@@ -252,6 +259,12 @@ spawn_t spawns[ ] =
{ "trigger_teleport", SP_trigger_teleport },
{ "trigger_hurt", SP_trigger_hurt },
{ "trigger_stage", SP_trigger_stage },
+ { "trigger_buildable", SP_trigger_buildable },
+ { "trigger_class", SP_trigger_class },
+ { "trigger_equipment", SP_trigger_equipment },
+ { "trigger_gravity", SP_trigger_gravity },
+ { "trigger_heal", SP_trigger_heal },
+ { "trigger_ammo", SP_trigger_ammo },
// targets perform no action by themselves, but must be triggered
// by another entity
@@ -265,6 +278,7 @@ spawn_t spawns[ ] =
{ "target_position", SP_target_position },
{ "target_location", SP_target_location },
{ "target_push", SP_target_push },
+ { "target_rumble", SP_target_rumble },
{ "light", SP_light },
{ "path_corner", SP_path_corner },
diff --git a/src/game/g_target.c b/src/game/g_target.c
index ee2d096f..64a3f33e 100644
--- a/src/game/g_target.c
+++ b/src/game/g_target.c
@@ -320,3 +320,73 @@ void SP_target_location( gentity_t *self )
G_SetOrigin( self, self->s.origin );
}
+
+/*
+===============
+target_rumble_think
+===============
+*/
+void target_rumble_think( gentity_t *self )
+{
+ int i;
+ gentity_t *ent;
+
+ if( self->last_move_time < level.time )
+ self->last_move_time = level.time + 0.5;
+
+ for( i = 0, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( !ent->inuse )
+ continue;
+
+ if( !ent->client )
+ continue;
+
+ if( ent->client->ps.groundEntityNum == ENTITYNUM_NONE )
+ continue;
+
+ ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
+ ent->client->ps.velocity[ 0 ] += crandom( ) * 150;
+ ent->client->ps.velocity[ 1 ] += crandom( ) * 150;
+ ent->client->ps.velocity[ 2 ] = self->speed;
+ }
+
+ if( level.time < self->timestamp )
+ self->nextthink = level.time + FRAMETIME;
+}
+
+/*
+===============
+target_rumble_use
+===============
+*/
+void target_rumble_use( gentity_t *self, gentity_t *other, gentity_t *activator )
+{
+ self->timestamp = level.time + ( self->count * FRAMETIME );
+ self->nextthink = level.time + FRAMETIME;
+ self->activator = activator;
+ self->last_move_time = 0;
+}
+
+/*
+===============
+SP_target_rumble
+===============
+*/
+void SP_target_rumble( gentity_t *self )
+{
+ if( !self->targetname )
+ {
+ G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
+ vtos( self->s.origin ) );
+ }
+
+ if( !self->count )
+ self->count = 10;
+
+ if( !self->speed )
+ self->speed = 100;
+
+ self->think = target_rumble_think;
+ self->use = target_rumble_use;
+}
diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c
index cffa0e66..01279cd6 100644
--- a/src/game/g_trigger.c
+++ b/src/game/g_trigger.c
@@ -503,6 +503,11 @@ void G_Checktrigger_stages( pTeam_t team, stage_t stage )
}
+/*
+===============
+trigger_stage_use
+===============
+*/
void trigger_stage_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
G_UseTargets( self, self );
@@ -517,3 +522,607 @@ void SP_trigger_stage( gentity_t *self )
self->r.svFlags = SVF_NOCLIENT;
}
+
+
+/*
+===============
+trigger_buildable_trigger
+===============
+*/
+void trigger_buildable_trigger( gentity_t *self, gentity_t *activator )
+{
+ int i = 0;
+
+ self->activator = activator;
+ if( self->nextthink )
+ return; // can't retrigger until the wait is over
+
+ //if there is no buildable list every buildable triggers
+ if( self->bTriggers[ i ] == BA_NONE )
+ G_UseTargets( self, activator );
+ else
+ {
+ //otherwise check against the list
+ for( i = 0; self->bTriggers[ i ] != BA_NONE; i++ )
+ {
+ if( activator->s.modelindex == self->bTriggers[ i ] )
+ {
+ G_UseTargets( self, activator );
+ return;
+ }
+ }
+ }
+
+ if( self->wait > 0 )
+ {
+ self->think = multi_wait;
+ self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
+ }
+ else
+ {
+ // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ self->touch = 0;
+ self->nextthink = level.time + FRAMETIME;
+ self->think = G_FreeEntity;
+ }
+}
+
+/*
+===============
+trigger_buildable_touch
+===============
+*/
+void trigger_buildable_touch( gentity_t *ent, gentity_t *other, trace_t *trace )
+{
+ //only triggered by buildables
+ if( other->s.eType != ET_BUILDABLE )
+ return;
+
+ trigger_buildable_trigger( ent, other );
+}
+
+/*
+===============
+trigger_buildable_use
+===============
+*/
+void trigger_buildable_use( gentity_t *ent, gentity_t *other, gentity_t *activator )
+{
+ trigger_buildable_trigger( ent, activator );
+}
+
+/*
+===============
+SP_trigger_buildable
+===============
+*/
+void SP_trigger_buildable( gentity_t *self )
+{
+ char *buffer;
+ int i = 0;
+ char *p, *q;
+ qboolean EOS = qfalse;
+
+ G_SpawnFloat( "wait", "0.5", &self->wait );
+ G_SpawnFloat( "random", "0", &self->random );
+
+ if( self->random >= self->wait && self->wait >= 0 )
+ {
+ self->random = self->wait - FRAMETIME;
+ G_Printf( S_COLOR_YELLOW "WARNING: trigger_buildable has random >= wait\n" );
+ }
+
+ G_SpawnString( "buildables", "", &buffer );
+
+ p = q = buffer;
+
+ while( *p != '\0' )
+ {
+ //skip to first , or EOS
+ while( *p != ',' && *p != '\0' )
+ p++;
+
+ if( *p == '\0' )
+ EOS = qtrue;
+
+ *p = '\0';
+
+ //strip leading whitespace
+ while( *q == ' ' )
+ q++;
+
+ self->bTriggers[ i ] = BG_FindBuildNumForName( q );
+ if( self->bTriggers[ i ] == BA_NONE )
+ G_Printf( S_COLOR_YELLOW "WARNING: unknown buildable %s in trigger_buildable\n", q );
+ else
+ i++;
+
+ if( !EOS )
+ {
+ p++;
+ q = p;
+ }
+ else
+ break;
+ }
+
+ self->bTriggers[ i ] = BA_NONE;
+
+ self->touch = trigger_buildable_touch;
+ self->use = trigger_buildable_use;
+
+ InitTrigger( self );
+ trap_LinkEntity( self );
+}
+
+
+/*
+===============
+trigger_class_trigger
+===============
+*/
+void trigger_class_trigger( gentity_t *self, gentity_t *activator )
+{
+ int i = 0;
+
+ //sanity check
+ if( !activator->client )
+ return;
+
+ if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ return;
+
+ self->activator = activator;
+ if( self->nextthink )
+ return; // can't retrigger until the wait is over
+
+ //if there is no class list every class triggers (stupid case)
+ if( self->cTriggers[ i ] == PCL_NONE )
+ G_UseTargets( self, activator );
+ else
+ {
+ //otherwise check against the list
+ for( i = 0; self->cTriggers[ i ] != PCL_NONE; i++ )
+ {
+ if( activator->client->ps.stats[ STAT_PCLASS ] == self->cTriggers[ i ] )
+ {
+ G_UseTargets( self, activator );
+ return;
+ }
+ }
+ }
+
+ if( self->wait > 0 )
+ {
+ self->think = multi_wait;
+ self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
+ }
+ else
+ {
+ // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ self->touch = 0;
+ self->nextthink = level.time + FRAMETIME;
+ self->think = G_FreeEntity;
+ }
+}
+
+/*
+===============
+trigger_class_touch
+===============
+*/
+void trigger_class_touch( gentity_t *ent, gentity_t *other, trace_t *trace )
+{
+ //only triggered by clients
+ if( !other->client )
+ return;
+
+ trigger_class_trigger( ent, other );
+}
+
+/*
+===============
+trigger_class_use
+===============
+*/
+void trigger_class_use( gentity_t *ent, gentity_t *other, gentity_t *activator )
+{
+ trigger_class_trigger( ent, activator );
+}
+
+/*
+===============
+SP_trigger_class
+===============
+*/
+void SP_trigger_class( gentity_t *self )
+{
+ char *buffer;
+ int i = 0;
+ char *p, *q;
+ qboolean EOS = qfalse;
+
+ G_SpawnFloat( "wait", "0.5", &self->wait );
+ G_SpawnFloat( "random", "0", &self->random );
+
+ if( self->random >= self->wait && self->wait >= 0 )
+ {
+ self->random = self->wait - FRAMETIME;
+ G_Printf( S_COLOR_YELLOW "WARNING: trigger_class has random >= wait\n" );
+ }
+
+ G_SpawnString( "classes", "", &buffer );
+
+ p = q = buffer;
+
+ while( *p != '\0' )
+ {
+ //skip to first , or EOS
+ while( *p != ',' && *p != '\0' )
+ p++;
+
+ if( *p == '\0' )
+ EOS = qtrue;
+
+ *p = '\0';
+
+ //strip leading whitespace
+ while( *q == ' ' )
+ q++;
+
+ self->cTriggers[ i ] = BG_FindClassNumForName( q );
+ if( self->cTriggers[ i ] == PCL_NONE )
+ G_Printf( S_COLOR_YELLOW "WARNING: unknown class %s in trigger_class\n", q );
+ else
+ i++;
+
+ if( !EOS )
+ {
+ p++;
+ q = p;
+ }
+ else
+ break;
+ }
+
+ self->cTriggers[ i ] = PCL_NONE;
+
+ self->touch = trigger_class_touch;
+ self->use = trigger_class_use;
+
+ InitTrigger( self );
+ trap_LinkEntity( self );
+}
+
+
+/*
+===============
+trigger_equipment_trigger
+===============
+*/
+void trigger_equipment_trigger( gentity_t *self, gentity_t *activator )
+{
+ int i = 0;
+
+ //sanity check
+ if( !activator->client )
+ return;
+
+ if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ return;
+
+ self->activator = activator;
+ if( self->nextthink )
+ return; // can't retrigger until the wait is over
+
+ //if there is no equipment list all equipment triggers (stupid case)
+ if( self->wTriggers[ i ] == WP_NONE && self->wTriggers[ i ] == UP_NONE )
+ G_UseTargets( self, activator );
+ else
+ {
+ //otherwise check against the lists
+ for( i = 0; self->wTriggers[ i ] != WP_NONE; i++ )
+ {
+ if( BG_gotWeapon( self->wTriggers[ i ], activator->client->ps.stats ) )
+ {
+ G_UseTargets( self, activator );
+ return;
+ }
+ }
+
+ for( i = 0; self->uTriggers[ i ] != UP_NONE; i++ )
+ {
+ if( BG_gotItem( self->uTriggers[ i ], activator->client->ps.stats ) )
+ {
+ G_UseTargets( self, activator );
+ return;
+ }
+ }
+ }
+
+ if( self->wait > 0 )
+ {
+ self->think = multi_wait;
+ self->nextthink = level.time + ( self->wait + self->random * crandom( ) ) * 1000;
+ }
+ else
+ {
+ // we can't just remove (self) here, because this is a touch function
+ // called while looping through area links...
+ self->touch = 0;
+ self->nextthink = level.time + FRAMETIME;
+ self->think = G_FreeEntity;
+ }
+}
+
+/*
+===============
+trigger_equipment_touch
+===============
+*/
+void trigger_equipment_touch( gentity_t *ent, gentity_t *other, trace_t *trace )
+{
+ //only triggered by clients
+ if( !other->client )
+ return;
+
+ trigger_equipment_trigger( ent, other );
+}
+
+/*
+===============
+trigger_equipment_use
+===============
+*/
+void trigger_equipment_use( gentity_t *ent, gentity_t *other, gentity_t *activator )
+{
+ trigger_equipment_trigger( ent, activator );
+}
+
+/*
+===============
+SP_trigger_equipment
+===============
+*/
+void SP_trigger_equipment( gentity_t *self )
+{
+ char *buffer;
+ int i = 0, j = 0;
+ char *p, *q;
+ qboolean EOS = qfalse;
+
+ G_SpawnFloat( "wait", "0.5", &self->wait );
+ G_SpawnFloat( "random", "0", &self->random );
+
+ if( self->random >= self->wait && self->wait >= 0 )
+ {
+ self->random = self->wait - FRAMETIME;
+ G_Printf( S_COLOR_YELLOW "WARNING: trigger_equipment has random >= wait\n" );
+ }
+
+ G_SpawnString( "equipment", "", &buffer );
+
+ p = q = buffer;
+
+ while( *p != '\0' )
+ {
+ //skip to first , or EOS
+ while( *p != ',' && *p != '\0' )
+ p++;
+
+ if( *p == '\0' )
+ EOS = qtrue;
+
+ *p = '\0';
+
+ //strip leading whitespace
+ while( *q == ' ' )
+ q++;
+
+ self->wTriggers[ i ] = BG_FindWeaponNumForName( q );
+ self->uTriggers[ j ] = BG_FindUpgradeNumForName( q );
+
+ if( self->wTriggers[ i ] == WP_NONE && self->uTriggers[ j ] == UP_NONE )
+ G_Printf( S_COLOR_YELLOW "WARNING: unknown equipment %s in trigger_class\n", q );
+ else if( self->wTriggers[ i ] != WP_NONE )
+ i++;
+ else if( self->uTriggers[ j ] != UP_NONE )
+ j++;
+
+ if( !EOS )
+ {
+ p++;
+ q = p;
+ }
+ else
+ break;
+ }
+
+ self->wTriggers[ i ] = WP_NONE;
+ self->uTriggers[ j ] = UP_NONE;
+
+ self->touch = trigger_equipment_touch;
+ self->use = trigger_equipment_use;
+
+ InitTrigger( self );
+ trap_LinkEntity( self );
+}
+
+
+/*
+===============
+trigger_gravity_touch
+===============
+*/
+void trigger_gravity_touch( gentity_t *ent, gentity_t *other, trace_t *trace )
+{
+ //only triggered by clients
+ if( !other->client )
+ return;
+
+ other->client->ps.gravity = ent->triggerGravity;
+}
+
+/*
+===============
+trigger_gravity_use
+===============
+*/
+void trigger_gravity_use( gentity_t *ent, gentity_t *other, gentity_t *activator )
+{
+ if( ent->r.linked )
+ trap_UnlinkEntity( ent );
+ else
+ trap_LinkEntity( ent );
+}
+
+
+/*
+===============
+SP_trigger_gravity
+===============
+*/
+void SP_trigger_gravity( gentity_t *self )
+{
+ G_SpawnInt( "gravity", "800", &self->triggerGravity );
+
+ self->touch = trigger_gravity_touch;
+ self->use = trigger_gravity_use;
+
+ InitTrigger( self );
+ trap_LinkEntity( self );
+}
+
+
+/*
+===============
+trigger_heal_use
+===============
+*/
+void trigger_heal_use( gentity_t *self, gentity_t *other, gentity_t *activator )
+{
+ if( self->r.linked )
+ trap_UnlinkEntity( self );
+ else
+ trap_LinkEntity( self );
+}
+
+/*
+===============
+trigger_heal_touch
+===============
+*/
+void trigger_heal_touch( gentity_t *self, gentity_t *other, trace_t *trace )
+{
+ int max;
+
+ if( !other->client )
+ return;
+
+ if( self->timestamp > level.time )
+ return;
+
+ if( self->spawnflags & 2 )
+ self->timestamp = level.time + 1000;
+ else
+ self->timestamp = level.time + FRAMETIME;
+
+ max = other->client->ps.stats[ STAT_MAX_HEALTH ];
+
+ other->health += self->damage;
+
+ if( other->health > max )
+ other->health = max;
+
+ other->client->ps.stats[ STAT_HEALTH ] = other->health;
+}
+
+/*
+===============
+SP_trigger_heal
+===============
+*/
+void SP_trigger_heal( gentity_t *self )
+{
+ G_SpawnInt( "heal", "5", &self->damage );
+
+ self->touch = trigger_heal_touch;
+ self->use = trigger_heal_use;
+
+ InitTrigger( self );
+
+ // link in to the world if starting active
+ if( !( self->spawnflags & 1 ) )
+ trap_LinkEntity( self );
+}
+
+
+/*
+===============
+trigger_ammo_touch
+===============
+*/
+void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
+{
+ int ammo, clips, maxClips, maxAmmo;
+
+ if( !other->client )
+ return;
+
+ if( other->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ return;
+
+ if( self->timestamp > level.time )
+ return;
+
+ if( other->client->ps.weaponstate != WEAPON_READY )
+ return;
+
+ if( BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 2 )
+ return;
+
+ if( !BG_FindUsesEnergyForWeapon( other->client->ps.weapon ) && self->spawnflags & 4 )
+ return;
+
+ if( self->spawnflags & 1 )
+ self->timestamp = level.time + 1000;
+ else
+ self->timestamp = level.time + FRAMETIME;
+
+ BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, NULL, NULL );
+ BG_unpackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups,
+ &ammo, &clips, &maxClips );
+
+ if( ( ammo + self->damage ) > maxAmmo )
+ {
+ if( clips < maxClips )
+ {
+ clips++;
+ ammo = 1;
+ }
+ else
+ ammo = maxAmmo;
+ }
+ else
+ ammo += self->damage;
+
+ BG_packAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups,
+ ammo, clips, maxClips );
+}
+
+/*
+===============
+SP_trigger_ammo
+===============
+*/
+void SP_trigger_ammo( gentity_t *self )
+{
+ G_SpawnInt( "ammo", "1", &self->damage );
+
+ self->touch = trigger_ammo_touch;
+
+ InitTrigger( self );
+ trap_LinkEntity( self );
+}
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index a384852f..3c8f1cd5 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -371,9 +371,9 @@
#define FLAMER_PRICE 450
#define FLAMER_GAS 80
#define FLAMER_REPEAT 300
-#define FLAMER_DMG HDM(30)
+#define FLAMER_DMG HDM(35)
#define FLAMER_RADIUS 50
-#define FLAMER_LIFETIME 1000.0f
+#define FLAMER_LIFETIME 500.0f
#define FLAMER_SPEED 200.0f
#define FLAMER_LAG 0.65f //the amount of player velocity that is added to the fireball