/* =========================================================================== Wolfenstein: Enemy Territory GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Wolfenstein: Enemy Territory GPL Source Code (“Wolf ET Source Code”). Wolf ET Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Wolf ET Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wolf ET Source Code. If not, see . In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "g_local.h" /* =================== G_PushMapEntityToBuffer =================== */ void G_PushMapEntityToBuffer( char* buffer, int size, mapEntityData_t *mEnt ) { char buf[32]; if ( level.ccLayers ) { Com_sprintf( buf, sizeof( buf ), "%i %i %i", ( (int)mEnt->org[0] ) / 128, ( (int)mEnt->org[1] ) / 128, ( (int)mEnt->org[2] ) / 128 ); } else { Com_sprintf( buf, sizeof( buf ), "%i %i", ( (int)mEnt->org[0] ) / 128, ( (int)mEnt->org[1] ) / 128 ); } switch ( mEnt->type ) { case ME_CONSTRUCT: // Gordon: these ones don't need much info case ME_DESTRUCT: case ME_DESTRUCT_2: case ME_COMMANDMAP_MARKER: Q_strcat( buffer, size, va( " %i %i", mEnt->type, mEnt->data ) ); break; case ME_TANK: case ME_TANK_DEAD: Q_strcat( buffer, size, va( " %i %s %i", mEnt->type, buf, mEnt->data ) ); break; default: Q_strcat( buffer, size, va( " %i %s %i %i", mEnt->type, buf, mEnt->yaw, mEnt->data ) ); break; } } /* =================== G_InitMapEntityData =================== */ void G_InitMapEntityData( mapEntityData_Team_t *teamList ) { int i; mapEntityData_t *trav, *lasttrav; memset( teamList, 0, sizeof( mapEntityData_Team_t ) ); teamList->activeMapEntityData.next = &teamList->activeMapEntityData; teamList->activeMapEntityData.prev = &teamList->activeMapEntityData; teamList->freeMapEntityData = teamList->mapEntityData_Team; for ( i = 0, trav = teamList->mapEntityData_Team + 1, lasttrav = teamList->mapEntityData_Team ; i < MAX_GENTITIES - 1 ; i++, trav++ ) { lasttrav->next = trav; lasttrav = trav; } } /* ================== G_FreeMapEntityData returns next entity in the array ================== */ mapEntityData_t *G_FreeMapEntityData( mapEntityData_Team_t *teamList, mapEntityData_t *mEnt ) { mapEntityData_t *ret = mEnt->next; if ( !mEnt->prev ) { G_Error( "G_FreeMapEntityData: not active" ); } // remove from the doubly linked active list mEnt->prev->next = mEnt->next; mEnt->next->prev = mEnt->prev; // the free list is only singly linked mEnt->next = teamList->freeMapEntityData; teamList->freeMapEntityData = mEnt; return( ret ); } /* =================== G_AllocMapEntityData =================== */ mapEntityData_t *G_AllocMapEntityData( mapEntityData_Team_t *teamList ) { mapEntityData_t *mEnt; if ( !teamList->freeMapEntityData ) { // no free entities - bomb out G_Error( "G_AllocMapEntityData: out of entities" ); } mEnt = teamList->freeMapEntityData; teamList->freeMapEntityData = teamList->freeMapEntityData->next; memset( mEnt, 0, sizeof( *mEnt ) ); mEnt->singleClient = -1; // link into the active list mEnt->next = teamList->activeMapEntityData.next; mEnt->prev = &teamList->activeMapEntityData; teamList->activeMapEntityData.next->prev = mEnt; teamList->activeMapEntityData.next = mEnt; return mEnt; } /* =================== G_FindMapEntityData =================== */ mapEntityData_t *G_FindMapEntityData( mapEntityData_Team_t *teamList, int entNum ) { mapEntityData_t *mEnt; for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->singleClient >= 0 ) { continue; } if ( entNum == mEnt->entNum ) { return( mEnt ); } } // not found return( NULL ); } /* =============================== G_FindMapEntityDataSingleClient =============================== */ mapEntityData_t *G_FindMapEntityDataSingleClient( mapEntityData_Team_t *teamList, mapEntityData_t *start, int entNum, int clientNum ) { mapEntityData_t *mEnt; if ( start ) { mEnt = start->next; } else { mEnt = teamList->activeMapEntityData.next; } for ( ; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( clientNum == -1 ) { if ( mEnt->singleClient < 0 ) { continue; } } else if ( mEnt->singleClient >= 0 && clientNum != mEnt->singleClient ) { continue; } if ( entNum == mEnt->entNum ) { return( mEnt ); } } // not found return( NULL ); } //////////////////////////////////////////////////////////////////// // some culling bits typedef struct plane_s { vec3_t normal; float dist; } plane_t; static plane_t frustum[4]; /* ======================== G_SetupFrustum ======================== */ void G_SetupFrustum( gentity_t* ent ) { int i; float xs, xc; float ang; vec3_t axis[3]; vec3_t vieworg; ang = ( 90 / 180.f ) * M_PI * 0.5f; xs = sin( ang ); xc = cos( ang ); AnglesToAxis( ent->client->ps.viewangles, axis ); VectorScale( axis[0], xs, frustum[0].normal ); VectorMA( frustum[0].normal, xc, axis[1], frustum[0].normal ); VectorScale( axis[0], xs, frustum[1].normal ); VectorMA( frustum[1].normal, -xc, axis[1], frustum[1].normal ); ang = ( 90 / 180.f ) * M_PI * 0.5f; xs = sin( ang ); xc = cos( ang ); VectorScale( axis[0], xs, frustum[2].normal ); VectorMA( frustum[2].normal, xc, axis[2], frustum[2].normal ); VectorScale( axis[0], xs, frustum[3].normal ); VectorMA( frustum[3].normal, -xc, axis[2], frustum[3].normal ); VectorCopy( ent->client->ps.origin, vieworg ); vieworg[2] += ent->client->ps.viewheight; for ( i = 0 ; i < 4 ; i++ ) { frustum[i].dist = DotProduct( vieworg, frustum[i].normal ); } } void G_SetupFrustum_ForBinoculars( gentity_t* ent ) { // TAT 12/26/2002 - Give bots a larger view angle through binoculars than players get - this should help the // landmine detection... #define BINOCULAR_ANGLE 10.0f #define BOT_BINOCULAR_ANGLE 60.0f int i; float xs, xc; float ang; vec3_t axis[3]; vec3_t vieworg; float baseAngle; if ( ent->r.svFlags & SVF_BOT ) { baseAngle = BOT_BINOCULAR_ANGLE; } else { baseAngle = BINOCULAR_ANGLE; } ang = ( baseAngle / 180.f ) * M_PI * 0.5f; xs = sin( ang ); xc = cos( ang ); AnglesToAxis( ent->client->ps.viewangles, axis ); VectorScale( axis[0], xs, frustum[0].normal ); VectorMA( frustum[0].normal, xc, axis[1], frustum[0].normal ); VectorScale( axis[0], xs, frustum[1].normal ); VectorMA( frustum[1].normal, -xc, axis[1], frustum[1].normal ); ang = ( baseAngle / 180.f ) * M_PI * 0.5f; xs = sin( ang ); xc = cos( ang ); VectorScale( axis[0], xs, frustum[2].normal ); VectorMA( frustum[2].normal, xc, axis[2], frustum[2].normal ); VectorScale( axis[0], xs, frustum[3].normal ); VectorMA( frustum[3].normal, -xc, axis[2], frustum[3].normal ); VectorCopy( ent->client->ps.origin, vieworg ); vieworg[2] += ent->client->ps.viewheight; for ( i = 0 ; i < 4 ; i++ ) { frustum[i].dist = DotProduct( vieworg, frustum[i].normal ); } } /* ======================== G_CullPointAndRadius - returns true if not culled ======================== */ static qboolean G_CullPointAndRadius( vec3_t pt, float radius ) { int i; float dist; plane_t *frust; // check against frustum planes for ( i = 0 ; i < 4 ; i++ ) { frust = &frustum[i]; dist = DotProduct( pt, frust->normal ) - frust->dist; if ( dist < -radius || dist <= radius ) { return( qfalse ); } } return( qtrue ); } qboolean G_VisibleFromBinoculars( gentity_t* viewer, gentity_t* ent, vec3_t origin ) { vec3_t vieworg; trace_t trace; VectorCopy( viewer->client->ps.origin, vieworg ); vieworg[2] += viewer->client->ps.viewheight; if ( !G_CullPointAndRadius( origin, 0 ) ) { return qfalse; } if ( !trap_InPVS( vieworg, origin ) ) { return qfalse; } trap_Trace( &trace, vieworg, NULL, NULL, origin, viewer->s.number, MASK_SHOT ); /* if( ent && trace.entityNum != ent-g_entities ) { return qfalse; }*/ if ( trace.fraction != 1.f ) { if ( ent ) { if ( trace.entityNum != ent->s.number ) { return qfalse; } else { return qtrue; } } else { return qfalse; } } return qtrue; } void G_ResetTeamMapData() { G_InitMapEntityData( &mapEntityData[0] ); G_InitMapEntityData( &mapEntityData[1] ); } void G_UpdateTeamMapData_Construct( gentity_t* ent ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; if ( ent->s.teamNum == 3 ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->type = ME_CONSTRUCT; mEnt->startTime = level.time; mEnt->yaw = 0; teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->type = ME_CONSTRUCT; mEnt->startTime = level.time; mEnt->yaw = 0; return; } if ( ent->s.teamNum == TEAM_AXIS ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->type = ME_CONSTRUCT; mEnt->startTime = level.time; mEnt->yaw = 0; } else { } if ( ent->s.teamNum == TEAM_ALLIES ) { teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->type = ME_CONSTRUCT; mEnt->startTime = level.time; mEnt->yaw = 0; } else { } } void G_UpdateTeamMapData_Tank( gentity_t* ent ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = ent->s.modelindex2; mEnt->startTime = level.time; if ( ent->s.eType == ET_TANK_INDICATOR_DEAD ) { mEnt->type = ME_TANK_DEAD; } else { mEnt->type = ME_TANK; } mEnt->yaw = 0; teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = ent->s.modelindex2; mEnt->startTime = level.time; if ( ent->s.eType == ET_TANK_INDICATOR_DEAD ) { mEnt->type = ME_TANK_DEAD; } else { mEnt->type = ME_TANK; } mEnt->yaw = 0; } void G_UpdateTeamMapData_Destruct( gentity_t* ent ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; if ( ent->s.teamNum == TEAM_AXIS ) { teamList = &mapEntityData[1]; // inverted mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->startTime = level.time; mEnt->type = ME_DESTRUCT; mEnt->yaw = 0; } else { if ( ent->parent->target_ent && ( ent->parent->target_ent->s.eType == ET_CONSTRUCTIBLE || ent->parent->target_ent->s.eType == ET_EXPLOSIVE ) ) { if ( ent->parent->spawnflags & ( ( 1 << 6 ) | ( 1 << 4 ) ) ) { teamList = &mapEntityData[1]; // inverted mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->startTime = level.time; mEnt->type = ME_DESTRUCT_2; mEnt->yaw = 0; } } } if ( ent->s.teamNum == TEAM_ALLIES ) { teamList = &mapEntityData[0]; // inverted mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->startTime = level.time; mEnt->type = ME_DESTRUCT; mEnt->yaw = 0; } else { if ( ent->parent->target_ent && ( ent->parent->target_ent->s.eType == ET_CONSTRUCTIBLE || ent->parent->target_ent->s.eType == ET_EXPLOSIVE ) ) { if ( ent->parent->spawnflags & ( ( 1 << 6 ) | ( 1 << 4 ) ) ) { teamList = &mapEntityData[0]; // inverted mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.pos.trBase, mEnt->org ); mEnt->data = mEnt->entNum; //ent->s.modelindex2; mEnt->startTime = level.time; mEnt->type = ME_DESTRUCT_2; mEnt->yaw = 0; } } } } void G_UpdateTeamMapData_Player( gentity_t* ent, qboolean forceAllied, qboolean forceAxis ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; if ( ent->client ) { switch ( ent->client->sess.sessionTeam ) { case TEAM_AXIS: forceAxis = qtrue; break; case TEAM_ALLIES: forceAllied = qtrue; break; default: break; } } if ( forceAxis && ent->client && !( ent->client->ps.pm_flags & PMF_LIMBO ) /*ent->health > 0*/ ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->client->ps.origin, mEnt->org ); mEnt->yaw = ent->client->ps.viewangles[YAW]; mEnt->data = num; mEnt->startTime = level.time; if ( ent->health <= 0 ) { mEnt->type = ME_PLAYER_REVIVE; } else { mEnt->type = ME_PLAYER; } } if ( forceAllied && ent->client && !( ent->client->ps.pm_flags & PMF_LIMBO ) /*ent->health > 0*/ ) { teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->client->ps.origin, mEnt->org ); mEnt->yaw = ent->client->ps.viewangles[YAW]; mEnt->data = num; mEnt->startTime = level.time; if ( ent->health <= 0 ) { mEnt->type = ME_PLAYER_REVIVE; } else { mEnt->type = ME_PLAYER; } } } static void G_UpdateTeamMapData_DisguisedPlayer( gentity_t* spotter, gentity_t* ent, qboolean forceAllied, qboolean forceAxis ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; if ( ent->client ) { switch ( ent->client->sess.sessionTeam ) { case TEAM_AXIS: forceAxis = qtrue; break; case TEAM_ALLIES: forceAllied = qtrue; break; default: break; } } if ( ent->client && !( ent->client->ps.pm_flags & PMF_LIMBO ) ) { if ( forceAxis ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, num, spotter->s.clientNum ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; mEnt->singleClient = spotter->s.clientNum; } VectorCopy( ent->client->ps.origin, mEnt->org ); mEnt->yaw = ent->client->ps.viewangles[YAW]; mEnt->data = num; mEnt->startTime = level.time; mEnt->type = ME_PLAYER_DISGUISED; } if ( forceAllied ) { teamList = &mapEntityData[1]; mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, num, spotter->s.clientNum ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; mEnt->singleClient = spotter->s.clientNum; } VectorCopy( ent->client->ps.origin, mEnt->org ); mEnt->yaw = ent->client->ps.viewangles[YAW]; mEnt->data = num; mEnt->startTime = level.time; mEnt->type = ME_PLAYER_DISGUISED; } } } void G_UpdateTeamMapData_LandMine( gentity_t* ent, qboolean forceAllied, qboolean forceAxis ) { //void G_UpdateTeamMapData_LandMine(gentity_t* ent) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; // inversed teamlists, we want to see the enemy mines switch ( ent->s.teamNum % 4 ) { case TEAM_AXIS: forceAxis = qtrue; break; case TEAM_ALLIES: forceAllied = qtrue; break; } if ( forceAxis && ( ent->s.teamNum < 4 || ent->s.teamNum >= 8 ) ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->r.currentOrigin, mEnt->org ); //mEnt->data = TEAM_AXIS; mEnt->data = ( ent->s.teamNum % 4 ); mEnt->startTime = level.time; //if( ent->s.teamNum < 4 ) mEnt->type = ME_LANDMINE; //else if( ent->s.teamNum >= 8 ) // mEnt->type = ME_LANDMINE_ARMED; } if ( forceAllied && ( ent->s.teamNum < 4 || ent->s.teamNum >= 8 ) ) { teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->r.currentOrigin, mEnt->org ); //mEnt->data = TEAM_ALLIES; mEnt->data = ( ent->s.teamNum % 4 ); mEnt->startTime = level.time; //if( ent->s.teamNum < 4 ) mEnt->type = ME_LANDMINE; //else if( ent->s.teamNum >= 8 ) // mEnt->type = ME_LANDMINE_ARMED; } } void G_UpdateTeamMapData_CommandmapMarker( gentity_t* ent ) { int num = ent - g_entities; mapEntityData_Team_t* teamList; mapEntityData_t *mEnt; if ( !ent->parent ) { return; } if ( ent->entstate != STATE_DEFAULT ) { return; } if ( ent->parent->spawnflags & ALLIED_OBJECTIVE ) { teamList = &mapEntityData[0]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.origin, mEnt->org ); mEnt->data = ent->parent->s.teamNum; mEnt->startTime = level.time; mEnt->type = ME_COMMANDMAP_MARKER; mEnt->yaw = 0; } if ( ent->parent->spawnflags & AXIS_OBJECTIVE ) { teamList = &mapEntityData[1]; mEnt = G_FindMapEntityData( teamList, num ); if ( !mEnt ) { mEnt = G_AllocMapEntityData( teamList ); mEnt->entNum = num; } VectorCopy( ent->s.origin, mEnt->org ); mEnt->data = ent->parent ? ent->parent->s.teamNum : -1; mEnt->startTime = level.time; mEnt->type = ME_COMMANDMAP_MARKER; mEnt->yaw = 0; } } void G_SendSpectatorMapEntityInfo( gentity_t* e ) { // special version, sends different set of ents - only the objectives, but also team info (string is split in two basically) mapEntityData_t *mEnt; mapEntityData_Team_t *teamList; char buffer[2048]; int al_cnt, ax_cnt; // Axis data init teamList = &mapEntityData[0]; ax_cnt = 0; for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->type != ME_CONSTRUCT && mEnt->type != ME_DESTRUCT && mEnt->type != ME_TANK && mEnt->type != ME_TANK_DEAD ) { continue; } if ( mEnt->singleClient >= 0 && e->s.clientNum != mEnt->singleClient ) { continue; } ax_cnt++; } // Allied data init teamList = &mapEntityData[1]; al_cnt = 0; for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->type != ME_CONSTRUCT && mEnt->type != ME_DESTRUCT && mEnt->type != ME_TANK && mEnt->type != ME_TANK_DEAD ) { continue; } if ( mEnt->singleClient >= 0 && e->s.clientNum != mEnt->singleClient ) { continue; } al_cnt++; } // Data setup Com_sprintf( buffer, sizeof( buffer ), "entnfo %i %i", ax_cnt, al_cnt ); // Axis data teamList = &mapEntityData[0]; for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->type != ME_CONSTRUCT && mEnt->type != ME_DESTRUCT && mEnt->type != ME_TANK && mEnt->type != ME_TANK_DEAD && mEnt->type != ME_DESTRUCT_2 ) { continue; } if ( mEnt->singleClient >= 0 && e->s.clientNum != mEnt->singleClient ) { continue; } G_PushMapEntityToBuffer( buffer, sizeof( buffer ), mEnt ); } // Allied data teamList = &mapEntityData[1]; for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->type != ME_CONSTRUCT && mEnt->type != ME_DESTRUCT && mEnt->type != ME_TANK && mEnt->type != ME_TANK_DEAD && mEnt->type != ME_DESTRUCT_2 ) { continue; } if ( mEnt->singleClient >= 0 && e->s.clientNum != mEnt->singleClient ) { continue; } G_PushMapEntityToBuffer( buffer, sizeof( buffer ), mEnt ); } trap_SendServerCommand( e - g_entities, buffer ); } void G_SendMapEntityInfo( gentity_t* e ) { mapEntityData_t *mEnt; mapEntityData_Team_t *teamList; char buffer[2048]; int cnt = 0; if ( e->client->sess.sessionTeam == TEAM_SPECTATOR ) { G_SendSpectatorMapEntityInfo( e ); return; } // something really went wrong if this evaluates to true if ( e->client->sess.sessionTeam != TEAM_AXIS && e->client->sess.sessionTeam != TEAM_ALLIES ) { return; } teamList = e->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1]; mEnt = teamList->activeMapEntityData.next; while ( mEnt && mEnt != &teamList->activeMapEntityData ) { if ( level.time - mEnt->startTime > 5000 ) { mEnt->status = 1; // we can free this player from the list now if ( mEnt->type == ME_PLAYER ) { mEnt = G_FreeMapEntityData( teamList, mEnt ); continue; } else if ( mEnt->type == ME_PLAYER_DISGUISED ) { if ( mEnt->singleClient == e->s.clientNum ) { mEnt = G_FreeMapEntityData( teamList, mEnt ); continue; } } } else { mEnt->status = 2; } cnt++; mEnt = mEnt->next; } if ( e->client->sess.sessionTeam == TEAM_AXIS ) { Com_sprintf( buffer, sizeof( buffer ), "entnfo %i 0", cnt ); } else { Com_sprintf( buffer, sizeof( buffer ), "entnfo 0 %i", cnt ); } for ( mEnt = teamList->activeMapEntityData.next; mEnt && mEnt != &teamList->activeMapEntityData; mEnt = mEnt->next ) { if ( mEnt->singleClient >= 0 && e->s.clientNum != mEnt->singleClient ) { continue; } G_PushMapEntityToBuffer( buffer, sizeof( buffer ), mEnt ); } trap_SendServerCommand( e - g_entities, buffer ); } void G_UpdateTeamMapData( void ) { int i, j /*, k*/; gentity_t *ent, *ent2; mapEntityData_t *mEnt; if ( level.time - level.lastMapEntityUpdate < 500 ) { return; } level.lastMapEntityUpdate = level.time; for ( i = 0, ent = g_entities; i < level.num_entities; i++, ent++ ) { if ( !ent->inuse ) { // mapEntityData[0][i].valid = qfalse; // mapEntityData[1][i].valid = qfalse; continue; } switch ( ent->s.eType ) { case ET_PLAYER: G_UpdateTeamMapData_Player( ent, qfalse, qfalse ); for ( j = 0; j < 2; j++ ) { mapEntityData_Team_t *teamList = &mapEntityData[j]; mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, ent->s.number, -1 ); while ( mEnt ) { VectorCopy( ent->client->ps.origin, mEnt->org ); mEnt->yaw = ent->client->ps.viewangles[YAW]; mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, ent->s.number, -1 ); } } break; case ET_CONSTRUCTIBLE_INDICATOR: if ( ent->parent && ent->parent->entstate == STATE_DEFAULT ) { G_UpdateTeamMapData_Construct( ent ); } break; case ET_EXPLOSIVE_INDICATOR: if ( ent->parent && ent->parent->entstate == STATE_DEFAULT ) { G_UpdateTeamMapData_Destruct( ent ); } break; case ET_TANK_INDICATOR: case ET_TANK_INDICATOR_DEAD: G_UpdateTeamMapData_Tank( ent ); break; case ET_MISSILE: if ( ent->methodOfDeath == MOD_LANDMINE ) { G_UpdateTeamMapData_LandMine( ent, qfalse, qfalse ); } break; case ET_COMMANDMAP_MARKER: G_UpdateTeamMapData_CommandmapMarker( ent ); break; default: break; } } //for(i = 0, ent = g_entities; i < MAX_CLIENTS; i++, ent++) { for ( i = 0, ent = g_entities; i < level.num_entities; i++, ent++ ) { qboolean f1, f2; if ( !ent->inuse || !ent->client ) { continue; } if ( ent->client->sess.playerType == PC_FIELDOPS ) { if ( ent->client->sess.skill[SK_SIGNALS] >= 4 && ent->health > 0 ) { vec3_t pos[3]; f1 = ent->client->sess.sessionTeam == TEAM_ALLIES ? qtrue : qfalse; f2 = ent->client->sess.sessionTeam == TEAM_AXIS ? qtrue : qfalse; G_SetupFrustum( ent ); for ( j = 0, ent2 = g_entities; j < level.maxclients; j++, ent2++ ) { if ( !ent2->inuse || ent2 == ent ) { continue; } //if( ent2->s.eType != ET_PLAYER ) { // continue; //} if ( ent2->client->sess.sessionTeam == TEAM_SPECTATOR ) { continue; } if ( ent2->health <= 0 || ent2->client->sess.sessionTeam == ent->client->sess.sessionTeam || !ent2->client->ps.powerups[PW_OPS_DISGUISED] ) { continue; } VectorCopy( ent2->client->ps.origin, pos[0] ); pos[0][2] += ent2->client->ps.mins[2]; VectorCopy( ent2->client->ps.origin, pos[1] ); VectorCopy( ent2->client->ps.origin, pos[2] ); pos[2][2] += ent2->client->ps.maxs[2]; if ( G_VisibleFromBinoculars( ent, ent2, pos[0] ) || G_VisibleFromBinoculars( ent, ent2, pos[1] ) || G_VisibleFromBinoculars( ent, ent2, pos[2] ) ) { G_UpdateTeamMapData_DisguisedPlayer( ent, ent2, f1, f2 ); } } } } else if ( ent->client->sess.playerType == PC_COVERTOPS ) { if ( ent->health > 0 ) { f1 = ent->client->sess.sessionTeam == TEAM_ALLIES ? qtrue : qfalse; f2 = ent->client->sess.sessionTeam == TEAM_AXIS ? qtrue : qfalse; G_SetupFrustum( ent ); for ( j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++ ) { if ( !ent2->inuse || ent2 == ent ) { continue; } switch ( ent2->s.eType ) { case ET_PLAYER: { vec3_t pos[3]; VectorCopy( ent2->client->ps.origin, pos[0] ); pos[0][2] += ent2->client->ps.mins[2]; VectorCopy( ent2->client->ps.origin, pos[1] ); VectorCopy( ent2->client->ps.origin, pos[2] ); pos[2][2] += ent2->client->ps.maxs[2]; if ( ent2->health > 0 && ( G_VisibleFromBinoculars( ent, ent2, pos[0] ) || G_VisibleFromBinoculars( ent, ent2, pos[1] ) || G_VisibleFromBinoculars( ent, ent2, pos[2] ) ) ) { if ( ent2->client->sess.sessionTeam != ent->client->sess.sessionTeam ) { int k; switch ( ent2->client->sess.sessionTeam ) { case TEAM_AXIS: mEnt = G_FindMapEntityData( &mapEntityData[0], ent2 - g_entities ); if ( mEnt && level.time - mEnt->startTime > 5000 ) { for ( k = 0; k < MAX_CLIENTS; k++ ) { if ( g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam ) { trap_SendServerCommand( k, va( "tt \"ENEMY SPOTTED CHECK COMMAND MAP FOR DETAILS \"\n" ) ); } } } break; case TEAM_ALLIES: mEnt = G_FindMapEntityData( &mapEntityData[1], ent2 - g_entities ); if ( mEnt && level.time - mEnt->startTime > 5000 ) { for ( k = 0; k < MAX_CLIENTS; k++ ) { if ( g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam ) { trap_SendServerCommand( k, va( "tt \"ENEMY SPOTTED CHECK COMMAND MAP FOR DETAILS \"\n" ) ); } } } break; default: break; } } G_UpdateTeamMapData_Player( ent2, f1, f2 ); } break; } default: break; } } if ( ent->client->ps.eFlags & EF_ZOOMING ) { G_SetupFrustum_ForBinoculars( ent ); for ( j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++ ) { if ( !ent2->inuse || ent2 == ent ) { continue; } switch ( ent2->s.eType ) { case ET_MISSILE: if ( ent2->methodOfDeath == MOD_LANDMINE ) { if ( ( ent2->s.teamNum < 4 || ent2->s.teamNum >= 8 ) && ( ent2->s.teamNum % 4 != ent->client->sess.sessionTeam ) ) { // TAT - as before, we can only detect a mine if we can see it from our binoculars if ( G_VisibleFromBinoculars( ent, ent2, ent2->r.currentOrigin ) ) { G_UpdateTeamMapData_LandMine( ent2, f1, f2 ); switch ( ent2->s.teamNum % 4 ) { case TEAM_AXIS: if ( !ent2->s.modelindex2 ) { ent->client->landmineSpottedTime = level.time; ent->client->landmineSpotted = ent2; ent2->s.density = ent - g_entities + 1; ent2->missionLevel = level.time; ent->client->landmineSpotted->count2 += 50; if ( ent->client->landmineSpotted->count2 >= 250 ) { // int k; ent->client->landmineSpotted->count2 = 250; ent->client->landmineSpotted->s.modelindex2 = 1; // for marker ent->client->landmineSpotted->s.frame = rand() % 20; ent->client->landmineSpotted->r.contents = CONTENTS_CORPSE; trap_LinkEntity( ent->client->landmineSpotted ); { gentity_t* pm = G_PopupMessage( PM_MINES ); VectorCopy( ent->client->landmineSpotted->r.currentOrigin, pm->s.origin ); pm->s.effect2Time = TEAM_AXIS; pm->s.effect3Time = ent - g_entities; } /* for( k = 0; k < MAX_CLIENTS; k++ ) { if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) { trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED BY %s^0 CHECK COMMAND MAP FOR DETAILS \"\n", ent->client->pers.netname)); } }*/ trap_SendServerCommand( ent - g_entities, "cp \"Landmine Revealed\n\"" ); AddScore( ent, 1 ); //G_AddExperience( ent, 1.f ); G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f ); G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" ); } } break; case TEAM_ALLIES: if ( !ent2->s.modelindex2 ) { ent->client->landmineSpottedTime = level.time; ent->client->landmineSpotted = ent2; ent2->s.density = ent - g_entities + 1; ent2->missionLevel = level.time; ent->client->landmineSpotted->count2 += 50; if ( ent->client->landmineSpotted->count2 >= 250 ) { // int k; ent->client->landmineSpotted->count2 = 250; ent->client->landmineSpotted->s.modelindex2 = 1; // for marker ent->client->landmineSpotted->s.frame = rand() % 20; ent->client->landmineSpotted->r.contents = CONTENTS_CORPSE; trap_LinkEntity( ent->client->landmineSpotted ); { gentity_t* pm = G_PopupMessage( PM_MINES ); VectorCopy( ent->client->landmineSpotted->r.currentOrigin, pm->s.origin ); pm->s.effect2Time = TEAM_ALLIES; pm->s.effect3Time = ent - g_entities; } /* for( k = 0; k < MAX_CLIENTS; k++ ) { if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) { trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED BY %s^0 CHECK COMMAND MAP FOR DETAILS \"\n", ent->client->pers.netname)); } }*/ trap_SendServerCommand( ent - g_entities, "cp \"Landmine Revealed\n\"" ); AddScore( ent, 1 ); //G_AddExperience( ent, 1.f ); G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f ); G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" ); } } break; } // end switch } // end (G_VisibleFromBinoculars( ent, ent2, ent2->r.currentOrigin )) else { // TAT - if we can't see the mine from our binoculars, make sure we clear out the landmineSpotted ptr, // because bots looking for mines are getting confused ent->client->landmineSpotted = NULL; } } } break; default: break; } } /* if(ent->client->landmineSpotted && !ent->client->landmineSpotted->s.modelindex2) { ent->client->landmineSpotted->count2 += 10; if(ent->client->landmineSpotted->count2 >= 250) { int k; ent->client->landmineSpotted->count2 = 250; ent->client->landmineSpotted->s.modelindex2 = 1; // for marker ent->client->landmineSpotted->s.frame = rand() % 20; for( k = 0; k < MAX_CLIENTS; k++ ) { if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) { trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED CHECK COMMAND MAP FOR DETAILS \"\n" )); } } trap_SendServerCommand( ent-g_entities, "cp \"Landmine Revealed\n\"" ); AddScore( ent, 1 ); //G_AddExperience( ent, 1.f ); G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f ); G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" ); } }*/ /* { // find any landmines that don't actually exist anymore, see if the covert ops can see the spot and if so - wipe them mapEntityData_Team_t *teamList = ent->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1]; mEnt = teamList->activeMapEntityData.next; while( mEnt && mEnt != &teamList->activeMapEntityData ) { if( mEnt->type == ME_LANDMINE && mEnt->entNum == -1 ) { if( G_VisibleFromBinoculars( ent, NULL, mEnt->org ) ) { mEnt = G_FreeMapEntityData( teamList, mEnt ); trap_SendServerCommand( ent-g_entities, "print \"Old Landmine Cleared\n\"" ); AddScore( ent, 1 ); continue; } } mEnt = mEnt->next; } }*/ } } } } // G_SendAllMapEntityInfo(); }