📄 cg_newdraw.c
字号:
/*
===========================================================================
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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -