diff options
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/bg_public.h | 10 | ||||
-rw-r--r-- | src/game/g_buildable.c | 144 | ||||
-rw-r--r-- | src/game/g_client.c | 3 | ||||
-rw-r--r-- | src/game/g_cmds.c | 1 | ||||
-rw-r--r-- | src/game/g_local.h | 4 | ||||
-rw-r--r-- | src/game/g_main.c | 5 | ||||
-rw-r--r-- | src/game/g_physics.c | 2 | ||||
-rw-r--r-- | src/game/g_svcmds.c | 3 |
8 files changed, 171 insertions, 1 deletions
diff --git a/src/game/bg_public.h b/src/game/bg_public.h index ba43b1f9..39dd1d80 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -429,6 +429,13 @@ typedef enum BA_NUM_BUILDABLES } buildable_t; +typedef enum +{ + RMT_SPHERE, + RMT_SPHERICAL_CONE_64, + RMT_SPHERICAL_CONE_240 +} rangeMarkerType_t; + // entityState_t->event values // entity events are for effects that take place relative // to an existing entities origin. Very network efficient. @@ -1176,7 +1183,8 @@ typedef enum ET_PLAYER, ET_ITEM, - ET_BUILDABLE, // buildable type + ET_BUILDABLE, + ET_RANGE_MARKER, ET_LOCATION, diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c index 3b237379..34136909 100644 --- a/src/game/g_buildable.c +++ b/src/game/g_buildable.c @@ -789,6 +789,7 @@ void AGeneric_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, i else self->nextthink = level.time; //blast immediately + G_RemoveRangeMarkerFrom( self ); G_LogDestruction( self, attacker, mod ); } @@ -1661,6 +1662,7 @@ void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int self->nextthink = level.time; //blast immediately } + G_RemoveRangeMarkerFrom( self ); G_LogDestruction( self, attacker, mod ); } @@ -1747,6 +1749,7 @@ static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *att self->nextthink = level.time; //blast immediately } + G_RemoveRangeMarkerFrom( self ); G_LogDestruction( self, attacker, mod ); if( self->usesBuildPointZone ) @@ -3020,6 +3023,7 @@ void G_FreeMarkedBuildables( gentity_t *deconner, char *readable, int rsize, if( nums ) Q_strcat( nums, nsize, va( " %d", (int)( ent - g_entities ) ) ); + G_RemoveRangeMarkerFrom( ent ); G_FreeEntity( ent ); } @@ -3491,6 +3495,55 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance /* ================ +G_AddRangeMarkerForBuildable +================ +*/ +static void G_AddRangeMarkerForBuildable( gentity_t *self ) +{ + gentity_t *rm; + + switch( self->s.modelindex ) + { + case BA_A_SPAWN: + case BA_A_OVERMIND: + case BA_A_ACIDTUBE: + case BA_A_TRAPPER: + case BA_A_HIVE: + case BA_H_MGTURRET: + case BA_H_TESLAGEN: + case BA_H_DCC: + case BA_H_REACTOR: + case BA_H_REPEATER: + break; + default: + return; + } + + rm = G_Spawn(); + rm->classname = "buildablerangemarker"; + rm->r.svFlags = SVF_BROADCAST | SVF_CLIENTMASK; + rm->s.eType = ET_RANGE_MARKER; + rm->s.modelindex = self->s.modelindex; + + self->rangeMarker = rm; +} + +/* +================ +G_RemoveRangeMarkerFrom +================ +*/ +void G_RemoveRangeMarkerFrom( gentity_t *self ) +{ + if( self->rangeMarker ) + { + G_FreeEntity( self->rangeMarker ); + self->rangeMarker = NULL; + } +} + +/* +================ G_Build Spawns a buildable @@ -3719,6 +3772,8 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, if( log ) G_BuildLogSet( log, built ); + G_AddRangeMarkerForBuildable( built ); + return built; } @@ -3840,6 +3895,7 @@ static gentity_t *G_FinishSpawningBuildable( gentity_t *ent, qboolean force ) { G_Printf( S_COLOR_YELLOW "G_FinishSpawningBuildable: %s startsolid at %s\n", built->classname, vtos( built->s.origin ) ); + G_RemoveRangeMarkerFrom( built ); G_FreeEntity( built ); return NULL; } @@ -4309,6 +4365,7 @@ void G_BuildLogRevert( int id ) if( ent->s.eType == ET_BUILDABLE ) G_LogPrintf( "revert: remove %d %s\n", (int)( ent - g_entities ), BG_Buildable( ent->s.modelindex )->name ); + G_RemoveRangeMarkerFrom( ent ); G_FreeEntity( ent ); break; } @@ -4370,3 +4427,90 @@ void G_BuildLogRevert( int id ) } } +/* +================ +G_UpdateBuildableRangeMarkers +================ +*/ +void G_UpdateBuildableRangeMarkers( void ) +{ + // is the entity 64-bit client-masking extension available? + qboolean maskingExtension = ( trap_Cvar_VariableIntegerValue( "sv_gppExtension" ) >= 1 ); + + gentity_t *e; + for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e ) + { + buildable_t bType; + team_t bTeam; + int i; + + if( e->s.eType != ET_BUILDABLE || !e->rangeMarker ) + continue; + + bType = e->s.modelindex; + bTeam = BG_Buildable( bType )->team; + + e->rangeMarker->s.pos = e->s.pos; + if( bType == BA_A_HIVE || bType == BA_H_TESLAGEN ) + VectorMA( e->s.pos.trBase, e->r.maxs[ 2 ], e->s.origin2, e->rangeMarker->s.pos.trBase ); + else if( bType == BA_A_TRAPPER || bType == BA_H_MGTURRET ) + vectoangles( e->s.origin2, e->rangeMarker->s.apos.trBase ); + + e->rangeMarker->r.singleClient = 0; + e->rangeMarker->r.hack.generic1 = 0; + + // remove any previously added NOCLIENT flags from the hack below + e->rangeMarker->r.svFlags &= ~SVF_NOCLIENT; + + for( i = 0; i < level.maxclients; ++i ) + { + gclient_t *client; + team_t team; + qboolean weaponDisplays, wantsToSee; + + client = &level.clients[ i ]; + if( client->pers.connected != CON_CONNECTED ) + continue; + + if( i >= 32 && !maskingExtension ) + { + // resort to not sending range markers at all + if( !trap_Cvar_VariableIntegerValue( "g_rangeMarkerWarningGiven" ) ) + { + trap_SendServerCommand( -1, "print \"" S_COLOR_YELLOW "WARNING: There is no " + "support for entity 64-bit client-masking on this server. Please update " + "your server executable. Until then, range markers will not be displayed " + "while there are clients with client numbers above 31 in the game.\n\"" ); + trap_Cvar_Set( "g_rangeMarkerWarningGiven", "1" ); + } + + for( e = &g_entities[ MAX_CLIENTS ]; e < &g_entities[ level.num_entities ]; ++e ) + { + if( e->s.eType == ET_BUILDABLE && e->rangeMarker ) + e->rangeMarker->r.svFlags |= SVF_NOCLIENT; + } + + return; + } + + team = client->pers.teamSelection; + if( team != TEAM_NONE ) + { + weaponDisplays = ( BG_InventoryContainsWeapon( WP_HBUILD, client->ps.stats ) || + client->ps.weapon == WP_ABUILD || client->ps.weapon == WP_ABUILD2 ); + } + wantsToSee = !!( client->pers.buildableRangeMarkerMask & ( 1 << bType ) ); + + if( ( team == TEAM_NONE || ( team == bTeam && weaponDisplays ) ) && wantsToSee ) + { + if( i >= 32 ) + e->rangeMarker->r.hack.generic1 |= 1 << ( i - 32 ); + else + e->rangeMarker->r.singleClient |= 1 << i; + } + } + + trap_LinkEntity( e->rangeMarker ); + } +} + diff --git a/src/game/g_client.c b/src/game/g_client.c index 548ec963..61ff80a3 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -969,6 +969,9 @@ char *ClientUserinfoChanged( int clientNum, qboolean forceName ) else client->pers.disableBlueprintErrors = qfalse; + client->pers.buildableRangeMarkerMask = + atoi( Info_ValueForKey( userinfo, "cg_buildableRangeMarkerMask" ) ); + // teamInfo s = Info_ValueForKey( userinfo, "teamoverlay" ); diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index caa5f990..c6ac1b5b 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1979,6 +1979,7 @@ void Cmd_Destroy_f( gentity_t *ent ) } G_Damage( traceEnt, ent, ent, forward, tr.endpos, traceEnt->health, 0, MOD_DECONSTRUCT ); + G_RemoveRangeMarkerFrom( traceEnt ); G_FreeEntity( traceEnt ); } } diff --git a/src/game/g_local.h b/src/game/g_local.h index 081c47b8..45926560 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -190,6 +190,7 @@ struct gentity_s team_t buildableTeam; // buildable item team gentity_t *parentNode; // for creep and defence/spawn dependencies + gentity_t *rangeMarker; qboolean active; // for power repeater, but could be useful elsewhere qboolean locked; // used for turret tracking qboolean powered; // for human buildables @@ -303,6 +304,7 @@ typedef struct int teamInfo; // level.time of team overlay update (disabled = 0) float flySpeed; // for spectator/noclip moves qboolean disableBlueprintErrors; // should the buildable blueprint never be hidden from the players? + int buildableRangeMarkerMask; class_t classSelection; // player class (copied to ent->client->ps.stats[ STAT_CLASS ] once spawned) float evolveHealthFraction; @@ -806,6 +808,8 @@ buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate ); void G_BuildLogSet( buildLog_t *log, gentity_t *ent ); void G_BuildLogAuto( gentity_t *actor, gentity_t *buildable, buildFate_t fate ); void G_BuildLogRevert( int id ); +void G_RemoveRangeMarkerFrom( gentity_t *self ); +void G_UpdateBuildableRangeMarkers( void ); // // g_utils.c diff --git a/src/game/g_main.c b/src/game/g_main.c index b3d36bad..c8e0af41 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -597,6 +597,10 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) // we're done with g_mapConfigs, so reset this for the next map trap_Cvar_Set( "g_mapConfigsLoaded", "0" ); + // set this cvar to 0 if it exists, but otherwise avoid its creation + if( trap_Cvar_VariableIntegerValue( "g_rangeMarkerWarningGiven" ) ) + trap_Cvar_Set( "g_rangeMarkerWarningGiven", "0" ); + G_RegisterCommands( ); G_admin_readconfig( NULL ); G_LoadCensors( ); @@ -2397,6 +2401,7 @@ void G_RunFrame( int levelTime ) G_CalculateAvgPlayers( ); G_UpdateZaps( msec ); } + G_UpdateBuildableRangeMarkers( ); // see if it is time to end the level CheckExitRules( ); diff --git a/src/game/g_physics.c b/src/game/g_physics.c index 455d3a6e..9e5b23d5 100644 --- a/src/game/g_physics.c +++ b/src/game/g_physics.c @@ -153,6 +153,8 @@ void G_Physics( gentity_t *ent, int msec ) contents = trap_PointContents( ent->r.currentOrigin, -1 ); if( contents & CONTENTS_NODROP ) { + if( ent->s.eType == ET_BUILDABLE ) + G_RemoveRangeMarkerFrom( ent ); G_FreeEntity( ent ); return; } diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index ae67e291..262f8744 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -58,6 +58,9 @@ void Svcmd_EntityList_f( void ) case ET_BUILDABLE: G_Printf( "ET_BUILDABLE " ); break; + case ET_RANGE_MARKER: + G_Printf( "ET_RANGE_MARKER " ); + break; case ET_LOCATION: G_Printf( "ET_LOCATION " ); break; |