/*
===========================================================================
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();
}