/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena 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 2 of the License, or (at your option) any later version. Quake III Arena 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 Foobar; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #ifndef MISSIONPACK // bk001204 #error This file not be used for classic Q3A. #endif #include "cg_local.h" #include "../ui/ui_shared.h" extern displayContextDef_t cgDC; // set in CG_ParseTeamInfo //static int sortedTeamPlayers[TEAM_MAXOVERLAY]; //static int numSortedTeamPlayers; int drawTeamOverlayModificationCount = -1; //static char systemChat[256]; //static char teamChat1[256]; //static char teamChat2[256]; void CG_InitTeamChat() { memset(teamChat1, 0, sizeof(teamChat1)); memset(teamChat2, 0, sizeof(teamChat2)); memset(systemChat, 0, sizeof(systemChat)); } void CG_SetPrintString(int type, const char *p) { if (type == SYSTEM_PRINT) { strcpy(systemChat, p); } else { strcpy(teamChat2, teamChat1); strcpy(teamChat1, p); } } void CG_CheckOrderPending() { if (cgs.gametype < GT_CTF) { return; } if (cgs.orderPending) { //clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer]; const char *p1, *p2, *b; p1 = p2 = b = NULL; switch (cgs.currentOrder) { case TEAMTASK_OFFENSE: p1 = VOICECHAT_ONOFFENSE; p2 = VOICECHAT_OFFENSE; b = "+button7; wait; -button7"; break; case TEAMTASK_DEFENSE: p1 = VOICECHAT_ONDEFENSE; p2 = VOICECHAT_DEFEND; b = "+button8; wait; -button8"; break; case TEAMTASK_PATROL: p1 = VOICECHAT_ONPATROL; p2 = VOICECHAT_PATROL; b = "+button9; wait; -button9"; break; case TEAMTASK_FOLLOW: p1 = VOICECHAT_ONFOLLOW; p2 = VOICECHAT_FOLLOWME; b = "+button10; wait; -button10"; break; case TEAMTASK_CAMP: p1 = VOICECHAT_ONCAMPING; p2 = VOICECHAT_CAMP; break; case TEAMTASK_RETRIEVE: p1 = VOICECHAT_ONGETFLAG; p2 = VOICECHAT_RETURNFLAG; break; case TEAMTASK_ESCORT: p1 = VOICECHAT_ONFOLLOWCARRIER; p2 = VOICECHAT_FOLLOWFLAGCARRIER; break; } if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) { // to everyone trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2)); } else { // for the player self if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) { trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder)); //trap_SendConsoleCommand(va("cmd say_team %s\n", p2)); trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1)); } else if (p2) { //trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p)); trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2)); } } if (b) { trap_SendConsoleCommand(b); } cgs.orderPending = qfalse; } } static void CG_SetSelectedPlayerName() { if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer]; if (ci) { trap_Cvar_Set("cg_selectedPlayerName", ci->name); trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer])); cgs.currentOrder = ci->teamTask; } } else { trap_Cvar_Set("cg_selectedPlayerName", "Everyone"); } } int CG_GetSelectedPlayer() { if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) { cg_currentSelectedPlayer.integer = 0; } return cg_currentSelectedPlayer.integer; } void CG_SelectNextPlayer() { CG_CheckOrderPending(); if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { cg_currentSelectedPlayer.integer++; } else { cg_currentSelectedPlayer.integer = 0; } CG_SetSelectedPlayerName(); } void CG_SelectPrevPlayer() { CG_CheckOrderPending(); if (cg_currentSelectedPlayer.integer > 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) { cg_currentSelectedPlayer.integer--; } else { cg_currentSelectedPlayer.integer = numSortedTeamPlayers; } CG_SetSelectedPlayerName(); } static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) { centity_t *cent; playerState_t *ps; vec3_t angles; vec3_t origin; if ( cg_drawStatus.integer == 0 ) { return; } cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon ); } else if (cg_draw3dIcons.integer) { VectorClear( angles ); origin[0] = 90; origin[1] = 0; origin[2] = -10; angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles ); } } static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { char num[16]; int value; centity_t *cent; playerState_t *ps; cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; value = ps->stats[STAT_ARMOR]; if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", value); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } #ifndef MISSIONPACK // bk001206 static float healthColors[4][4] = { // { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} }; // bk0101016 - float const { 1.0f, 0.69f, 0.0f, 1.0f } , // normal { 1.0f, 0.2f, 0.2f, 1.0f }, // low health { 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing { 1.0f, 1.0f, 1.0f, 1.0f } }; // health > 100 #endif static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) { centity_t *cent; playerState_t *ps; vec3_t angles; vec3_t origin; cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses qhandle_t icon; icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; if ( icon ) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon ); } } else if (cg_draw3dIcons.integer) { if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) { VectorClear( angles ); origin[0] = 70; origin[1] = 0; origin[2] = 0; angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 ); CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles ); } } } static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { char num[16]; int value; centity_t *cent; playerState_t *ps; cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; if ( cent->currentState.weapon ) { value = ps->ammo[cent->currentState.weapon]; if ( value > -1 ) { if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", value); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } } } static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) { vec3_t angles; float size, stretch; float frac; float x = rect->x; VectorClear( angles ); if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) { frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME; size = rect->w * 1.25 * ( 1.5 - frac * 0.5 ); stretch = size - rect->w * 1.25; // kick in the direction of damage x -= stretch * 0.5 + cg.damageX * stretch * 0.5; cg.headStartYaw = 180 + cg.damageX * 45; cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); cg.headEndPitch = 5 * cos( crandom()*M_PI ); cg.headStartTime = cg.time; cg.headEndTime = cg.time + 100 + random() * 2000; } else { if ( cg.time >= cg.headEndTime ) { // select a new head angle cg.headStartYaw = cg.headEndYaw; cg.headStartPitch = cg.headEndPitch; cg.headStartTime = cg.headEndTime; cg.headEndTime = cg.time + 100 + random() * 2000; cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); cg.headEndPitch = 5 * cos( crandom()*M_PI ); } size = rect->w * 1.25; } // if the server was frozen for a while we may have a bad head start time if ( cg.headStartTime > cg.time ) { cg.headStartTime = cg.time; } frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime ); frac = frac * frac * ( 3 - 2 * frac ); angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac; angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac; CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles ); } static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { clientInfo_t *ci; int value; char num[16]; ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", ci->health); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } } static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { clientInfo_t *ci; int value; char num[16]; ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { if (ci->armor > 0) { if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", ci->armor); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } } } qhandle_t CG_StatusHandle(int task) { qhandle_t h = cgs.media.assaultShader; switch (task) { case TEAMTASK_OFFENSE : h = cgs.media.assaultShader; break; case TEAMTASK_DEFENSE : h = cgs.media.defendShader; break; case TEAMTASK_PATROL : h = cgs.media.patrolShader; break; case TEAMTASK_FOLLOW : h = cgs.media.followShader; break; case TEAMTASK_CAMP : h = cgs.media.campShader; break; case TEAMTASK_RETRIEVE : h = cgs.media.retrieveShader; break; case TEAMTASK_ESCORT : h = cgs.media.escortShader; break; default : h = cgs.media.assaultShader; break; } return h; } static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) { clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { qhandle_t h; if (cgs.orderPending) { // blink the icon if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) { return; } h = CG_StatusHandle(cgs.currentOrder); } else { h = CG_StatusHandle(ci->teamTask); } CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h ); } } static void CG_DrawPlayerStatus( rectDef_t *rect ) { clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; if (ci) { qhandle_t h = CG_StatusHandle(ci->teamTask); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h); } } static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) { clientInfo_t *ci; ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); if (ci) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle); } } static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { clientInfo_t *ci; ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); if (!p || !*p) { p = "unknown"; } CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle); } } static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; if (ci) { const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); if (!p || !*p) { p = "unknown"; } CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle); } } static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) { clientInfo_t *ci; ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { if ( cg_weapons[ci->curWeapon].weaponIcon ) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon ); } else { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader); } } } static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { char num[16]; int value = cg.snap->ps.persistant[PERS_SCORE]; if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", value); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) { int value; vec3_t origin, angles; value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; if ( value ) { CG_RegisterItemVisuals( value ); if (qtrue) { CG_RegisterItemVisuals( value ); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); } else { VectorClear( angles ); origin[0] = 90; origin[1] = 0; origin[2] = -10; angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles ); } } } static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) { clientInfo_t *ci; int j; float x, y; ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; if (ci) { x = rect->x; y = rect->y; for (j = 0; j < PW_NUM_POWERUPS; j++) { if (ci->powerups & (1 << j)) { gitem_t *item; item = BG_FindItemForPowerup( j ); if (item) { CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) ); x += 3; y += 3; return; } } } } } static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) { clipHandle_t cm; clientInfo_t *ci; float len; vec3_t origin; vec3_t mins, maxs, angles; ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); if (ci) { if ( cg_draw3dIcons.integer ) { cm = ci->headModel; if ( !cm ) { return; } // offset the origin y and z to center the head trap_R_ModelBounds( cm, mins, maxs ); origin[2] = -0.5 * ( mins[2] + maxs[2] ); origin[1] = 0.5 * ( mins[1] + maxs[1] ); // calculate distance so the head nearly fills the box // assume heads are taller than wide len = 0.7 * ( maxs[2] - mins[2] ); origin[0] = len / 0.268; // len / tan( fov/2 ) // allow per-model tweaking VectorAdd( origin, ci->headOffset, origin ); angles[PITCH] = 0; angles[YAW] = 180; angles[ROLL] = 0; CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles ); } else if ( cg_drawIcons.integer ) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon ); } // if they are deferred, draw a cross out if ( ci->deferred ) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader ); } } } static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { playerState_t *ps; int value; char num[16]; ps = &cg.snap->ps; value = ps->stats[STAT_HEALTH]; if (shader) { trap_R_SetColor( color ); CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); trap_R_SetColor( NULL ); } else { Com_sprintf (num, sizeof(num), "%i", value); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } } static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { int value; char num[16]; if ( cgs.scores1 == SCORE_NOT_PRESENT ) { Com_sprintf (num, sizeof(num), "-"); } else { Com_sprintf (num, sizeof(num), "%i", cgs.scores1); } value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { int value; char num[16]; if ( cgs.scores2 == SCORE_NOT_PRESENT ) { Com_sprintf (num, sizeof(num), "-"); } else { Com_sprintf (num, sizeof(num), "%i", cgs.scores2); } value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle); } // FIXME: team name support static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle); } static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle); } static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { int i; for ( i = 0 ; i < cgs.maxclients ; i++ ) { if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle); return; } } } static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) { if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) { if (cgs.gametype == GT_HARVESTER) { vec4_t color = {0, 0, 1, 1}; trap_R_SetColor(color); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon ); trap_R_SetColor(NULL); } return; } if (shader) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); } else { gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG ); if (item) { vec4_t color = {0, 0, 1, 1}; trap_R_SetColor(color); if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] ); } else { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); } trap_R_SetColor(NULL); } } } static void CG_DrawBlueFlagHead(rectDef_t *rect) { int i; for ( i = 0 ; i < cgs.maxclients ; i++ ) { if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { vec3_t angles; VectorClear( angles ); angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); return; } } } static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { int i; for ( i = 0 ; i < cgs.maxclients ; i++ ) { if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle); return; } } } static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) { if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) { if (cgs.gametype == GT_HARVESTER) { vec4_t color = {1, 0, 0, 1}; trap_R_SetColor(color); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon ); trap_R_SetColor(NULL); } return; } if (shader) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); } else { gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG ); if (item) { vec4_t color = {1, 0, 0, 1}; trap_R_SetColor(color); if( cgs.redflag >= 0 && cgs.redflag <= 2) { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] ); } else { CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); } trap_R_SetColor(NULL); } } } static void CG_DrawRedFlagHead(rectDef_t *rect) { int i; for ( i = 0 ; i < cgs.maxclients ; i++ ) { if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { vec3_t angles; VectorClear( angles ); angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); return; } } } static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) { char num[16]; vec3_t origin, angles; qhandle_t handle; int value = cg.snap->ps.generic1; if (cgs.gametype != GT_HARVESTER) { return; } if( value > 99 ) { value = 99; } Com_sprintf (num, sizeof(num), "%i", value); value = CG_Text_Width(num, scale, 0); CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle); if (cg_drawIcons.integer) { if (!force2D && cg_draw3dIcons.integer) { VectorClear(angles); origin[0] = 90; origin[1] = 0; origin[2] = -10; angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { handle = cgs.media.redCubeModel; } else { handle = cgs.media.blueCubeModel; } CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles ); } else { if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) { handle = cgs.media.redCubeIcon; } else { handle = cgs.media.blueCubeIcon; } CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle ); } } } static void CG_OneFlagStatus(rectDef_t *rect) { if (cgs.gametype != GT_1FCTF) { return; } else { gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); if (item) { if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) { vec4_t color = {1, 1, 1, 1}; int index = 0; if (cgs.flagStatus == FLAG_TAKEN_RED) { color[1] = color[2] = 0; index = 1; } else if (cgs.flagStatus == FLAG_TAKEN_BLUE) { color[0] = color[1] = 0; index = 1; } else if (cgs.flagStatus == FLAG_DROPPED) { index = 2; } trap_R_SetColor(color); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] ); } } } } static void CG_DrawCTFPowerUp(rectDef_t *rect) { int value; if (cgs.gametype < GT_CTF) { return; } value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP]; if ( value ) { CG_RegisterItemVisuals( value ); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); } } static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) { CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]); } static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) { char num[16]; int sorted[MAX_POWERUPS]; int sortedTime[MAX_POWERUPS]; int i, j, k; int active; playerState_t *ps; int t; gitem_t *item; float f; rectDef_t r2; float *inc; r2.x = rect->x; r2.y = rect->y; r2.w = rect->w; r2.h = rect->h; inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x; ps = &cg.snap->ps; if ( ps->stats[STAT_HEALTH] <= 0 ) { return; } // sort the list by time remaining active = 0; for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { if ( !ps->powerups[ i ] ) { continue; } t = ps->powerups[ i ] - cg.time; // ZOID--don't draw if the power up has unlimited time (999 seconds) // This is true of the CTF flags if ( t <= 0 || t >= 999000) { continue; } // insert into the list for ( j = 0 ; j < active ; j++ ) { if ( sortedTime[j] >= t ) { for ( k = active - 1 ; k >= j ; k-- ) { sorted[k+1] = sorted[k]; sortedTime[k+1] = sortedTime[k]; } break; } } sorted[j] = i; sortedTime[j] = t; active++; } // draw the icons and timers for ( i = 0 ; i < active ; i++ ) { item = BG_FindItemForPowerup( sorted[i] ); if (item) { t = ps->powerups[ sorted[i] ]; if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { trap_R_SetColor( NULL ); } else { vec4_t modulate; f = (float)( t - cg.time ) / POWERUP_BLINK_TIME; f -= (int)f; modulate[0] = modulate[1] = modulate[2] = modulate[3] = f; trap_R_SetColor( modulate ); } CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) ); Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000); CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0); *inc += r2.w + special; } } trap_R_SetColor( NULL ); } float CG_GetValue(int ownerDraw) { centity_t *cent; clientInfo_t *ci; playerState_t *ps; cent = &cg_entities[cg.snap->ps.clientNum]; ps = &cg.snap->ps; switch (ownerDraw) { case CG_SELECTEDPLAYER_ARMOR: ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; return ci->armor; break; case CG_SELECTEDPLAYER_HEALTH: ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; return ci->health; break; case CG_PLAYER_ARMOR_VALUE: return ps->stats[STAT_ARMOR]; break; case CG_PLAYER_AMMO_VALUE: if ( cent->currentState.weapon ) { return ps->ammo[cent->currentState.weapon]; } break; case CG_PLAYER_SCORE: return cg.snap->ps.persistant[PERS_SCORE]; break; case CG_PLAYER_HEALTH: return ps->stats[STAT_HEALTH]; break; case CG_RED_SCORE: return cgs.scores1; break; case CG_BLUE_SCORE: return cgs.scores2; break; default: break; } return -1; } qboolean CG_OtherTeamHasFlag() { if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) { int team = cg.snap->ps.persistant[PERS_TEAM]; if (cgs.gametype == GT_1FCTF) { if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) { return qtrue; } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) { return qtrue; } else { return qfalse; } } else { if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) { return qtrue; } else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) { return qtrue; } else { return qfalse; } } } return qfalse; } qboolean CG_YourTeamHasFlag() { if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) { int team = cg.snap->ps.persistant[PERS_TEAM]; if (cgs.gametype == GT_1FCTF) { if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) { return qtrue; } else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) { return qtrue; } else { return qfalse; } } else { if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) { return qtrue; } else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) { return qtrue; } else { return qfalse; } } } return qfalse; } // THINKABOUTME: should these be exclusive or inclusive.. // qboolean CG_OwnerDrawVisible(int flags) { if (flags & CG_SHOW_TEAMINFO) { return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers); } if (flags & CG_SHOW_NOTEAMINFO) { return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers); } if (flags & CG_SHOW_OTHERTEAMHASFLAG) { return CG_OtherTeamHasFlag(); } if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) { return CG_YourTeamHasFlag(); } if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) { if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) { return qtrue; } else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) { return qtrue; } return qfalse; } if (flags & CG_SHOW_ANYTEAMGAME) { if( cgs.gametype >= GT_TEAM) { return qtrue; } } if (flags & CG_SHOW_ANYNONTEAMGAME) { if( cgs.gametype < GT_TEAM) { return qtrue; } } if (flags & CG_SHOW_HARVESTER) { if( cgs.gametype == GT_HARVESTER ) { return qtrue; } else { return qfalse; } } if (flags & CG_SHOW_ONEFLAG) { if( cgs.gametype == GT_1FCTF ) { return qtrue; } else { return qfalse; } } if (flags & CG_SHOW_CTF) { if( cgs.gametype == GT_CTF ) { return qtrue; } } if (flags & CG_SHOW_OBELISK) { if( cgs.gametype == GT_OBELISK ) { return qtrue; } else { return qfalse; } } if (flags & CG_SHOW_HEALTHCRITICAL) { if (cg.snap->ps.stats[STAT_HEALTH] < 25) { return qtrue; } } if (flags & CG_SHOW_HEALTHOK) { if (cg.snap->ps.stats[STAT_HEALTH] >= 25) { return qtrue; } } if (flags & CG_SHOW_SINGLEPLAYER) { if( cgs.gametype == GT_SINGLE_PLAYER ) { return qtrue; } } if (flags & CG_SHOW_TOURNAMENT) { if( cgs.gametype == GT_TOURNAMENT ) { return qtrue; } } if (flags & CG_SHOW_DURINGINCOMINGVOICE) { } if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) { if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { return qtrue; } } return qfalse; } static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) { int adj = (force2D) ? 0 : 2; if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) { CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D); } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) { CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D); } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) { CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D); } } static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0); } static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0); } static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0); } const char *CG_GetKillerText() { const char *s = ""; if ( cg.killerName[0] ) { s = va("Fragged by %s", cg.killerName ); } return s; } static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { // fragged by ... line if ( cg.killerName[0] ) { int x = rect->x + rect->w / 2; CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle); } } static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit; CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle); } static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { if (cgs.scores1 != SCORE_NOT_PRESENT) { CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle); } } static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { if (cgs.scores2 != SCORE_NOT_PRESENT) { CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle); } } const char *CG_GetGameStatusText() { const char *s = ""; if ( cgs.gametype < GT_TEAM) { if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) { s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] ); } } else { if ( cg.teamScores[0] == cg.teamScores[1] ) { s = va("Teams are tied at %i", cg.teamScores[0] ); } else if ( cg.teamScores[0] >= cg.teamScores[1] ) { s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] ); } else { s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] ); } } return s; } static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle); } const char *CG_GameTypeString() { if ( cgs.gametype == GT_FFA ) { return "Free For All"; } else if ( cgs.gametype == GT_TEAM ) { return "Team Deathmatch"; } else if ( cgs.gametype == GT_CTF ) { return "Capture the Flag"; } else if ( cgs.gametype == GT_1FCTF ) { return "One Flag CTF"; } else if ( cgs.gametype == GT_OBELISK ) { return "Overload"; } else if ( cgs.gametype == GT_HARVESTER ) { return "Harvester"; } return ""; } static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle); } static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) { int len, count; vec4_t newColor; glyphInfo_t *glyph; if (text) { // TTimo: FIXME // const unsigned char *s = text; // bk001206 - unsigned const char *s = text; float max = *maxX; float useScale; fontInfo_t *font = &cgDC.Assets.textFont; if (scale <= cg_smallFont.value) { font = &cgDC.Assets.smallFont; } else if (scale > cg_bigFont.value) { font = &cgDC.Assets.bigFont; } useScale = scale * font->glyphScale; trap_R_SetColor( color ); len = strlen(text); if (limit > 0 && len > limit) { len = limit; } count = 0; while (s && *s && count < len) { glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build if ( Q_IsColorString( s ) ) { memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) ); newColor[3] = color[3]; trap_R_SetColor( newColor ); s += 2; continue; } else { float yadj = useScale * glyph->top; if (CG_Text_Width(s, useScale, 1) + x > max) { *maxX = 0; break; } CG_Text_PaintChar(x, y - yadj, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); x += (glyph->xSkip * useScale) + adjust; *maxX = x; count++; s++; } } trap_R_SetColor( NULL ); } } #define PIC_WIDTH 12 void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) { int xx; float y; int i, j, len, count; const char *p; vec4_t hcolor; float pwidth, lwidth, maxx, leftOver; clientInfo_t *ci; gitem_t *item; qhandle_t h; // max player name width pwidth = 0; count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers; for (i = 0; i < count; i++) { ci = cgs.clientinfo + sortedTeamPlayers[i]; if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { len = CG_Text_Width( ci->name, scale, 0); if (len > pwidth) pwidth = len; } } // max location name width lwidth = 0; for (i = 1; i < MAX_LOCATIONS; i++) { p = CG_ConfigString(CS_LOCATIONS + i); if (p && *p) { len = CG_Text_Width(p, scale, 0); if (len > lwidth) lwidth = len; } } y = rect->y; for (i = 0; i < count; i++) { ci = cgs.clientinfo + sortedTeamPlayers[i]; if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { xx = rect->x + 1; for (j = 0; j <= PW_NUM_POWERUPS; j++) { if (ci->powerups & (1 << j)) { item = BG_FindItemForPowerup( j ); if (item) { CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) ); xx += PIC_WIDTH; } } } // FIXME: max of 3 powerups shown properly xx = rect->x + (PIC_WIDTH * 3) + 2; CG_GetColorForHealth( ci->health, ci->armor, hcolor ); trap_R_SetColor(hcolor); CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader ); //Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor); //CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0); // draw weapon icon xx += PIC_WIDTH + 1; // weapon used is not that useful, use the space for task #if 0 if ( cg_weapons[ci->curWeapon].weaponIcon ) { CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon ); } else { CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader ); } #endif trap_R_SetColor(NULL); if (cgs.orderPending) { // blink the icon if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) { h = 0; } else { h = CG_StatusHandle(cgs.currentOrder); } } else { h = CG_StatusHandle(ci->teamTask); } if (h) { CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, h); } xx += PIC_WIDTH + 1; leftOver = rect->w - xx; maxx = xx + leftOver / 3; CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0); p = CG_ConfigString(CS_LOCATIONS + ci->location); if (!p || !*p) { p = "unknown"; } xx += leftOver / 3 + 2; maxx = rect->w - 4; CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0); y += text_y + 2; if ( y + text_y + 2 > rect->y + rect->h ) { break; } } } } void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { if (cg.spectatorLen) { float maxX; if (cg.spectatorWidth == -1) { cg.spectatorWidth = 0; cg.spectatorPaintX = rect->x + 1; cg.spectatorPaintX2 = -1; } if (cg.spectatorOffset > cg.spectatorLen) { cg.spectatorOffset = 0; cg.spectatorPaintX = rect->x + 1; cg.spectatorPaintX2 = -1; } if (cg.time > cg.spectatorTime) { cg.spectatorTime = cg.time + 10; if (cg.spectatorPaintX <= rect->x + 2) { if (cg.spectatorOffset < cg.spectatorLen) { cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1; cg.spectatorOffset++; } else { cg.spectatorOffset = 0; if (cg.spectatorPaintX2 >= 0) { cg.spectatorPaintX = cg.spectatorPaintX2; } else { cg.spectatorPaintX = rect->x + rect->w - 2; } cg.spectatorPaintX2 = -1; } } else { cg.spectatorPaintX--; if (cg.spectatorPaintX2 >= 0) { cg.spectatorPaintX2--; } } } maxX = rect->x + rect->w - 2; CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0); if (cg.spectatorPaintX2 >= 0) { float maxX2 = rect->x + rect->w - 2; CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset); } if (cg.spectatorOffset && maxX > 0) { // if we have an offset ( we are skipping the first part of the string ) and we fit the string if (cg.spectatorPaintX2 == -1) { cg.spectatorPaintX2 = rect->x + rect->w - 2; } } else { cg.spectatorPaintX2 = -1; } } } void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { score_t *score = &cg.scores[cg.selectedScore]; float value = 0; char *text = NULL; color[3] = 0.25; switch (ownerDraw) { case CG_ACCURACY: value = score->accuracy; break; case CG_ASSISTS: value = score->assistCount; break; case CG_DEFEND: value = score->defendCount; break; case CG_EXCELLENT: value = score->excellentCount; break; case CG_IMPRESSIVE: value = score->impressiveCount; break; case CG_PERFECT: value = score->perfect; break; case CG_GAUNTLET: value = score->guantletCount; break; case CG_CAPTURES: value = score->captures; break; } if (value > 0) { if (ownerDraw != CG_PERFECT) { if (ownerDraw == CG_ACCURACY) { text = va("%i%%", (int)value); if (value > 50) { color[3] = 1.0; } } else { text = va("%i", (int)value); color[3] = 1.0; } } else { if (value) { color[3] = 1.0; } text = "Wow"; } } trap_R_SetColor(color); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); if (text) { color[3] = 1.0; value = CG_Text_Width(text, scale, 0); CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0); } trap_R_SetColor(NULL); } // void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) { rectDef_t rect; if ( cg_drawStatus.integer == 0 ) { return; } //if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) { // return; //} rect.x = x; rect.y = y; rect.w = w; rect.h = h; switch (ownerDraw) { case CG_PLAYER_ARMOR_ICON: CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY); break; case CG_PLAYER_ARMOR_ICON2D: CG_DrawPlayerArmorIcon(&rect, qtrue); break; case CG_PLAYER_ARMOR_VALUE: CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle); break; case CG_PLAYER_AMMO_ICON: CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY); break; case CG_PLAYER_AMMO_ICON2D: CG_DrawPlayerAmmoIcon(&rect, qtrue); break; case CG_PLAYER_AMMO_VALUE: CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle); break; case CG_SELECTEDPLAYER_HEAD: CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse); break; case CG_VOICE_HEAD: CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue); break; case CG_VOICE_NAME: CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle); break; case CG_SELECTEDPLAYER_STATUS: CG_DrawSelectedPlayerStatus(&rect); break; case CG_SELECTEDPLAYER_ARMOR: CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle); break; case CG_SELECTEDPLAYER_HEALTH: CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle); break; case CG_SELECTEDPLAYER_NAME: CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle); break; case CG_SELECTEDPLAYER_LOCATION: CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle); break; case CG_SELECTEDPLAYER_WEAPON: CG_DrawSelectedPlayerWeapon(&rect); break; case CG_SELECTEDPLAYER_POWERUP: CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY); break; case CG_PLAYER_HEAD: CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY); break; case CG_PLAYER_ITEM: CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY); break; case CG_PLAYER_SCORE: CG_DrawPlayerScore(&rect, scale, color, shader, textStyle); break; case CG_PLAYER_HEALTH: CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle); break; case CG_RED_SCORE: CG_DrawRedScore(&rect, scale, color, shader, textStyle); break; case CG_BLUE_SCORE: CG_DrawBlueScore(&rect, scale, color, shader, textStyle); break; case CG_RED_NAME: CG_DrawRedName(&rect, scale, color, textStyle); break; case CG_BLUE_NAME: CG_DrawBlueName(&rect, scale, color, textStyle); break; case CG_BLUE_FLAGHEAD: CG_DrawBlueFlagHead(&rect); break; case CG_BLUE_FLAGSTATUS: CG_DrawBlueFlagStatus(&rect, shader); break; case CG_BLUE_FLAGNAME: CG_DrawBlueFlagName(&rect, scale, color, textStyle); break; case CG_RED_FLAGHEAD: CG_DrawRedFlagHead(&rect); break; case CG_RED_FLAGSTATUS: CG_DrawRedFlagStatus(&rect, shader); break; case CG_RED_FLAGNAME: CG_DrawRedFlagName(&rect, scale, color, textStyle); break; case CG_HARVESTER_SKULLS: CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle); break; case CG_HARVESTER_SKULLS2D: CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle); break; case CG_ONEFLAG_STATUS: CG_OneFlagStatus(&rect); break; case CG_PLAYER_LOCATION: CG_DrawPlayerLocation(&rect, scale, color, textStyle); break; case CG_TEAM_COLOR: CG_DrawTeamColor(&rect, color); break; case CG_CTF_POWERUP: CG_DrawCTFPowerUp(&rect); break; case CG_AREA_POWERUP: CG_DrawAreaPowerUp(&rect, align, special, scale, color); break; case CG_PLAYER_STATUS: CG_DrawPlayerStatus(&rect); break; case CG_PLAYER_HASFLAG: CG_DrawPlayerHasFlag(&rect, qfalse); break; case CG_PLAYER_HASFLAG2D: CG_DrawPlayerHasFlag(&rect, qtrue); break; case CG_AREA_SYSTEMCHAT: CG_DrawAreaSystemChat(&rect, scale, color, shader); break; case CG_AREA_TEAMCHAT: CG_DrawAreaTeamChat(&rect, scale, color, shader); break; case CG_AREA_CHAT: CG_DrawAreaChat(&rect, scale, color, shader); break; case CG_GAME_TYPE: CG_DrawGameType(&rect, scale, color, shader, textStyle); break; case CG_GAME_STATUS: CG_DrawGameStatus(&rect, scale, color, shader, textStyle); break; case CG_KILLER: CG_DrawKiller(&rect, scale, color, shader, textStyle); break; case CG_ACCURACY: case CG_ASSISTS: case CG_DEFEND: case CG_EXCELLENT: case CG_IMPRESSIVE: case CG_PERFECT: case CG_GAUNTLET: case CG_CAPTURES: CG_DrawMedal(ownerDraw, &rect, scale, color, shader); break; case CG_SPECTATORS: CG_DrawTeamSpectators(&rect, scale, color, shader); break; case CG_TEAMINFO: if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) { CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader); } break; case CG_CAPFRAGLIMIT: CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle); break; case CG_1STPLACE: CG_Draw1stPlace(&rect, scale, color, shader, textStyle); break; case CG_2NDPLACE: CG_Draw2ndPlace(&rect, scale, color, shader, textStyle); break; default: break; } } void CG_MouseEvent(int x, int y) { int n; if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) { trap_Key_SetCatcher(0); return; } cgs.cursorX+= x; if (cgs.cursorX < 0) cgs.cursorX = 0; else if (cgs.cursorX > 640) cgs.cursorX = 640; cgs.cursorY += y; if (cgs.cursorY < 0) cgs.cursorY = 0; else if (cgs.cursorY > 480) cgs.cursorY = 480; n = Display_CursorType(cgs.cursorX, cgs.cursorY); cgs.activeCursor = 0; if (n == CURSOR_ARROW) { cgs.activeCursor = cgs.media.selectCursor; } else if (n == CURSOR_SIZER) { cgs.activeCursor = cgs.media.sizeCursor; } if (cgs.capturedItem) { Display_MouseMove(cgs.capturedItem, x, y); } else { Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY); } } /* ================== CG_HideTeamMenus ================== */ void CG_HideTeamMenu() { Menus_CloseByName("teamMenu"); Menus_CloseByName("getMenu"); } /* ================== CG_ShowTeamMenus ================== */ void CG_ShowTeamMenu() { Menus_OpenByName("teamMenu"); } /* ================== CG_EventHandling ================== type 0 - no event handling 1 - team menu 2 - hud editor */ void CG_EventHandling(int type) { cgs.eventHandling = type; if (type == CGAME_EVENT_NONE) { CG_HideTeamMenu(); } else if (type == CGAME_EVENT_TEAMMENU) { //CG_ShowTeamMenu(); } else if (type == CGAME_EVENT_SCOREBOARD) { } } void CG_KeyEvent(int key, qboolean down) { if (!down) { return; } if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) { CG_EventHandling(CGAME_EVENT_NONE); trap_Key_SetCatcher(0); return; } //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) { // if we see this then we should always be visible // CG_EventHandling(CGAME_EVENT_NONE); // trap_Key_SetCatcher(0); //} Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY); if (cgs.capturedItem) { cgs.capturedItem = NULL; } else { if (key == K_MOUSE2 && down) { cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY); } } } int CG_ClientNumFromName(const char *p) { int i; for (i = 0; i < cgs.maxclients; i++) { if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) { return i; } } return -1; } void CG_ShowResponseHead() { Menus_OpenByName("voiceMenu"); trap_Cvar_Set("cl_conXOffset", "72"); cg.voiceTime = cg.time; } void CG_RunMenuScript(char **args) { } void CG_GetTeamColor(vec4_t *color) { if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) { (*color)[0] = 1.0f; (*color)[3] = 0.25f; (*color)[1] = (*color)[2] = 0.0f; } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) { (*color)[0] = (*color)[1] = 0.0f; (*color)[2] = 1.0f; (*color)[3] = 0.25f; } else { (*color)[0] = (*color)[2] = 0.0f; (*color)[1] = 0.17f; (*color)[3] = 0.25f; } }