commit c1c289dc385256b5af3d850f355bc951cd50f016 Author: /dev/humancontroller Date: Sat Aug 6 02:13:03 2011 +0200 multitarget support diff --git a/src/game/g_local.h b/src/game/g_local.h index 7e6ea10..548f587 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -50,6 +50,9 @@ typedef struct gclient_s gclient_t; #define FL_NO_HUMANS 0x00004000 // spawn point just for bots #define FL_FORCE_GESTURE 0x00008000 // spawn point just for bots +#define MAX_TARGETS 4 // note: if you increase these, then also +#define MAX_TARGETNAMES 4 // change g_spawn.c to spawn extras + // movers are things like doors, plats, buttons, etc typedef enum { @@ -126,8 +129,8 @@ struct gentity_s int timestamp; // body queue sinking, etc float angle; // set in editor, -1 = up, -2 = down - char *target; - char *targetname; + char *targets[ MAX_TARGETS + 1 ]; + char *targetnames[ MAX_TARGETNAMES + 1 ]; char *team; char *targetShaderName; char *targetShaderNewName; @@ -816,11 +819,12 @@ int G_ParticleSystemIndex( char *name ); int G_ShaderIndex( char *name ); int G_ModelIndex( char *name ); int G_SoundIndex( char *name ); -void G_KillBox (gentity_t *ent); -gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match); -gentity_t *G_PickTarget (char *targetname); -void G_UseTargets (gentity_t *ent, gentity_t *activator); -void G_SetMovedir ( vec3_t angles, vec3_t movedir); +void G_KillBox( gentity_t *ent ); +gentity_t *G_Find( gentity_t *from, int fieldofs, const char *match ); +gentity_t *G_TargetFind( gentity_t *targ, int *tIx, int *tnIx, gentity_t *self ); +gentity_t *G_PickTarget( gentity_t *self ); +void G_UseTargets( gentity_t *ent, gentity_t *activator ); +void G_SetMovedir( vec3_t angles, vec3_t movedir ); void G_InitGentity( gentity_t *e ); gentity_t *G_Spawn( void ); diff --git a/src/game/g_main.c b/src/game/g_main.c index b2824df..39a8482 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -383,7 +383,7 @@ All but the last will have the teamchain field set to the next one void G_FindTeams( void ) { gentity_t *e, *e2; - int i, j; + int i, j, k; int c, c2; c = 0; @@ -424,10 +424,10 @@ void G_FindTeams( void ) e2->flags |= FL_TEAMSLAVE; // make sure that targets only point at the master - if( e2->targetname ) + for( k = 0; e2->targetnames[ k ]; k++ ) { - e->targetname = e2->targetname; - e2->targetname = NULL; + e->targetnames[ k ] = e2->targetnames[ k ]; + e2->targetnames[ k ] = NULL; } } } @@ -1572,18 +1572,13 @@ void FindIntermissionPoint( void ) VectorCopy( ent->s.origin, level.intermission_origin ); VectorCopy( ent->s.angles, level.intermission_angle ); // if it has a target, look towards it - if( ent->target ) + target = G_PickTarget( ent ); + if( target ) { - target = G_PickTarget( ent->target ); - - if( target ) - { - VectorSubtract( target->s.origin, level.intermission_origin, dir ); - vectoangles( dir, level.intermission_angle ); - } + VectorSubtract( target->s.origin, level.intermission_origin, dir ); + vectoangles( dir, level.intermission_angle ); } } - } /* diff --git a/src/game/g_misc.c b/src/game/g_misc.c index c70b2a9..d31406a 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -148,7 +148,7 @@ void locateCamera( gentity_t *ent ) gentity_t *target; gentity_t *owner; - owner = G_PickTarget( ent->target ); + owner = G_PickTarget( ent ); if( !owner ) { G_Printf( "Couldn't find target for misc_portal_surface\n" ); @@ -178,7 +178,7 @@ void locateCamera( gentity_t *ent ) VectorCopy( owner->s.origin, ent->s.origin2 ); // see if the portal_camera has a target - target = G_PickTarget( owner->target ); + target = G_PickTarget( owner ); if( target ) { VectorSubtract( target->s.origin, owner->s.origin, dir ); @@ -203,7 +203,7 @@ void SP_misc_portal_surface( gentity_t *ent ) ent->r.svFlags = SVF_PORTAL; ent->s.eType = ET_PORTAL; - if( !ent->target ) + if( !ent->targets[ 0 ] ) { VectorCopy( ent->s.origin, ent->s.origin2 ); } diff --git a/src/game/g_mover.c b/src/game/g_mover.c index fa7e962..be6530e 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -836,7 +836,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) moverState_t teamState; // if this is a non-client-usable door return - if( ent->targetname && other && other->client ) + if( ent->targetnames[ 0 ] && other && other->client ) return; // only the master should be used @@ -1335,18 +1335,15 @@ void manualTriggerSpectator( gentity_t *trigger, gentity_t *player ) { gentity_t *t = NULL; gentity_t *targets[ MAX_GENTITIES ]; - int i = 0, j; + int i = 0, j, k; float minDistance = (float)INFINITE; //restrict this hack to trigger_multiple only for now if( strcmp( trigger->classname, "trigger_multiple" ) ) return; - if( !trigger->target ) - return; - //create a list of door entities this trigger targets - while( ( t = G_Find( t, FOFS( targetname ), trigger->target ) ) != NULL ) + while( ( t = G_TargetFind( t, &j, &k, trigger ) ) != NULL ) { if( !strcmp( t->classname, "func_door" ) ) targets[ i++ ] = t; @@ -1553,7 +1550,7 @@ void SP_func_door( gentity_t *ent ) if( health ) ent->takedamage = qtrue; - if( ent->targetname || health ) + if( ent->targetnames[ 0 ] || health ) { // non touch/shoot doors ent->think = Think_MatchTeam; @@ -1667,7 +1664,7 @@ void SP_func_door_rotating( gentity_t *ent ) if( health ) ent->takedamage = qtrue; - if( ent->targetname || health ) + if( ent->targetnames[ 0 ] || ent->health ) { // non touch/shoot doors ent->think = Think_MatchTeam; @@ -1805,7 +1802,7 @@ void SP_func_door_model( gentity_t *ent ) if( health ) ent->takedamage = qtrue; - if( !( ent->targetname || health ) ) + if( !( ent->targetnames[ 0 ] || ent->health ) ) { ent->nextthink = level.time + FRAMETIME; ent->think = Think_SpawnNewDoorTrigger; @@ -1964,7 +1961,7 @@ void SP_func_plat( gentity_t *ent ) ent->parent = ent; // so it can be treated as a door // spawn the trigger if one hasn't been custom made - if( !ent->targetname ) + if( !ent->targetnames[ 0 ] ) SpawnPlatTrigger( ent ); } @@ -2227,8 +2224,9 @@ Link all the corners together void Think_SetupTrainTargets( gentity_t *ent ) { gentity_t *path, *next, *start; + int i, j; - ent->nextTrain = G_Find( NULL, FOFS( targetname ), ent->target ); + ent->nextTrain = G_TargetFind( NULL, &i, &j, ent ); if( !ent->nextTrain ) { @@ -2243,7 +2241,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) if( !start ) start = path; - if( !path->target ) + if( !path->targets[ 0 ] ) { G_Printf( "Train corner at %s without a target\n", vtos( path->s.origin ) ); @@ -2256,7 +2254,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) next = NULL; do { - next = G_Find( next, FOFS( targetname ), path->target ); + next = G_TargetFind( next, &i, &j, path ); if( !next ) { @@ -2283,7 +2281,7 @@ Target: next path corner and other targets to fire */ void SP_path_corner( gentity_t *self ) { - if( !self->targetname ) + if( !self->targetnames[ 0 ] ) { G_Printf( "path_corner with no targetname at %s\n", vtos( self->s.origin ) ); G_FreeEntity( self ); @@ -2367,7 +2365,7 @@ void SP_func_train( gentity_t *self ) if( !self->speed ) self->speed = 100; - if( !self->target ) + if( !self->targets[ 0 ] ) { G_Printf( "func_train without a target at %s\n", vtos( self->r.absmin ) ); G_FreeEntity( self ); diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 5a9cac2..6dc67f8 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -130,8 +130,14 @@ field_t fields[ ] = {"rotatorAngle", FOFS(rotatorAngle), F_FLOAT}, {"spawnflags", FOFS(spawnflags), F_INT}, {"speed", FOFS(speed), F_FLOAT}, - {"target", FOFS(target), F_STRING}, - {"targetname", FOFS(targetname), F_STRING}, + {"target", FOFS(targets[ 0 ]), F_STRING}, + {"target2", FOFS(targets[ 1 ]), F_STRING}, + {"target3", FOFS(targets[ 2 ]), F_STRING}, + {"target4", FOFS(targets[ 3 ]), F_STRING}, + {"targetname", FOFS(targetnames[ 0 ]), F_STRING}, + {"targetname2", FOFS(targetnames[ 1 ]), F_STRING}, + {"targetname3", FOFS(targetnames[ 2 ]), F_STRING}, + {"targetname4", FOFS(targetnames[ 3 ]), F_STRING}, {"targetShaderName", FOFS(targetShaderName), F_STRING}, {"targetShaderNewName", FOFS(targetShaderNewName), F_STRING}, {"wait", FOFS(wait), F_FLOAT} @@ -443,7 +449,7 @@ level.spawnVars[], then call the class specfic spawn function */ void G_SpawnGEntityFromSpawnVars( void ) { - int i; + int i, j; gentity_t *ent; // get the next free entity @@ -464,6 +470,20 @@ void G_SpawnGEntityFromSpawnVars( void ) VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); + // don't leave any "gaps" + j = 0; + for( i = 0; i < MAX_TARGETS; ++i ) + { + if( ent->targets[ i ] ) + ent->targets[ j++ ] = ent->targets[ i ]; + } + j = 0; + for( i = 0; i < MAX_TARGETNAMES; ++i ) + { + if( ent->targetnames[ i ] ) + ent->targetnames[ j++ ] = ent->targetnames[ i ]; + } + // if we didn't get a classname, don't bother spawning anything if( !G_CallSpawn( ent ) ) G_FreeEntity( ent ); diff --git a/src/game/g_target.c b/src/game/g_target.c index 03d78ca..790a913 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -203,7 +203,7 @@ void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activa if( !activator || !activator->client ) return; - dest = G_PickTarget( self->target ); + dest = G_PickTarget( self ); if( !dest ) { @@ -219,7 +219,7 @@ The activator will be teleported away. */ void SP_target_teleporter( gentity_t *self ) { - if( !self->targetname ) + if( !self->targetnames[ 0 ] ) G_Printf( "untargeted %s at %s\n", self->classname, vtos( self->s.origin ) ); G_SpawnFloat( "speed", "400", &self->speed ); @@ -249,7 +249,7 @@ void target_relay_use( gentity_t *self, gentity_t *other, gentity_t *activator ) { gentity_t *ent; - ent = G_PickTarget( self->target ); + ent = G_PickTarget( self ); if( ent && ent->use ) ent->use( ent, self, activator ); @@ -388,7 +388,7 @@ SP_target_rumble */ void SP_target_rumble( gentity_t *self ) { - if( !self->targetname ) + if( !self->targetnames[ 0 ] ) { G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname, vtos( self->s.origin ) ); @@ -467,7 +467,7 @@ SP_target_hurt */ void SP_target_hurt( gentity_t *self ) { - if( !self->targetname ) + if( !self->targetnames[ 0 ] ) { G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname, vtos( self->s.origin ) ); diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index 8d1a9ff..fa215bf 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -181,7 +181,7 @@ void AimAtTarget( gentity_t *self ) VectorAdd( self->r.absmin, self->r.absmax, origin ); VectorScale( origin, 0.5, origin ); - ent = G_PickTarget( self->target ); + ent = G_PickTarget( self ); if( !ent ) { @@ -254,7 +254,7 @@ void SP_target_push( gentity_t *self ) G_SetMovedir( self->s.angles, self->s.origin2 ); VectorScale( self->s.origin2, self->speed, self->s.origin2 ); - if( self->target ) + if( self->targets[ 0 ] ) { VectorCopy( self->s.origin, self->r.absmin ); VectorCopy( self->s.origin, self->r.absmax ); @@ -292,7 +292,7 @@ void trigger_teleporter_touch( gentity_t *self, gentity_t *other, trace_t *trace return; - dest = G_PickTarget( self->target ); + dest = G_PickTarget( self ); if( !dest ) { diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 2d5d1c2..81474ad 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -184,41 +184,52 @@ gentity_t *G_Find( gentity_t *from, int fieldofs, const char *match ) /* ============= -G_PickTarget - -Selects a random entity from among the targets +G_FindTargets ============= */ -#define MAXCHOICES 32 - -gentity_t *G_PickTarget( char *targetname ) +gentity_t *G_TargetFind( gentity_t *targ, int *tIx, int *tnIx, gentity_t *self ) { - gentity_t *ent = NULL; - int num_choices = 0; - gentity_t *choice[ MAXCHOICES ]; + if( targ ) + goto cont; - if( !targetname ) + for( *tIx = 0; self->targets[ *tIx ]; ++(*tIx) ) { - G_Printf("G_PickTarget called with NULL targetname\n"); - return NULL; + for( *tnIx = 0; *tnIx < MAX_TARGETNAMES; ++(*tnIx) ) + { + cont: + targ = G_Find( targ, FOFS( targetnames[ *tnIx ] ), self->targets[ *tIx ] ); + if( targ ) + return targ; + } } - while( 1 ) - { - ent = G_Find( ent, FOFS( targetname ), targetname ); + return NULL; +} - if( !ent ) - break; - choice[ num_choices++ ] = ent; +/* +============= +G_PickTarget - if( num_choices == MAXCHOICES ) - break; - } +Selects a random entity from among the targets +============= +*/ +gentity_t *G_PickTarget( gentity_t *self ) +{ + int i, j; + gentity_t *t = NULL; + int num_choices = 0; + gentity_t *choice[ MAX_GENTITIES ]; + + while( ( t = G_TargetFind( t, &i, &j, self ) ) != NULL ) + choice[ num_choices++ ] = t; if( !num_choices ) { - G_Printf( "G_PickTarget: target %s not found\n", targetname ); + G_Printf( "G_PickTarget: none of the following targets were found:" ); + for( i = 0; self->targets[ i ]; ++i ) + G_Printf( "%s %s", ( i == 0 ? "" : "," ), self->targets[ i ] ); + G_Printf( "\n" ); return NULL; } @@ -232,14 +243,14 @@ G_UseTargets "activator" should be set to the entity that initiated the firing. -Search for (string)targetname in all entities that -match (string)self.target and call their .use function - +For all t in the entities, where t.targetnames[i] matches +ent.targets[j] for any (i,j) pairs, call the t.use function. ============================== */ void G_UseTargets( gentity_t *ent, gentity_t *activator ) { - gentity_t *t; + gentity_t *t = NULL; + int i, j; if( !ent ) return; @@ -251,24 +262,17 @@ void G_UseTargets( gentity_t *ent, gentity_t *activator ) trap_SetConfigstring( CS_SHADERSTATE, BuildShaderStateConfig( ) ); } - if( !ent->target ) - return; - - t = NULL; - while( ( t = G_Find( t, FOFS( targetname ), ent->target ) ) != NULL ) + while( ( t = G_TargetFind( t, &i, &j, ent ) ) != NULL ) { - if( t == ent ) - G_Printf( "WARNING: Entity used itself.\n" ); - else + if( t->use ) { - if( t->use ) - t->use( t, ent, activator ); - } + t->use( t, ent, activator ); - if( !ent->inuse ) - { - G_Printf( "entity was removed while using targets\n" ); - return; + if( !ent->inuse ) + { + G_Printf( "entity was removed while using targets\n" ); + return; + } } } }