/*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * Valve LLC. All other use, distribution, or modification is prohibited * without written permission from Valve LLC. * ****/ // // hud.cpp // // implementation of CHud class // //LRC - define to help track what calls are made on changelevel, save/restore, etc //#define ENGINE_DEBUG #include "hud.h" #include "cl_util.h" #include #include #include "parsemsg.h" #include "hud_servers.h" //#include "bumpmap.h" #include "demo.h" #include "demo_api.h" cvar_t *hud_textmode; float g_hud_text_color[3]; extern client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ); extern cvar_t *sensitivity; cvar_t *cl_lw = NULL; cvar_t *cl_rollangle; cvar_t *cl_rollspeed; void ShutdownInput( void ); //DECLARE_MESSAGE( m_Logo, Logo ) int __MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_Logo( pszName, iSize, pbuf ); } //DECLARE_MESSAGE( m_Logo, Logo ) //LRC int __MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf) { return gHUD.MsgFunc_HUDColor(pszName, iSize, pbuf ); } //LRC int __MsgFunc_SetFog(const char *pszName, int iSize, void *pbuf) { gHUD.MsgFunc_SetFog( pszName, iSize, pbuf ); return 1; } //LRC int __MsgFunc_KeyedDLight(const char *pszName, int iSize, void *pbuf) { gHUD.MsgFunc_KeyedDLight( pszName, iSize, pbuf ); return 1; } //LRC int __MsgFunc_AddShine(const char *pszName, int iSize, void *pbuf) { gHUD.MsgFunc_AddShine( pszName, iSize, pbuf ); return 1; } //LRC int __MsgFunc_SetSky(const char *pszName, int iSize, void *pbuf) { gHUD.MsgFunc_SetSky( pszName, iSize, pbuf ); return 1; } int __MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf ) { #ifdef ENGINE_DEBUG CONPRINT("## ResetHUD\n"); #endif return gHUD.MsgFunc_ResetHUD( pszName, iSize, pbuf ); } int __MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) { #ifdef ENGINE_DEBUG CONPRINT("## InitHUD\n"); #endif gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); return 1; } int __MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) { gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); return 1; } int __MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); } int __MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); } int __MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); } int __MsgFunc_PlayMP3( const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_PlayMP3( pszName, iSize, pbuf ); } int __MsgFunc_BumpLight( const char *pszName, int iSize, void *pbuf ) { /* float rad, strength; Vector pos, col; int moveWithEnt; bool enabled; char* targetname; bool moveWithExtraInfo = false; Vector moveWithPos, moveWithAngles; int style; BEGIN_READ( pbuf, iSize ); int msgtype = READ_BYTE(); if( msgtype == 0 ) { // create a new light targetname = READ_STRING(); pos.x = READ_COORD(); pos.y = READ_COORD(); pos.z = READ_COORD(); rad = READ_COORD(); strength = READ_COORD(); col.x = READ_BYTE() / 255.0f; col.y = READ_BYTE() / 255.0f; col.z = READ_BYTE() / 255.0f; style = READ_BYTE(); enabled = ( READ_BYTE() ? true : false ); moveWithEnt = READ_SHORT(); if( moveWithEnt != -1 && READ_BYTE() ) { moveWithPos.x = READ_COORD(); moveWithPos.y = READ_COORD(); moveWithPos.z = READ_COORD(); moveWithAngles.x = READ_ANGLE(); moveWithAngles.y = READ_ANGLE(); moveWithAngles.z = READ_ANGLE(); moveWithExtraInfo = true; } g_BumpmapMgr.AddLight( targetname, pos, col, strength, rad, enabled, style, moveWithEnt, moveWithExtraInfo, moveWithPos, moveWithAngles ); } else if( msgtype == 1 ) { // set the enabled/disabled state of an existing one targetname = READ_STRING(); enabled = ( READ_BYTE() ? true : false ); g_BumpmapMgr.EnableLight( targetname, enabled ); } else { gEngfuncs.Con_Printf( "BUMPMAPPING: Bogus bump light message type: %i\n", msgtype ); // Totally bogus, dude. } */ return 1; } // TFFree Command Menu void __CmdFunc_OpenCommandMenu( void ) { } // TFC "special" command void __CmdFunc_InputPlayerSpecial( void ) { } void __CmdFunc_CloseCommandMenu( void ) { } void __CmdFunc_ForceCloseCommandMenu( void ) { } void __CmdFunc_ToggleServerBrowser( void ) { } void __CmdFunc_StopMP3( void ) { if( !IsXashFWGS() && gEngfuncs.pfnGetCvarPointer( "gl_overbright" ) ) gEngfuncs.pfnClientCmd( "mp3 stop\n" ); else gEngfuncs.pfnPrimeMusicStream( 0, 0 ); } // TFFree Command Menu Message Handlers int __MsgFunc_ValClass( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_TeamNames( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_Feign( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_Detpack( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_VGUIMenu( const char *pszName, int iSize, void *pbuf ) { return 0; } /* int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) { return 0; } */ int __MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) { return 0; } /* int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf) { return 0; } int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf) { return 0; } int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf) { return 0; } */ int __MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ) { return 0; } int __MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ) { return 0; } // This is called every time the DLL is loaded void CHud::Init( void ) { #ifdef ENGINE_DEBUG CONPRINT("## CHud::Init\n"); #endif HOOK_MESSAGE( Logo ); HOOK_MESSAGE( ResetHUD ); HOOK_MESSAGE( GameMode ); HOOK_MESSAGE( InitHUD ); HOOK_MESSAGE( ViewMode ); HOOK_MESSAGE( SetFOV ); HOOK_MESSAGE( Concuss ); HOOK_MESSAGE( HUDColor ); //LRC HOOK_MESSAGE( SetFog ); //LRC HOOK_MESSAGE( KeyedDLight ); //LRC HOOK_MESSAGE( AddShine ); //LRC HOOK_MESSAGE( SetSky ); //LRC //KILLAR: MP3 // if( gMP3.Initialize() ) // { HOOK_MESSAGE( PlayMP3 ); HOOK_COMMAND( "stopaudio", StopMP3 ); // } // TFFree CommandMenu HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); HOOK_COMMAND( "special", InputPlayerSpecial ); HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); HOOK_MESSAGE( ValClass ); HOOK_MESSAGE( TeamNames ); HOOK_MESSAGE( Feign ); HOOK_MESSAGE( Detpack ); //HOOK_MESSAGE( MOTD ); HOOK_MESSAGE( BuildSt ); HOOK_MESSAGE( RandomPC ); HOOK_MESSAGE( ServerName ); //HOOK_MESSAGE( ScoreInfo ); //HOOK_MESSAGE( TeamScore ); //HOOK_MESSAGE( TeamInfo ); HOOK_MESSAGE( Spectator ); HOOK_MESSAGE( AllowSpec ); HOOK_MESSAGE( BumpLight ); // VGUI Menus HOOK_MESSAGE( VGUIMenu ); CVAR_CREATE( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch CVAR_CREATE( "hud_takesshots", "0", FCVAR_ARCHIVE ); // controls whether or not to automatically take screenshots at the end of a round hud_textmode = CVAR_CREATE ( "hud_textmode", "0", FCVAR_ARCHIVE ); // start glow effect --FragBait0 // CVAR_CREATE( "r_glow", "0", FCVAR_ARCHIVE ); // CVAR_CREATE( "r_glowmode", "0", FCVAR_ARCHIVE ); //AJH this is now redundant // CVAR_CREATE( "r_glowstrength", "1", FCVAR_ARCHIVE ); // CVAR_CREATE( "r_glowblur", "4", FCVAR_ARCHIVE ); // CVAR_CREATE( "r_glowdark", "2", FCVAR_ARCHIVE ); // CVAR_CREATE( "r_shadows", "0", FCVAR_ARCHIVE ); // end glow effect //viewEntityIndex = 0; // trigger_viewset stuff //viewFlags = 0; m_iLogo = 0; m_iFOV = 0; //numMirrors = 0; m_iHUDColor = 0x00FF0000; //255,0,0 -- LRC CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", FCVAR_ARCHIVE ); CVAR_CREATE( "cl_autowepswitch", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); default_fov = CVAR_CREATE( "default_fov", "90", FCVAR_ARCHIVE ); m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); m_pSpriteList = NULL; m_pShinySurface = NULL; //LRC // Clear any old HUD list if( m_pHudList ) { HUDLIST *pList; while ( m_pHudList ) { pList = m_pHudList; m_pHudList = m_pHudList->pNext; free( pList ); } m_pHudList = NULL; } // In case we get messages before the first update -- time will be valid m_flTime = 1.0; m_iNoConsolePrint = 0; m_Ammo.Init(); m_Health.Init(); m_SayText.Init(); m_Spectator.Init(); m_Geiger.Init(); m_Train.Init(); m_Battery.Init(); m_Flash.Init(); m_Message.Init(); m_StatusBar.Init(); m_DeathNotice.Init(); m_AmmoSecondary.Init(); m_TextMessage.Init(); m_StatusIcons.Init(); m_MOTD.Init(); m_Scoreboard.Init(); m_Particle.Init(); // (LRC) -- 30/08/02 November235: Particles to Order m_Menu.Init(); // advanced NVG //m_NVG.Init(); // advanced NVG MsgFunc_ResetHUD( 0, 0, NULL ); cl_rollangle = gEngfuncs.pfnRegisterVariable ( "cl_rollangle", "0.65", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); cl_rollspeed = gEngfuncs.pfnRegisterVariable ( "cl_rollspeed", "300", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); } // CHud destructor // cleans up memory allocated for m_rg* arrays CHud::~CHud() { #ifdef ENGINE_DEBUG CONPRINT("## CHud::destructor\n"); #endif delete[] m_rghSprites; delete[] m_rgrcRects; delete[] m_rgszSpriteNames; //gMP3.Shutdown(); //LRC - clear all shiny surfaces if( m_pShinySurface ) { delete m_pShinySurface; m_pShinySurface = NULL; } if( m_pHudList ) { HUDLIST *pList; while( m_pHudList ) { pList = m_pHudList; m_pHudList = m_pHudList->pNext; free( pList ); } m_pHudList = NULL; } } // GetSpriteIndex() // searches through the sprite list loaded from hud.txt for a name matching SpriteName // returns an index into the gHUD.m_rghSprites[] array // returns 0 if sprite not found int CHud::GetSpriteIndex( const char *SpriteName ) { // look through the loaded sprite name list for SpriteName for( int i = 0; i < m_iSpriteCount; i++ ) { if( strncmp( SpriteName, m_rgszSpriteNames + ( i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) return i; } return -1; // invalid sprite } void CHud::VidInit( void ) { #ifdef ENGINE_DEBUG CONPRINT("## CHud::VidInit\n"); #endif int j; m_scrinfo.iSize = sizeof(m_scrinfo); GetScreenInfo( &m_scrinfo ); // ---------- // Load Sprites // --------- // m_hsprFont = LoadSprite("sprites/%d_font.spr"); m_hsprLogo = 0; m_hsprCursor = 0; //numMirrors = 0; // LRC - clear all shiny surfaces if( m_pShinySurface ) { delete m_pShinySurface; m_pShinySurface = NULL; } if( ScreenWidth < 640 ) m_iRes = 320; else m_iRes = 640; // Only load this once if( !m_pSpriteList ) { // we need to load the hud.txt, and all sprites within m_pSpriteList = SPR_GetList( "sprites/hud.txt", &m_iSpriteCountAllRes ); if( m_pSpriteList ) { // count the number of sprites of the appropriate res m_iSpriteCount = 0; client_sprite_t *p = m_pSpriteList; for( j = 0; j < m_iSpriteCountAllRes; j++ ) { if( p->iRes == m_iRes ) m_iSpriteCount++; p++; } // allocated memory for sprite handle arrays m_rghSprites = new HSPRITE[m_iSpriteCount]; m_rgrcRects = new wrect_t[m_iSpriteCount]; m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; p = m_pSpriteList; int index = 0; for( j = 0; j < m_iSpriteCountAllRes; j++ ) { if( p->iRes == m_iRes ) { char sz[256]; sprintf( sz, "sprites/%s.spr", p->szSprite ); m_rghSprites[index] = SPR_Load( sz ); m_rgrcRects[index] = p->rc; strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); index++; } p++; } } } else { // we have already have loaded the sprite reference from hud.txt, but // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) client_sprite_t *p = m_pSpriteList; // count the number of sprites of the appropriate res m_iSpriteCount = 0; for( j = 0; j < m_iSpriteCountAllRes; j++ ) { if( p->iRes == m_iRes ) m_iSpriteCount++; p++; } delete[] m_rghSprites; delete[] m_rgrcRects; delete[] m_rgszSpriteNames; // allocated memory for sprite handle arrays m_rghSprites = new HSPRITE[m_iSpriteCount]; m_rgrcRects = new wrect_t[m_iSpriteCount]; m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; p = m_pSpriteList; int index = 0; for( j = 0; j < m_iSpriteCountAllRes; j++ ) { if( p->iRes == m_iRes ) { char sz[256]; sprintf( sz, "sprites/%s.spr", p->szSprite ); m_rghSprites[index] = SPR_Load( sz ); m_rgrcRects[index] = p->rc; strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); index++; } p++; } } // assumption: number_1, number_2, etc, are all listed and loaded sequentially m_HUD_number_0 = GetSpriteIndex( "number_0" ); if( m_HUD_number_0 == -1 ) { const char *msg = "There is something wrong with your game data! Please, reinstall\n"; if( HUD_MessageBox( msg ) ) { gEngfuncs.pfnClientCmd( "quit\n" ); } return; } m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; m_Ammo.VidInit(); m_Health.VidInit(); m_Spectator.VidInit(); m_Geiger.VidInit(); m_Train.VidInit(); m_Battery.VidInit(); m_Flash.VidInit(); m_Message.VidInit(); m_StatusBar.VidInit(); m_DeathNotice.VidInit(); m_SayText.VidInit(); m_Menu.VidInit(); m_AmmoSecondary.VidInit(); m_TextMessage.VidInit(); m_StatusIcons.VidInit(); // advanced NVG // m_NVG.VidInit(); // advanced NVG m_Scoreboard.VidInit(); m_MOTD.VidInit(); m_Particle.VidInit(); // (LRC) -- 30/08/02 November235: Particles to Order } int CHud::MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); // update Train data m_iLogo = READ_BYTE(); return 1; } //LRC int CHud::MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf) { BEGIN_READ( pbuf, iSize ); m_iHUDColor = READ_LONG(); return 1; } float g_lastFOV = 0.0; /* ============ COM_FileBase ============ */ // Extracts the base name of a file (no path, no extension, assumes '/' as path separator) void COM_FileBase ( const char *in, char *out ) { int len, start, end; len = strlen( in ); // scan backward for '.' end = len - 1; while( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) end--; if( in[end] != '.' ) // no '.', copy to end end = len - 1; else end--; // Found ',', copy to left of '.' // Scan backward for '/' start = len - 1; while( start >= 0 && in[start] != '/' && in[start] != '\\' ) start--; if( in[start] != '/' && in[start] != '\\' ) start = 0; else start++; // Length of new sting len = end - start + 1; // Copy partial string strncpy( out, &in[start], len ); // Terminate it out[len] = 0; } /* ================= HUD_IsGame ================= */ int HUD_IsGame( const char *game ) { const char *gamedir; char gd[1024]; gamedir = gEngfuncs.pfnGetGameDirectory(); if( gamedir && gamedir[0] ) { COM_FileBase( gamedir, gd ); if( !stricmp( gd, game ) ) return 1; } return 0; } /* ===================== HUD_GetFOV Returns last FOV ===================== */ float HUD_GetFOV( void ) { if( gEngfuncs.pDemoAPI->IsRecording() ) { // Write it int i = 0; unsigned char buf[100]; // Active *(float *)&buf[i] = g_lastFOV; i += sizeof(float); Demo_WriteBuffer( TYPE_ZOOM, i, buf ); } if( gEngfuncs.pDemoAPI->IsPlayingback() ) { g_lastFOV = g_demozoom; } return g_lastFOV; } int CHud::MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); int newfov = READ_BYTE(); int def_fov = CVAR_GET_FLOAT( "default_fov" ); g_lastFOV = newfov; if( newfov == 0 ) { m_iFOV = def_fov; } else { m_iFOV = newfov; } // the clients fov is actually set in the client data update section of the hud // Set a new sensitivity if( m_iFOV == def_fov ) { // reset to saved sensitivity m_flMouseSensitivity = 0; } else { // set a new sensitivity that is proportional to the change from the FOV default m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); } return 1; } void CHud::AddHudElem( CHudBase *phudelem ) { HUDLIST *pdl, *ptemp; //phudelem->Think(); if( !phudelem ) return; pdl = (HUDLIST *)malloc( sizeof(HUDLIST) ); if( !pdl ) return; memset( pdl, 0, sizeof(HUDLIST) ); pdl->p = phudelem; if( !m_pHudList ) { m_pHudList = pdl; return; } ptemp = m_pHudList; while( ptemp->pNext ) ptemp = ptemp->pNext; ptemp->pNext = pdl; } float CHud::GetSensitivity( void ) { return m_flMouseSensitivity; }