diff options
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/g_active.c | 8 | ||||
-rw-r--r-- | src/game/g_cmds.c | 2 | ||||
-rw-r--r-- | src/game/g_local.h | 7 | ||||
-rw-r--r-- | src/game/g_spawn.c | 14 | ||||
-rw-r--r-- | src/game/g_target.c | 70 | ||||
-rw-r--r-- | src/game/g_trigger.c | 609 | ||||
-rw-r--r-- | src/game/tremulous.h | 4 |
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 |