From 10121326fbf07b701038893ecdb19f672c29c11e Mon Sep 17 00:00:00 2001 From: /dev/humancontroller Date: Sun, 13 Jul 2014 18:12:01 +0200 Subject: implement the range marker functionality, use it to create buildable range markers use the entity 64-bit client-masking extension when available --- src/game/g_buildable.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) (limited to 'src/game/g_buildable.c') 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 ); } @@ -3489,6 +3493,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 @@ -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 ); + } +} + -- cgit