/* =========================================================================== 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. =========================================================================== */ // cg_info.c -- display information while data is being loading #include "cg_local.h" /* =================== CG_DrawLoadingIcons =================== */ /*static void CG_DrawLoadingIcons( void ) { int n; int x, y; // JOSEPH 5-2-00 Per MAXX return; for( n = 0; n < loadingPlayerIconCount; n++ ) { x = 16 + n * 78; y = 324; CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] ); } for( n = 0; n < loadingItemIconCount; n++ ) { y = 400; if( n >= 13 ) { y += 40; } x = 16 + n % 13 * 48; CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] ); } }*/ /* ====================== CG_LoadingString ====================== */ void CG_LoadingString( const char *s ) { Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) ); if ( s && *s ) { CG_Printf( va( "LOADING... %s\n",s ) ); //----(SA) added so you can see from the console what's going on } // Arnout: no need for this //trap_UpdateScreen(); } /* ==================== CG_DrawInformation Draw all the status / pacifier stuff during level loading ==================== */ void CG_DrawInformation( qboolean forcerefresh ) { static int lastcalled = 0; if ( lastcalled && ( trap_Milliseconds() - lastcalled < 500 ) ) { return; } lastcalled = trap_Milliseconds(); if ( cg.snap ) { return; // we are in the world, no need to draw information } CG_DrawConnectScreen( qfalse, forcerefresh ); // OSP - Server MOTD window /* if(cg.motdWindow == NULL) { CG_createMOTDWindow(); } if(cg.motdWindow != NULL) { CG_windowDraw(); }*/ // OSP*/ } void CG_ShowHelp_On( int *status ) { int milli = trap_Milliseconds(); if ( *status == SHOW_SHUTDOWN && milli < cg.fadeTime ) { cg.fadeTime = 2 * milli + STATS_FADE_TIME - cg.fadeTime; } else if ( *status != SHOW_ON ) { cg.fadeTime = milli + STATS_FADE_TIME; } *status = SHOW_ON; } void CG_ShowHelp_Off( int *status ) { if ( *status != SHOW_OFF ) { int milli = trap_Milliseconds(); if ( milli < cg.fadeTime ) { cg.fadeTime = 2 * milli + STATS_FADE_TIME - cg.fadeTime; } else { cg.fadeTime = milli + STATS_FADE_TIME; } *status = SHOW_SHUTDOWN; } } // Demo playback key catcher support void CG_DemoClick( int key, qboolean down ) { int milli = trap_Milliseconds(); // Avoid active console keypress issues if ( !down && !cgs.fKeyPressed[key] ) { return; } cgs.fKeyPressed[key] = down; switch ( key ) { case K_ESCAPE: CG_ShowHelp_Off( &cg.demohelpWindow ); CG_keyOff_f(); return; case K_TAB: if ( down ) { CG_ScoresDown_f(); } else { CG_ScoresUp_f();} return; // Help info case K_BACKSPACE: if ( !down ) { if ( cg.demohelpWindow != SHOW_ON ) { CG_ShowHelp_On( &cg.demohelpWindow ); } else { CG_ShowHelp_Off( &cg.demohelpWindow ); } } return; // Screenshot keys case K_F11: if ( !down ) { trap_SendConsoleCommand( va( "screenshot%s\n", ( ( cg_useScreenshotJPEG.integer ) ? "JPEG" : "" ) ) ); } return; case K_F12: if ( !down ) { CG_autoScreenShot_f(); } return; // Window controls case K_SHIFT: case K_CTRL: case K_MOUSE4: cgs.fResize = down; return; case K_MOUSE1: cgs.fSelect = down; return; case K_MOUSE2: if ( !down ) { CG_mvSwapViews_f(); // Swap the window with the main view } return; case K_INS: case K_KP_PGUP: if ( !down ) { CG_mvShowView_f(); // Make a window for the client } return; case K_DEL: case K_KP_PGDN: if ( !down ) { CG_mvHideView_f(); // Delete the window for the client } return; case K_MOUSE3: if ( !down ) { CG_mvToggleView_f(); // Toggle a window for the client } return; // Third-person controls case K_ENTER: if ( !down ) { trap_Cvar_Set( "cg_thirdperson", ( ( cg_thirdPerson.integer == 0 ) ? "1" : "0" ) ); } return; case K_UPARROW: if ( milli > cgs.thirdpersonUpdate ) { float range = cg_thirdPersonRange.value; cgs.thirdpersonUpdate = milli + DEMO_THIRDPERSONUPDATE; range -= ( ( range >= 4 * DEMO_RANGEDELTA ) ? DEMO_RANGEDELTA : ( range - DEMO_RANGEDELTA ) ); trap_Cvar_Set( "cg_thirdPersonRange", va( "%f", range ) ); } return; case K_DOWNARROW: if ( milli > cgs.thirdpersonUpdate ) { float range = cg_thirdPersonRange.value; cgs.thirdpersonUpdate = milli + DEMO_THIRDPERSONUPDATE; range += ( ( range >= 120 * DEMO_RANGEDELTA ) ? 0 : DEMO_RANGEDELTA ); trap_Cvar_Set( "cg_thirdPersonRange", va( "%f", range ) ); } return; case K_RIGHTARROW: if ( milli > cgs.thirdpersonUpdate ) { float angle = cg_thirdPersonAngle.value - DEMO_ANGLEDELTA; cgs.thirdpersonUpdate = milli + DEMO_THIRDPERSONUPDATE; if ( angle < 0 ) { angle += 360.0f; } trap_Cvar_Set( "cg_thirdPersonAngle", va( "%f", angle ) ); } return; case K_LEFTARROW: if ( milli > cgs.thirdpersonUpdate ) { float angle = cg_thirdPersonAngle.value + DEMO_ANGLEDELTA; cgs.thirdpersonUpdate = milli + DEMO_THIRDPERSONUPDATE; if ( angle >= 360.0f ) { angle -= 360.0f; } trap_Cvar_Set( "cg_thirdPersonAngle", va( "%f", angle ) ); } return; // Timescale controls case K_KP_5: case K_KP_INS: case K_SPACE: if ( !down ) { trap_Cvar_Set( "timescale", "1" ); cgs.timescaleUpdate = cg.time + 1000; } return; case K_KP_DOWNARROW: if ( !down ) { float tscale = cg_timescale.value; if ( tscale <= 1.1f ) { if ( tscale > 0.1f ) { tscale -= 0.1f; } } else { tscale -= 1.0;} trap_Cvar_Set( "timescale", va( "%f", tscale ) ); cgs.timescaleUpdate = cg.time + (int)( 1000.0f * tscale ); } return; case K_MWHEELDOWN: if ( !cgs.fKeyPressed[K_SHIFT] ) { if ( !down ) { CG_ZoomOut_f(); } return; } // Roll over into timescale changes case K_KP_LEFTARROW: if ( !down && cg_timescale.value > 0.1f ) { trap_Cvar_Set( "timescale", va( "%f", cg_timescale.value - 0.1f ) ); cgs.timescaleUpdate = cg.time + (int)( 1000.0f * cg_timescale.value - 0.1f ); } return; case K_KP_UPARROW: if ( !down ) { trap_Cvar_Set( "timescale", va( "%f", cg_timescale.value + 1.0f ) ); cgs.timescaleUpdate = cg.time + (int)( 1000.0f * cg_timescale.value + 1.0f ); } return; case K_MWHEELUP: if ( !cgs.fKeyPressed[K_SHIFT] ) { if ( !down ) { CG_ZoomIn_f(); } return; } // Roll over into timescale changes case K_KP_RIGHTARROW: if ( !down ) { trap_Cvar_Set( "timescale", va( "%f", cg_timescale.value + 0.1f ) ); cgs.timescaleUpdate = cg.time + (int)( 1000.0f * cg_timescale.value + 0.1f ); } return; // AVI recording controls case K_F1: if ( down ) { cgs.aviDemoRate = demo_avifpsF1.integer; } else { trap_Cvar_Set( "cl_avidemo", demo_avifpsF1.string );} return; case K_F2: if ( down ) { cgs.aviDemoRate = demo_avifpsF2.integer; } else { trap_Cvar_Set( "cl_avidemo", demo_avifpsF2.string );} return; case K_F3: if ( down ) { cgs.aviDemoRate = demo_avifpsF3.integer; } else { trap_Cvar_Set( "cl_avidemo", demo_avifpsF3.string );} return; case K_F4: if ( down ) { cgs.aviDemoRate = demo_avifpsF4.integer; } else { trap_Cvar_Set( "cl_avidemo", demo_avifpsF4.string );} return; case K_F5: if ( down ) { cgs.aviDemoRate = demo_avifpsF5.integer; } else { trap_Cvar_Set( "cl_avidemo", demo_avifpsF5.string );} return; } } // // Color/font info used for all overlays (below) // #define COLOR_BG { 0.0f, 0.0f, 0.0f, 0.6f } #define COLOR_BORDER { 0.5f, 0.5f, 0.5f, 0.5f } #define COLOR_BG_TITLE { 0.16, 0.2f, 0.17f, 0.8f } #define COLOR_BG_VIEW { 0.16, 0.2f, 0.17f, 0.8f } #define COLOR_BORDER_TITLE { 0.1f, 0.1f, 0.1f, 0.2f } #define COLOR_BORDER_VIEW { 0.2f, 0.2f, 0.2f, 0.4f } #define COLOR_HDR { 0.6f, 0.6f, 0.6f, 1.0f } #define COLOR_HDR2 { 0.6f, 0.6f, 0.4f, 1.0f } #define COLOR_TEXT { 0.625f, 0.625f, 0.6f, 1.0f } #define FONT_HEADER &cgs.media.limboFont1 #define FONT_SUBHEADER &cgs.media.limboFont1_lo #define FONT_TEXT &cgs.media.limboFont2 vec4_t color_bg = COLOR_BG_VIEW; vec4_t color_border = COLOR_BORDER_VIEW; vec4_t color_hdr = COLOR_HDR2; vec4_t color_name = COLOR_TEXT; #define VD_X 4 #define VD_Y 78 #define VD_SCALE_X_HDR 0.25f #define VD_SCALE_Y_HDR 0.30f #define VD_SCALE_X_NAME 0.30f #define VD_SCALE_Y_NAME 0.30f qboolean CG_ViewingDraw() { if ( cg.mvTotalClients < 1 ) { return( qfalse ); } else { int w, wTag; int tSpacing = 15; // Should derive from CG_Text_Height_Ext int pID = cg.mvCurrentMainview->mvInfo & MV_PID; char *viewInfo = "Viewing:"; wTag = CG_Text_Width_Ext( viewInfo, VD_SCALE_X_HDR, 0, FONT_HEADER ); w = wTag + 3 + CG_Text_Width_Ext( cgs.clientinfo[pID].name, VD_SCALE_X_NAME, 0, FONT_TEXT ); CG_DrawRect( VD_X - 2, VD_Y, w + 7, tSpacing + 4, 1, color_border ); CG_FillRect( VD_X - 2, VD_Y, w + 7, tSpacing + 4, color_bg ); CG_Text_Paint_Ext( VD_X, VD_Y + tSpacing, // x, y VD_SCALE_X_HDR, VD_SCALE_Y_HDR, // scale_x, scale_y color_hdr, viewInfo, 0.0f, 0, ITEM_TEXTSTYLE_SHADOWED, FONT_HEADER ); CG_Text_Paint_Ext( VD_X + wTag + 5, VD_Y + tSpacing, // x, y VD_SCALE_X_NAME, VD_SCALE_Y_NAME, // scale_x, scale_y color_name, cgs.clientinfo[pID].name, 0.0f, 0, ITEM_TEXTSTYLE_SHADOWED, FONT_TEXT ); return( qtrue ); } } #define GS_X 166 #define GS_Y 10 #define GS_W 308 void CG_GameStatsDraw() { if ( cgs.gamestats.show == SHOW_OFF ) { return; } else { int i, x = GS_X + 4, y = GS_Y, h; gameStats_t *gs = &cgs.gamestats; vec4_t bgColor = COLOR_BG; // window vec4_t borderColor = COLOR_BORDER; // window vec4_t bgColorTitle = COLOR_BG_TITLE; // titlebar vec4_t borderColorTitle = COLOR_BORDER_TITLE; // titlebar // Main header int hStyle = ITEM_TEXTSTYLE_SHADOWED; float hScale = 0.16f; float hScaleY = 0.21f; fontInfo_t *hFont = FONT_HEADER; // Sub header int hStyle2 = 0; float hScale2 = 0.16f; float hScaleY2 = 0.20f; fontInfo_t *hFont2 = FONT_SUBHEADER; vec4_t hdrColor = COLOR_HDR; // text // vec4_t hdrColor2 = COLOR_HDR2; // text // Text settings int tStyle = ITEM_TEXTSTYLE_SHADOWED; int tSpacing = 9; // Should derive from CG_Text_Height_Ext float tScale = 0.19f; fontInfo_t *tFont = FONT_TEXT; vec4_t tColor = COLOR_TEXT; // text float diff = cgs.gamestats.fadeTime - cg.time; // FIXME: Should compute this beforehand h = 2 + tSpacing + 2 + // Header 2 + 2 + tSpacing + 2 + // Stats columns 1 + // Stats + extra tSpacing * ( ( gs->cWeapons > 0 ) ? gs->cWeapons : 1 ) + tSpacing * ( ( gs->fHasStats ) ? 3 : 0 ) + ( ( cgs.gametype == GT_WOLF_LMS ) ? 0 : ( 4 + 2 * tSpacing + // Rank/XP 1 + tSpacing + 4 + 2 * tSpacing + // Skill columns 1 + // Skillz tSpacing * ( ( gs->cSkills > 0 ) ? gs->cSkills : 1 ) ) ) + 2; // Fade-in effects if ( diff > 0.0f ) { float scale = ( diff / STATS_FADE_TIME ); if ( cgs.gamestats.show == SHOW_ON ) { scale = 1.0f - scale; } bgColor[3] *= scale; bgColorTitle[3] *= scale; borderColor[3] *= scale; borderColorTitle[3] *= scale; hdrColor[3] *= scale; tColor[3] *= scale; y -= h * ( 1.0f - scale ); } else if ( cgs.gamestats.show == SHOW_SHUTDOWN ) { cgs.gamestats.show = SHOW_OFF; return; } CG_DrawRect( GS_X, y, GS_W, h, 1, borderColor ); CG_FillRect( GS_X, y, GS_W, h, bgColor ); // Header CG_FillRect( GS_X, y, GS_W, tSpacing + 4, bgColorTitle ); CG_DrawRect( GS_X, y, GS_W, tSpacing + 4, 1, borderColorTitle ); y += 1; y += tSpacing; CG_Text_Paint_Ext( x, y, hScale, hScaleY, hdrColor, "PLAYER STATS", 0.0f, 0, hStyle, hFont ); y += 3; y += 2; // Weapon stats y += 2; CG_FillRect( GS_X, y, GS_W, tSpacing + 3, bgColorTitle ); CG_DrawRect( GS_X, y, GS_W, tSpacing + 3, 1, borderColorTitle ); y += 1 + tSpacing; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Weapon", 0.0f, 0, hStyle2, hFont2 ); x += 66; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Accuracy", 0.0f, 0, hStyle2, hFont2 ); x += 53; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Hits / Shots", 0.0f, 0, hStyle2, hFont2 ); x += 62; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Kills", 0.0f, 0, hStyle2, hFont2 ); x += 29; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Deaths", 0.0f, 0, hStyle2, hFont2 ); x += 40; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Headshots", 0.0f, 0, hStyle2, hFont2 ); x = GS_X + 4; y += 2; y += 1; if ( gs->cWeapons == 0 ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, "No weapon info available.", 0.0f, 0, tStyle, tFont ); } else { for ( i = 0; i < gs->cWeapons; i++ ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, gs->strWS[i], 0.0f, 0, tStyle, tFont ); } if ( gs->fHasStats ) { y += tSpacing; for ( i = 0; i < 2; i++ ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, gs->strExtra[i], 0.0f, 0, tStyle, tFont ); } } } // No rank/xp/skill info for LMS if ( cgs.gametype == GT_WOLF_LMS ) { return; } // Rank/XP info y += tSpacing; y += 2; CG_FillRect( GS_X, y, GS_W, tSpacing + 3, bgColorTitle ); CG_DrawRect( GS_X, y, GS_W, tSpacing + 3, 1, borderColorTitle ); y += 1 + tSpacing; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Rank", 0.0f, 0, hStyle2, hFont2 ); x += 82; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "XP", 0.0f, 0, hStyle2, hFont2 ); x = GS_X + 4; y += 1; y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, gs->strRank, 0.0f, 0, tStyle, tFont ); // Skill info y += tSpacing; y += 2; CG_FillRect( GS_X, y, GS_W, tSpacing + 3, bgColorTitle ); CG_DrawRect( GS_X, y, GS_W, tSpacing + 3, 1, borderColorTitle ); y += 1 + tSpacing; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Skills", 0.0f, 0, hStyle2, hFont2 ); x += 84; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Level", 0.0f, 0, hStyle2, hFont2 ); x += 40; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "XP / Next Level", 0.0f, 0, hStyle2, hFont2 ); if ( cgs.gametype == GT_WOLF_CAMPAIGN ) { x += 86; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Medals", 0.0f, 0, hStyle2, hFont2 ); } x = GS_X + 4; y += 1; if ( gs->cSkills == 0 ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, "No skills acquired!", 0.0f, 0, tStyle, tFont ); } else { for ( i = 0; i < gs->cSkills; i++ ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, gs->strSkillz[i], 0.0f, 0, tStyle, tFont ); } } } } #define TS_X -20 // spacing from right #define TS_Y -60 // spacing from bottom #define TS_W 308 void CG_TopShotsDraw() { if ( cgs.topshots.show == SHOW_OFF ) { return; } else { int i, x = 640 + TS_X - TS_W, y = 480, h; topshotStats_t *ts = &cgs.topshots; vec4_t bgColor = COLOR_BG; // window vec4_t borderColor = COLOR_BORDER; // window vec4_t bgColorTitle = COLOR_BG_TITLE; // titlebar vec4_t borderColorTitle = COLOR_BORDER_TITLE; // titlebar // Main header int hStyle = ITEM_TEXTSTYLE_SHADOWED; float hScale = 0.16f; float hScaleY = 0.21f; fontInfo_t *hFont = FONT_HEADER; // Sub header int hStyle2 = 0; float hScale2 = 0.16f; float hScaleY2 = 0.20f; fontInfo_t *hFont2 = FONT_SUBHEADER; vec4_t hdrColor = COLOR_HDR; // text vec4_t hdrColor2 = COLOR_HDR2; // text // Text settings int tStyle = ITEM_TEXTSTYLE_SHADOWED; int tSpacing = 9; // Should derive from CG_Text_Height_Ext float tScale = 0.19f; fontInfo_t *tFont = FONT_TEXT; vec4_t tColor = COLOR_TEXT; // text float diff = cgs.topshots.fadeTime - cg.time; // FIXME: Should compute this beforehand h = 2 + tSpacing + 2 + // Header 2 + 2 + tSpacing + 2 + // Stats columns 1 + // Stats + extra tSpacing * ( ( ts->cWeapons > 0 ) ? ts->cWeapons : 1 ) + 1; // Fade-in effects if ( diff > 0.0f ) { float scale = ( diff / STATS_FADE_TIME ); if ( cgs.topshots.show == SHOW_ON ) { scale = 1.0f - scale; } bgColor[3] *= scale; bgColorTitle[3] *= scale; borderColor[3] *= scale; borderColorTitle[3] *= scale; hdrColor[3] *= scale; hdrColor2[3] *= scale; tColor[3] *= scale; y += ( TS_Y - h ) * scale; } else if ( cgs.topshots.show == SHOW_SHUTDOWN ) { cgs.topshots.show = SHOW_OFF; return; } else { y += TS_Y - h; } CG_DrawRect( x, y, TS_W, h, 1, borderColor ); CG_FillRect( x, y, TS_W, h, bgColor ); // Header CG_FillRect( x, y, TS_W, tSpacing + 4, bgColorTitle ); CG_DrawRect( x, y, TS_W, tSpacing + 4, 1, borderColorTitle ); y += 1; y += tSpacing; CG_Text_Paint_Ext( x + 4, y, hScale, hScaleY, hdrColor, "\"TOPSHOT\" ACCURACIES", 0.0f, 0, hStyle, hFont ); y += 4; // Weapon stats y += 2; CG_FillRect( x, y, TS_W, tSpacing + 3, bgColorTitle ); CG_DrawRect( x, y, TS_W, tSpacing + 3, 1, borderColorTitle ); x += 4; y += 1 + tSpacing; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Weapon", 0.0f, 0, hStyle2, hFont2 ); x += 60; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Accuracy", 0.0f, 0, hStyle2, hFont2 ); x += 53; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Hits / Shots", 0.0f, 0, hStyle2, hFont2 ); x += 62; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Kills", 0.0f, 0, hStyle2, hFont2 ); x += 32; CG_Text_Paint_Ext( x, y, hScale2, hScaleY2, hdrColor, "Player", 0.0f, 0, hStyle2, hFont2 ); x = 640 + TS_X - TS_W + 4; y += 1; if ( ts->cWeapons == 0 ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, "No qualifying weapon info available.", 0.0f, 0, tStyle, tFont ); } else { for ( i = 0; i < ts->cWeapons; i++ ) { y += tSpacing; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, ts->strWS[i], 0.0f, 0, tStyle, tFont ); } } } } #define DH_X -20 // spacing from right #define DH_Y -60 // spacing from bottom #define DH_W 148 void CG_DemoHelpDraw() { if ( cg.demohelpWindow == SHOW_OFF ) { return; } else { const char *help[] = { "^nTAB ^mscores", "^nF1-F5 ^mavidemo record", "^nF11-F12 ^mscreenshot", NULL, "^nKP_DOWN ^mslow down (--)", "^nKP_LEFT ^mslow down (-)", "^nKP_UP ^mspeed up (++)", "^nKP_RIGHT ^mspeed up (+)", "^nSPACE ^mnormal speed", NULL, "^nENTER ^mExternal view", "^nLFT/RGHT ^mChange angle", "^nUP/DOWN ^mMove in/out" }; const char *mvhelp[] = { NULL, "^nMOUSE1 ^mSelect/move view", "^nMOUSE2 ^mSwap w/main view", "^nMOUSE3 ^mToggle on/off", "^nSHIFT ^mHold to resize", "^nKP_PGUP ^mEnable a view", "^nKP_PGDN ^mClose a view" }; int i, x, y = 480, w, h; vec4_t bgColor = COLOR_BG; // window vec4_t borderColor = COLOR_BORDER; // window vec4_t bgColorTitle = COLOR_BG_TITLE; // titlebar vec4_t borderColorTitle = COLOR_BORDER_TITLE; // titlebar // Main header int hStyle = ITEM_TEXTSTYLE_SHADOWED; float hScale = 0.16f; float hScaleY = 0.21f; fontInfo_t *hFont = FONT_HEADER; vec4_t hdrColor2 = COLOR_HDR2; // text // Text settings int tStyle = ITEM_TEXTSTYLE_SHADOWED; int tSpacing = 9; // Should derive from CG_Text_Height_Ext float tScale = 0.19f; fontInfo_t *tFont = FONT_TEXT; vec4_t tColor = COLOR_TEXT; // text float diff = cg.fadeTime - trap_Milliseconds(); // FIXME: Should compute this beforehand w = DH_W + ( ( cg.mvTotalClients > 1 ) ? 12 : 0 ); x = 640 + DH_X - w; h = 2 + tSpacing + 2 + // Header 2 + 1 + tSpacing * ( 2 + ( sizeof( help ) + ( ( cg.mvTotalClients > 1 ) ? sizeof( mvhelp ) : 0 ) ) / sizeof( char * ) ) + 2; // Fade-in effects if ( diff > 0.0f ) { float scale = ( diff / STATS_FADE_TIME ); if ( cg.demohelpWindow == SHOW_ON ) { scale = 1.0f - scale; } bgColor[3] *= scale; bgColorTitle[3] *= scale; borderColor[3] *= scale; borderColorTitle[3] *= scale; hdrColor2[3] *= scale; tColor[3] *= scale; y += ( DH_Y - h ) * scale; } else if ( cg.demohelpWindow == SHOW_SHUTDOWN ) { cg.demohelpWindow = SHOW_OFF; return; } else { y += DH_Y - h; } CG_DrawRect( x, y, w, h, 1, borderColor ); CG_FillRect( x, y, w, h, bgColor ); // Header CG_FillRect( x, y, w, tSpacing + 4, bgColorTitle ); CG_DrawRect( x, y, w, tSpacing + 4, 1, borderColorTitle ); x += 4; y += 1; y += tSpacing; CG_Text_Paint_Ext( x, y, hScale, hScaleY, hdrColor2, "DEMO CONTROLS", 0.0f, 0, hStyle, hFont ); y += 3; // Control info for ( i = 0; i < sizeof( help ) / sizeof( char * ); i++ ) { y += tSpacing; if ( help[i] != NULL ) { CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, (char*)help[i], 0.0f, 0, tStyle, tFont ); } } if ( cg.mvTotalClients > 1 ) { for ( i = 0; i < sizeof( mvhelp ) / sizeof( char * ); i++ ) { y += tSpacing; if ( mvhelp[i] != NULL ) { CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, (char*)mvhelp[i], 0.0f, 0, tStyle, tFont ); } } } y += tSpacing * 2; CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, "^nBACKSPACE ^mhelp on/off", 0.0f, 0, tStyle, tFont ); } } char *CG_getBindKeyName( const char *cmd, char *buf, int len ) { int j; for ( j = 0; j < 256; j++ ) { trap_Key_GetBindingBuf( j, buf, len ); if ( *buf == 0 ) { continue; } if ( !Q_stricmp( buf, cmd ) ) { trap_Key_KeynumToStringBuf( j, buf, MAX_STRING_TOKENS ); Q_strupr( buf ); return( buf ); } } Q_strncpyz( buf, va( "(%s)", cmd ), len ); return( buf ); } typedef struct { char *cmd; char *info; } helpType_t; #define SH_X 2 // spacing from left #define SH_Y 155 // spacing from top void CG_SpecHelpDraw() { if ( cg.spechelpWindow == SHOW_OFF ) { return; } else { const helpType_t help[] = { { "+zoom", "hold for pointer" }, { "+attack", "window move/resize" }, { "+sprint", "hold to resize" }, { "weapnext", "window on/off" }, { "weapprev", "swap w/main view" }, { NULL, NULL }, { "weapalt", "swingcam toggle" }, { "spechelp", "help on/off" } }; int i, x, y = 480, w, h; int len, maxlen = 0; char format[MAX_STRING_TOKENS], buf[MAX_STRING_TOKENS]; char *lines[16]; vec4_t bgColor = COLOR_BG; // window vec4_t borderColor = COLOR_BORDER; // window vec4_t bgColorTitle = COLOR_BG_TITLE; // titlebar vec4_t borderColorTitle = COLOR_BORDER_TITLE; // titlebar // Main header int hStyle = ITEM_TEXTSTYLE_SHADOWED; float hScale = 0.16f; float hScaleY = 0.21f; fontInfo_t *hFont = FONT_HEADER; vec4_t hdrColor2 = COLOR_HDR2; // text // Text settings int tStyle = ITEM_TEXTSTYLE_SHADOWED; int tSpacing = 9; // Should derive from CG_Text_Height_Ext float tScale = 0.19f; fontInfo_t *tFont = FONT_TEXT; vec4_t tColor = COLOR_TEXT; // text float diff = cg.fadeTime - trap_Milliseconds(); // FIXME: Should compute all this stuff beforehand // Compute required width for ( i = 0; i < sizeof( help ) / sizeof( helpType_t ); i++ ) { if ( help[i].cmd != NULL ) { len = strlen( CG_getBindKeyName( help[i].cmd, buf, sizeof( buf ) ) ); if ( len > maxlen ) { maxlen = len; } } } Q_strncpyz( format, va( "^2%%%ds ^N%%s", maxlen ), sizeof( format ) ); for ( i = 0, maxlen = 0; i < sizeof( help ) / sizeof( helpType_t ); i++ ) { if ( help[i].cmd != NULL ) { lines[i] = va( format, CG_getBindKeyName( help[i].cmd, buf, sizeof( buf ) ), help[i].info ); len = CG_Text_Width_Ext( lines[i], tScale, 0, FONT_TEXT ); if ( len > maxlen ) { maxlen = len; } } else { lines[i] = NULL; } } w = maxlen + 8; x = SH_X; y = SH_Y; h = 2 + tSpacing + 2 + // Header 2 + 1 + tSpacing * ( sizeof( help ) / sizeof( helpType_t ) ) + 2; // Fade-in effects if ( diff > 0.0f ) { float scale = ( diff / STATS_FADE_TIME ); if ( cg.spechelpWindow == SHOW_ON ) { scale = 1.0f - scale; } bgColor[3] *= scale; bgColorTitle[3] *= scale; borderColor[3] *= scale; borderColorTitle[3] *= scale; hdrColor2[3] *= scale; tColor[3] *= scale; x -= w * ( 1.0f - scale ); } else if ( cg.spechelpWindow == SHOW_SHUTDOWN ) { cg.spechelpWindow = SHOW_OFF; return; } CG_DrawRect( x, y, w, h, 1, borderColor ); CG_FillRect( x, y, w, h, bgColor ); // Header CG_FillRect( x, y, w, tSpacing + 4, bgColorTitle ); CG_DrawRect( x, y, w, tSpacing + 4, 1, borderColorTitle ); x += 4; y += 1; y += tSpacing; CG_Text_Paint_Ext( x, y, hScale, hScaleY, hdrColor2, "SPECTATOR CONTROLS", 0.0f, 0, hStyle, hFont ); y += 3; // Control info for ( i = 0; i < sizeof( help ) / sizeof( helpType_t ); i++ ) { y += tSpacing; if ( lines[i] != NULL ) { CG_Text_Paint_Ext( x, y, tScale, tScale, tColor, lines[i], 0.0f, 0, tStyle, tFont ); } } } } void CG_DrawOverlays( void ) { CG_GameStatsDraw(); CG_TopShotsDraw(); #ifdef MV_SUPPORT CG_SpecHelpDraw(); #endif if ( cg.demoPlayback ) { CG_DemoHelpDraw(); } }