Even though the code to use Hud scripts is included in the Quake 3 source, it is not activated by default. In fact, it is meant to be used only with the Team Arena version of Quake 3. If you wish to use this feature you must make some changes to the code and recompile the cgame and (possibly) the game modules. This tutorial will only look at making these changes using Visual C++ 6.0. Other versions of Visual C++ will be very similar and the steps required should be easily worked out for other compiling methods.
In order to activate just the scripted Hud but not activate all the rest of the TA features, we must make a number of changes to the source code of the cgame module. We also have to make some changes to the cgame project. The configuration we will be using for these code changes is Win32 Release. This will result in a vanilla Quake 3 cgame module but with the scripted Hud activated. We do not need to recompile the game module with this method.
Project Changes
There are two changes that must be made to the cgame project before we can recompile it.
The first is to add the cg_newDraw.c file to the build. This file is part of the project but it is not included when the project is compiled. To add it to the build, right click on cg_newDraw.c in the FileView window and select the Settings... option. Select the General tab and uncheck the box labeled Exclude file from build. Press OK and the file will be included when you compile the project.
Next you must add a define to the Project Settings. Go to the Project Settings for the cgame Win32 Release and select the C/C++ tab. In the Preprocessor definitions box add the following to the end of the text :
,SCRIPTHUD
Notice the comma at the start of the text. This adds a #define for SCRIPTHUD to the project. For other compilers you can add the following to the cg_local.h file to achieve the same thing :
#define SCRIPTHUD
It is this define that activates the scripted Hud code. If SCRIPTHUD is defined you get the scripted Hud. If it is not defined you get the normal Quake 3 Hud.
Source Code Changes
The changes to the source code are numerous but minor and are confined to five files. The line numbers are approximate and will vary depending on the source code version you are using and how much the file has been modified. Lines of source before and after the changes will be included to ease in figuring out where things take place.
cg_local.h
About line 810
qhandle_t dustPuffShader;
#endif
#ifdef SCRIPTHUD
qhandle_t heartShader;
#endif
qhandle_t invulnerabilityPowerupModel;
About line 950
#ifdef SCRIPTHUD
// new stuff
qhandle_t patrolShader;
qhandle_t assaultShader;
qhandle_t campShader;
qhandle_t followShader;
qhandle_t defendShader;
qhandle_t teamLeaderShader;
qhandle_t retrieveShader;
qhandle_t escortShader;
qhandle_t flagShaders[3];
#endif
#ifdef MISSIONPACK // SCRIPTHUD
sfxHandle_t countPrepareTeamSound;
About line 1175
extern vmCvar_t cg_trueLightning;
#ifdef SCRIPTHUD
extern vmCvar_t cg_redTeamName;
extern vmCvar_t cg_blueTeamName;
extern vmCvar_t cg_currentSelectedPlayer;
#endif
#ifdef MISSIONPACK // SCRIPTHUD
extern vmCvar_t cg_currentSelectedPlayerName;
cg_newDraw.c
About line 23
//#ifndef MISSIONPACK // bk001204 SCRIPTHUD
//#error This file not be used for classic Q3A.
//#endif
#include "cg_local.h"
#ifdef SCRIPTHUD
#include "../ui/ui_shared.h"
About line 810
#ifdef MISSIONPACK //SCRIPTHUD
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 );
}
}
#endif // SCRIPTHUD
About line 1640
case CG_TEAM_COLOR:
CG_DrawTeamColor(&rect, color);
break;
#ifdef MISSIONPACK // SCRIPTHUD
case CG_CTF_POWERUP:
CG_DrawCTFPowerUp(&rect);
break;
#endif // SCRIPTHUD
case CG_AREA_POWERUP:
About line 1855 (at end of file)
(*color)[1] = 0.17f;
(*color)[3] = 0.25f;
}
}
#endif // SCRIPTHUD
cg_main.c
About line 26
#include "cg_local.h"
#ifdef SCRIPTHUD
#include "../ui/ui_shared.h"
// display context for new ui stuff
displayContextDef_t cgDC;
#endif
About line 68
case CG_MOUSE_EVENT:
#ifdef SCRIPTHUD
cgDC.cursorx = cgs.cursorX;
cgDC.cursory = cgs.cursorY;
#endif
CG_MouseEvent(arg0, arg1);
About line 185
vmCvar_t cg_trueLightning;
#ifdef SCRIPTHUD
vmCvar_t cg_redTeamName;
vmCvar_t cg_blueTeamName;
vmCvar_t cg_currentSelectedPlayer;
#endif
#ifdef MISSIONPACK // SCRIPTHUD
vmCvar_t cg_currentSelectedPlayerName;
About line 285
{ &cg_synchronousClients, "g_synchronousClients", "0", 0 }, //
#ifdef SCRIPTHUD
{ &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
{ &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO },
{ &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
#endif
#ifdef MISSIONPACK // SCRIPTHUD
{ &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
About line 1010
cgs.media.medkitUsageModel = trap_R_RegisterModel( "models/powerups/regen.md3" )
#endif
#ifdef SCRIPTHUD
cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" );
#endif
cgs.media.invulnerabilityPowerupModel = trap_R_RegisterModel( "models/powerups/shield/shield.md3" );
About line 1068
cgs.gameModels[i] = trap_R_RegisterModel( modelName );
}
#ifdef MISSIONPACK // SCRIPTHUD
// new stuff
cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
#endif
#ifdef SCRIPTHUD
cgs.media.patrolShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/patrol.tga");
cgs.media.assaultShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/assault.tga");
cgs.media.campShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/camp.tga");
cgs.media.followShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/follow.tga");
cgs.media.defendShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/defend.tga");
cgs.media.teamLeaderShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/team_leader.tga");
cgs.media.retrieveShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/retrieve.tga");
cgs.media.escortShader = trap_R_RegisterShaderNoMip("ui/assets/statusbar/escort.tga");
cgs.media.sizeCursor = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/sizecursor.tga" );
cgs.media.selectCursor = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectcursor.tga" );
cgs.media.flagShaders[0] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_in_base.tga");
cgs.media.flagShaders[1] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_capture.tga");
cgs.media.flagShaders[2] = trap_R_RegisterShaderNoMip("ui/assets/statusbar/flag_missing.tga");
#endif
#ifdef MISSIONPACK // SCRIPTHUD
trap_R_RegisterModel( "models/players/james/lower.md3" );
About line 1200
trap_S_StartBackgroundTrack( parm1, parm2 );
}
#ifdef SCRIPTHUD
char *CG_GetMenuBuffer(const char *filename) {
int len;
About line 1888
#ifdef SCRIPTHUD // bk001204 - only needed there
static float CG_Cvar_Get(const char *cvar) {
char buff[128];
About line 1897
#ifdef SCRIPTHUD
void CG_Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text,
CG_Text_Paint(x, y, scale, color, text, 0, limit, style);
About line 2105
trap_CM_LoadMap( cgs.mapname );
#ifdef SCRIPTHUD
String_Init();
#endif
cg.loading = qtrue;
About line 2120
CG_RegisterClients();
#ifdef SCRIPTHUD
CG_AssetCache();
CG_LoadHudMenu(); // load new hud stuff
#endif
cg.loading = qfalse;
About line 2170
/*
==================
CG_EventHandling
==================
type 0 - no event handling
1 - team menu
2 - hud editor
*/
#ifndef SCRIPTHUD
void CG_EventHandling(int type) {
}
cg_draw.c
About line 28
#include "cg_local.h"
#ifdef SCRIPTHUD
#include "../ui/ui_shared.h"
About line 45
char teamChat2[256];
#ifdef SCRIPTHUD
int CG_Text_Width(const char *text, float scale, int limit) {
About line 210
#ifndef SCRIPTHUD
static void CG_DrawField (int x, int y, int width, int value) {
About line 425
#ifndef SCRIPTHUD
static void CG_DrawStatusBarHead( float x ) {
About line 484
#ifndef SCRIPTHUD
static void CG_DrawStatusBarFlag( float x, int team ) {
CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
About line 523
#ifndef SCRIPTHUD
static void CG_DrawStatusBar( void ) {
int color;
About line 1055
#ifndef SCRIPTHUD
static float CG_DrawScores( float y ) {
const char *s;
About line 1220
#ifndef SCRIPTHUD
static float CG_DrawPowerups( float y ) {
int sorted[MAX_POWERUPS];
About line 1323
#ifndef SCRIPTHUD
static void CG_DrawLowerRight( void ) {
float y;
About line 1343
#ifndef SCRIPTHUD
static int CG_DrawPickupItem( int y ) {
int value;
About line 1376
#ifndef SCRIPTHUD
static void CG_DrawLowerLeft( void ) {
float y;
About line 1399
#ifndef SCRIPTHUD
static void CG_DrawTeamInfo( void ) {
int w, h;
About line 1472
#ifndef SCRIPTHUD
static void CG_DrawHoldableItem( void ) {
int value;
About line 1840
static void CG_DrawCenterString( void ) {
char *start;
int l;
int x, y, w;
#ifdef SCRIPTHUD // bk010221 - unused else
int h;
#endif
float *color;
About line 1871
#ifdef SCRIPTHUD
w = CG_Text_Width(linebuffer, 0.5, 0);
h = CG_Text_Height(linebuffer, 0.5, 0);
x = (SCREEN_WIDTH - w) / 2;
CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
y += h + 6;
#else
w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
About line 2038
name = cgs.clientinfo[ cg.crosshairClientNum ].name;
#ifdef SCRIPTHUD
color[3] *= 0.5f;
w = CG_Text_Width(name, 0.3f, 0);
CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
#else
w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
About line 2138
static qboolean CG_DrawScoreboard( void ) {
#ifdef SCRIPTHUD
static qboolean firstTime = qtrue;
About line 2213
static void CG_DrawIntermission( void ) {
// int key;
#ifdef SCRIPTHUD
//if (cg_singlePlayer.integer) {
About line 2371
s = va( "%s vs %s", ci1->name, ci2->name );
#ifdef SCRIPTHUD
w = CG_Text_Width(s, 0.6f, 0);
CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
#else
w = CG_DrawStrlen( s );
About line 2403
}
#ifdef SCRIPTHUD
w = CG_Text_Width(s, 0.6f, 0);
CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
#else
w = CG_DrawStrlen( s );
About line 2460
#ifdef SCRIPTHUD
w = CG_Text_Width(s, scale, 0);
CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
#else
w = CG_DrawStrlen( s );
About line 2471
#ifdef SCRIPTHUD
/*
=================
CG_DrawTimedMenus
=================
*/
void CG_DrawTimedMenus( void ) {
About line 2494
static void CG_Draw2D( void ) {
#ifdef SCRIPTHUD
if (cgs.orderPending && cg.time > cgs.orderTime) {
About line 2526
if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
#ifdef SCRIPTHUD
if ( cg_drawStatus.integer ) {
About line 2542
CG_DrawWeaponSelect();
#ifndef SCRIPTHUD
CG_DrawHoldableItem();
#else
About line 2553
if ( cgs.gametype >= GT_TEAM ) {
#ifndef SCRIPTHUD
CG_DrawTeamInfo();
About line 2563
CG_DrawLagometer();
#ifdef SCRIPTHUD
if (!cg_paused.integer) {
CG_DrawUpperRight();
}
#else
CG_DrawUpperRight();
#endif
#ifndef SCRIPTHUD
CG_DrawLowerRight();
CG_DrawLowerLeft();
About line 2590
static void CG_DrawTourneyScoreboard( void ) {
#ifdef SCRIPTHUD
#else
CG_DrawOldTourneyScoreboard();
cg_consolecmds.c
About line 88
static void CG_ScoresDown_f( void ) {
#ifdef SCRIPTHUD
CG_BuildSpectatorString();
#endif
About line 118
#ifdef SCRIPTHUD
extern menuDef_t *menuScoreboard;
void Menu_Reset( void );
About line 156
Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
}
}
#endif // SCRIPTHUD
#ifdef MISSIONPACK // SCRIPTHUD
static void CG_spWin_f( void) {
trap_Cvar_Set("cg_cameraOrbit", "2");
About line 242
#ifdef SCRIPTHUD
static void CG_NextTeamMember_f( void ) {
CG_SelectNextPlayer();
About line 250
CG_SelectPrevPlayer();
}
#endif
#ifdef MISSIONPACK //SCRIPTHUD
static void CG_NextOrder_f( void ) {
About line 476
{ "tcmd", CG_TargetCommand_f },
#ifdef SCRIPTHUD
{ "loadhud", CG_LoadHud_f },
{ "nextTeamMember", CG_NextTeamMember_f },
{ "prevTeamMember", CG_PrevTeamMember_f },
#endif //SCRIPTHUD
#ifdef MISSIONPACK //SCRIPTHUD
{ "nextOrder", CG_NextOrder_f },
About line 498
{ "spLose", CG_spLose_f },
#endif //SCRIPTHUD
#ifdef SCRIPTHUD
{ "scoresDown", CG_scrollScoresDown_f },
{ "scoresUp", CG_scrollScoresUp_f },
#endif
All that is needed at this point is to recompile the project and the scripted Hud is ready to be used. If you get compile errors make sure that you have the correct UI source files in your source tree. Not having these files is the most common reason for compiling problems.