/* =========================================================================== 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. =========================================================================== */ /****************************************************************************** ***** teh firetams! (sic) ****/ #include "cg_local.h" /****************************************************************************** ***** Defines, constants, etc ****/ static int sortedFireTeamClients[MAX_CLIENTS]; /****************************************************************************** ***** Support Routines ****/ int QDECL CG_SortFireTeam( const void *a, const void *b ) { clientInfo_t *ca, *cb; int cna, cnb; cna = *(int*)a; cnb = *(int*)b; ca = &cgs.clientinfo[cna]; cb = &cgs.clientinfo[cnb]; // Not on our team, so shove back if ( !CG_IsOnSameFireteam( cnb, cg.clientNum ) ) { return -1; } if ( !CG_IsOnSameFireteam( cna, cg.clientNum ) ) { return 1; } // Leader comes first if ( CG_IsFireTeamLeader( cna ) ) { return -1; } if ( CG_IsFireTeamLeader( cnb ) ) { return 1; } // Then higher ranks if ( ca->rank > cb->rank ) { return -1; } if ( cb->rank > ca->rank ) { return 1; } // Then score /* if ( ca->score > cb->score ) { return -1; } if ( cb->score > ca->score ) { return 1; }*/ // not atm return 0; } // Sorts client's fireteam by leader then rank void CG_SortClientFireteam() { int i; for ( i = 0; i < MAX_CLIENTS; i++ ) { sortedFireTeamClients[i] = i; } qsort( sortedFireTeamClients, MAX_CLIENTS, sizeof( sortedFireTeamClients[0] ), CG_SortFireTeam ); /* for(i = 0; i < MAX_CLIENTS; i++) { CG_Printf( "%i ", sortedFireTeamClients[i] ); } CG_Printf( "\n" );*/ } // Parses fireteam servercommand void CG_ParseFireteams() { int i, j; char* s; const char* p; int clnts[2]; qboolean onFireteam2; qboolean isLeader2; // qboolean onFireteam = CG_IsOnFireteam( cg.clientNum ) ? qtrue : qfalse; // qboolean isLeader = CG_IsFireTeamLeader( cg.clientNum ) ? qtrue : qfalse; for ( i = 0; i < MAX_CLIENTS; i++ ) { cgs.clientinfo[i].fireteamData = NULL; } for ( i = 0; i < MAX_FIRETEAMS; i++ ) { char hexbuffer[11] = "0x00000000"; p = CG_ConfigString( CS_FIRETEAMS + i ); /* s = Info_ValueForKey(p, "n"); if(!s || !*s) { cg.fireTeams[i].inuse = qfalse; continue; } else { cg.fireTeams[i].inuse = qtrue; }*/ // Q_strncpyz(cg.fireTeams[i].name, s, 32); // CG_Printf("Fireteam: %s\n", cg.fireTeams[i].name); j = atoi( Info_ValueForKey( p, "id" ) ); if ( j == -1 ) { cg.fireTeams[i].inuse = qfalse; continue; } else { cg.fireTeams[i].inuse = qtrue; cg.fireTeams[i].ident = j; } s = Info_ValueForKey( p, "l" ); cg.fireTeams[i].leader = atoi( s ); s = Info_ValueForKey( p, "c" ); Q_strncpyz( hexbuffer + 2, s, 9 ); sscanf( hexbuffer, "%x", &clnts[1] ); Q_strncpyz( hexbuffer + 2, s + 8, 9 ); sscanf( hexbuffer, "%x", &clnts[0] ); for ( j = 0; j < MAX_CLIENTS; j++ ) { if ( COM_BitCheck( clnts, j ) ) { cg.fireTeams[i].joinOrder[j] = qtrue; cgs.clientinfo[j].fireteamData = &cg.fireTeams[i]; // CG_Printf("%s\n", cgs.clientinfo[j].name); } else { cg.fireTeams[i].joinOrder[j] = qfalse; } } } CG_SortClientFireteam(); onFireteam2 = CG_IsOnFireteam( cg.clientNum ) ? qtrue : qfalse; isLeader2 = CG_IsFireTeamLeader( cg.clientNum ) ? qtrue : qfalse; } // Fireteam that both specified clients are on, if they both are on the same team fireteamData_t* CG_IsOnSameFireteam( int clientNum, int clientNum2 ) { if ( CG_IsOnFireteam( clientNum ) == CG_IsOnFireteam( clientNum2 ) ) { return CG_IsOnFireteam( clientNum ); } return NULL; } // Fireteam that specified client is leader of, or NULL if none fireteamData_t* CG_IsFireTeamLeader( int clientNum ) { fireteamData_t* f; if ( !( f = CG_IsOnFireteam( clientNum ) ) ) { return NULL; } if ( f->leader != clientNum ) { return NULL; } return f ; } // Client, not on a fireteam, not sorted, but on your team clientInfo_t* CG_ClientInfoForPosition( int pos, int max ) { int i, cnt = 0; for ( i = 0; i < MAX_CLIENTS && cnt < max; i++ ) { if ( cg.clientNum != i && cgs.clientinfo[i].infoValid && !CG_IsOnFireteam( i ) && cgs.clientinfo[cg.clientNum].team == cgs.clientinfo[i].team ) { if ( cnt == pos ) { return &cgs.clientinfo[i]; } cnt++; } } return NULL; } // Fireteam, that's on your same team fireteamData_t* CG_FireTeamForPosition( int pos, int max ) { int i, cnt = 0; for ( i = 0; i < MAX_FIRETEAMS && cnt < max; i++ ) { if ( cg.fireTeams[i].inuse && cgs.clientinfo[cg.fireTeams[i].leader].team == cgs.clientinfo[cg.clientNum].team ) { if ( cnt == pos ) { return &cg.fireTeams[i]; } cnt++; } } return NULL; } // Client, not sorted by rank, on CLIENT'S fireteam clientInfo_t* CG_FireTeamPlayerForPosition( int pos, int max ) { int i, cnt = 0; fireteamData_t* f = CG_IsOnFireteam( cg.clientNum ); if ( !f ) { return NULL; } for ( i = 0; i < MAX_CLIENTS && cnt < max; i++ ) { if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[cg.clientNum].team == cgs.clientinfo[i].team ) { if ( !( f == CG_IsOnFireteam( i ) ) ) { continue; } if ( cnt == pos ) { return &cgs.clientinfo[i]; } cnt++; } } return NULL; } // Client, sorted by rank, on CLIENT'S fireteam clientInfo_t* CG_SortedFireTeamPlayerForPosition( int pos, int max ) { int i, cnt = 0; fireteamData_t* f = CG_IsOnFireteam( cg.clientNum ); if ( !f ) { return NULL; } for ( i = 0; i < MAX_CLIENTS && cnt < max; i++ ) { if ( !( f == CG_IsOnFireteam( sortedFireTeamClients[i] ) ) ) { return NULL; } if ( cnt == pos ) { return &cgs.clientinfo[sortedFireTeamClients[i]]; } cnt++; } return NULL; } /****************************************************************************** ***** Main Functions ****/ #define FT_BAR_YSPACING 2.f #define FT_BAR_HEIGHT 10.f void CG_DrawFireTeamOverlay( rectDef_t* rect ) { int x = rect->x; int y = rect->y + 1; // +1, jitter it into place in 1024 :) float h; clientInfo_t* ci = NULL; char buffer[64]; fireteamData_t* f = NULL; int i; vec4_t clr1 = { .16f, .2f, .17f, .8f }; vec4_t clr2 = { 0.f, 0.f, 0.f, .2f }; vec4_t clr3 = { 0.25f, 0.f, 0.f, 153 / 255.f }; vec4_t tclr = { 0.6f, 0.6f, 0.6f, 1.0f }; vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.6f }; // window vec4_t borderColor = { 0.5f, 0.5f, 0.5f, 0.5f }; // window if ( !( f = CG_IsOnFireteam( cg.clientNum ) ) ) { return; } h = 12 + 2 + 2; for ( i = 0; i < 6; i++ ) { ci = CG_SortedFireTeamPlayerForPosition( i, 6 ); if ( !ci ) { break;; } h += FT_BAR_HEIGHT + FT_BAR_YSPACING; } CG_DrawRect( x, y, 204, h, 1, borderColor ); CG_FillRect( x + 1, y + 1, 204 - 2, h - 2, bgColor ); x += 2; y += 2; CG_FillRect( x, y, 204 - 4, 12, clr1 ); sprintf( buffer, "Fireteam: %s", bg_fireteamNames[f->ident] ); Q_strupr( buffer ); CG_Text_Paint_Ext( x + 3, y + FT_BAR_HEIGHT, .19f, .19f, tclr, buffer, 0, 0, 0, &cgs.media.limboFont1 ); x += 2; //y += 2; for ( i = 0; i < 6; i++ ) { y += FT_BAR_HEIGHT + FT_BAR_YSPACING; x = rect->x + 2; ci = CG_SortedFireTeamPlayerForPosition( i, 6 ); if ( !ci ) { break;; } if ( ci->selected ) { CG_FillRect( x, y + FT_BAR_YSPACING, 204 - 4, FT_BAR_HEIGHT, clr3 ); } else { CG_FillRect( x, y + FT_BAR_YSPACING, 204 - 4, FT_BAR_HEIGHT, clr2 ); } x += 4; CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, BG_ClassLetterForNumber( ci->cls ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); x += 10; CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->team == TEAM_AXIS ? miniRankNames_Axis[ci->rank] : miniRankNames_Allies[ci->rank], 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); x += 22; CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, ci->name, 0, 17, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); x += 90; /* CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.movementAutonomyIcons[0]); x += FT_BAR_HEIGHT; CG_DrawPic(x + 2, y + 2, FT_BAR_HEIGHT - 4, FT_BAR_HEIGHT - 4, cgs.media.weaponAutonomyIcons[0]); x += FT_BAR_HEIGHT; x += 4;*/ /* if( isLeader ) { CG_Text_Paint_Ext(x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va("%i", i+4), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); }*/ x += 20; if ( ci->health > 80 ) { CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va( "%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); } else if ( ci->health > 0 ) { CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorYellow, va( "%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); } else { CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, colorRed, va( "%i", ci->health < 0 ? 0 : ci->health ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); } //x += 20; { vec2_t loc; char *s; loc[0] = ci->location[0]; loc[1] = ci->location[1]; s = va( "^3(%s)", BG_GetLocationString( loc ) ); x = rect->x + ( 204 - 4 - CG_Text_Width_Ext( s, .2f, 0, &cgs.media.limboFont2 ) ); CG_Text_Paint_Ext( x, y + FT_BAR_HEIGHT, .2f, .2f, tclr, va( "^3(%s)", BG_GetLocationString( loc ) ), 0, 0, ITEM_TEXTSTYLE_SHADOWED, &cgs.media.limboFont2 ); } } } qboolean CG_FireteamGetBoxNeedsButtons() { if ( cgs.applicationEndTime > cg.time ) { if ( cgs.applicationClient < 0 ) { return qfalse; } return qtrue; } if ( cgs.invitationEndTime > cg.time ) { if ( cgs.invitationClient < 0 ) { return qfalse; } return qtrue; } if ( cgs.propositionEndTime > cg.time ) { if ( cgs.propositionClient < 0 ) { return qfalse; } return qtrue; } return qfalse; } const char* CG_FireteamGetBoxText() { if ( cgs.applicationEndTime > cg.time ) { if ( cgs.applicationClient == -1 ) { return "Sent"; } if ( cgs.applicationClient == -2 ) { return "Failed"; } if ( cgs.applicationClient == -3 ) { return "Accepted"; } if ( cgs.applicationClient == -4 ) { return "Sent"; } if ( cgs.applicationClient < 0 ) { return NULL; } return va( "Accept application from %s?", cgs.clientinfo[cgs.applicationClient].name ); } if ( cgs.invitationEndTime > cg.time ) { if ( cgs.invitationClient == -1 ) { return "Sent"; } if ( cgs.invitationClient == -2 ) { return "Failed"; } if ( cgs.invitationClient == -3 ) { return "Accepted"; } if ( cgs.invitationClient == -4 ) { return "Sent"; } if ( cgs.invitationClient < 0 ) { return NULL; } return va( "Accept invitiation from %s?", cgs.clientinfo[cgs.invitationClient].name ); } if ( cgs.propositionEndTime > cg.time ) { if ( cgs.propositionClient == -1 ) { return "Sent"; } if ( cgs.propositionClient == -2 ) { return "Failed"; } if ( cgs.propositionClient == -3 ) { return "Accepted"; } if ( cgs.propositionClient == -4 ) { return "Sent"; } if ( cgs.propositionClient < 0 ) { return NULL; } return va( "Accept %s's proposition to invite %s to join your fireteam?", cgs.clientinfo[cgs.propositionClient2].name, cgs.clientinfo[cgs.propositionClient].name ); } return NULL; } qboolean CG_FireteamHasClass( int classnum, qboolean selectedonly ) { fireteamData_t* ft; int i; if ( !( ft = CG_IsOnFireteam( cg.clientNum ) ) ) { return qfalse; } for ( i = 0; i < MAX_CLIENTS; i++ ) { /* if( i == cgs.clientinfo ) { continue; }*/ if ( !cgs.clientinfo[ i ].infoValid ) { continue; } if ( ft != CG_IsOnFireteam( i ) ) { continue; } if ( cgs.clientinfo[ i ].cls != classnum ) { continue; } if ( selectedonly && !cgs.clientinfo[ i ].selected ) { continue; } return qtrue; } return qfalse; } const char* CG_BuildSelectedFirteamString( void ) { char buffer[256]; clientInfo_t* ci; int cnt = 0; int i; *buffer = '\0'; for ( i = 0; i < 6; i++ ) { ci = CG_SortedFireTeamPlayerForPosition( i, 6 ); if ( !ci ) { break; } if ( !ci->selected ) { continue; } cnt++; Q_strcat( buffer, sizeof( buffer ), va( "%i ", ci->clientNum ) ); } if ( cnt == 0 ) { return "0"; } if ( !cgs.clientinfo[cg.clientNum].selected ) { Q_strcat( buffer, sizeof( buffer ), va( "%i ", cg.clientNum ) ); cnt++; } return va( "%i %s", cnt, buffer ); }