cs16-client-legacy/cl_dll/hud/hud.cpp

501 lines
12 KiB
C++
Raw Normal View History

2016-03-05 20:29:55 +01:00
/***
*
* 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
//
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "parsemsg.h"
#include "demo.h"
#include "demo_api.h"
#include "vgui_parser.h"
#include "rain.h"
#include "camera.h"
2016-03-05 20:29:55 +01:00
2016-07-03 20:43:32 +02:00
#include <new>
#include <unordered_map>
2016-03-05 20:29:55 +01:00
extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount);
wrect_t nullrc = { 0, 0, 0, 0 };
float g_lastFOV = 0.0;
const char *sPlayerModelFiles[12] =
2016-03-05 20:29:55 +01:00
{
"models/player.mdl",
"models/player/leet/leet.mdl", // t
"models/player/gign/gign.mdl", // ct
"models/player/vip/vip.mdl", //ct
"models/player/gsg9/gsg9.mdl", // ct
"models/player/guerilla/guerilla.mdl", // t
"models/player/arctic/arctic.mdl", // t
"models/player/sas/sas.mdl", // ct
"models/player/terror/terror.mdl", // t
"models/player/urban/urban.mdl", // ct
"models/player/spetsnaz/spetsnaz.mdl", // ct
"models/player/militia/militia.mdl" // t
};
#define GHUD_DECLARE_MESSAGE(x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf ) { return gHUD.MsgFunc_##x(pszName, iSize, pbuf); }
GHUD_DECLARE_MESSAGE(Logo)
GHUD_DECLARE_MESSAGE(SetFOV)
GHUD_DECLARE_MESSAGE(InitHUD)
GHUD_DECLARE_MESSAGE(Concuss)
GHUD_DECLARE_MESSAGE(ResetHUD)
GHUD_DECLARE_MESSAGE(ViewMode)
GHUD_DECLARE_MESSAGE(GameMode)
GHUD_DECLARE_MESSAGE(ReceiveW)
GHUD_DECLARE_MESSAGE(BombDrop)
GHUD_DECLARE_MESSAGE(HostageK)
GHUD_DECLARE_MESSAGE(BombPickup)
GHUD_DECLARE_MESSAGE(HostagePos)
GHUD_DECLARE_MESSAGE(ShadowIdx)
void __CmdFunc_InputCommandSpecial()
{
2016-04-16 21:02:14 +02:00
#ifdef _CS16CLIENT_ALLOW_SPECIAL_SCRIPTING
2016-03-05 20:29:55 +01:00
gEngfuncs.pfnClientCmd("_special");
#endif
2016-04-16 21:02:14 +02:00
}
2016-03-05 20:29:55 +01:00
// This is called every time the DLL is loaded
void CHud :: Init( void )
{
HOOK_COMMAND( "special", InputCommandSpecial );
HOOK_MESSAGE( Logo );
HOOK_MESSAGE( ResetHUD );
HOOK_MESSAGE( GameMode );
HOOK_MESSAGE( InitHUD );
HOOK_MESSAGE( ViewMode );
HOOK_MESSAGE( SetFOV );
HOOK_MESSAGE( Concuss );
HOOK_MESSAGE( ReceiveW );
HOOK_MESSAGE( BombDrop );
HOOK_MESSAGE( BombPickup );
HOOK_MESSAGE( HostagePos );
HOOK_MESSAGE( HostageK );
HOOK_MESSAGE( ShadowIdx );
CVAR_CREATE( "_vgui_menus", "1", FCVAR_ARCHIVE | FCVAR_USERINFO );
2016-03-05 20:29:55 +01:00
CVAR_CREATE( "_cl_autowepswitch", "1", FCVAR_ARCHIVE | FCVAR_USERINFO );
CVAR_CREATE( "_ah", "0", FCVAR_ARCHIVE | FCVAR_USERINFO );
2016-03-05 20:29:55 +01:00
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 );
cl_righthand = CVAR_CREATE( "hand", "1", FCVAR_ARCHIVE );
cl_weather = CVAR_CREATE( "cl_weather", "1", FCVAR_ARCHIVE );
2016-04-16 21:02:14 +02:00
cl_minmodels = CVAR_CREATE( "cl_minmodels", "0", FCVAR_ARCHIVE );
2016-03-05 20:29:55 +01:00
cl_min_t = CVAR_CREATE( "cl_min_t", "1", FCVAR_ARCHIVE );
2016-04-16 21:02:14 +02:00
cl_min_ct = CVAR_CREATE( "cl_min_ct", "2", FCVAR_ARCHIVE );
2016-03-05 20:29:55 +01:00
cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" );
cl_predict = gEngfuncs.pfnGetCvarPointer( "cl_predict" );
#ifdef __ANDROID__
cl_android_force_defaults = CVAR_CREATE( "cl_android_force_defaults", "1", FCVAR_ARCHIVE );
#endif
2016-03-05 20:29:55 +01:00
cl_shadows = CVAR_CREATE( "cl_shadows", "1", FCVAR_ARCHIVE );
default_fov = CVAR_CREATE( "default_fov", "90", 0 );
m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE );
2016-04-16 21:02:14 +02:00
fastsprites = CVAR_CREATE( "fastsprites", "0", FCVAR_ARCHIVE );
cl_weapon_sparks = CVAR_CREATE( "cl_weapon_sparks", "1", FCVAR_ARCHIVE );
cl_weapon_wallpuff = CVAR_CREATE( "cl_weapon_wallpuff", "1", FCVAR_ARCHIVE );
2016-07-03 20:43:32 +02:00
zoom_sens_ratio = CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 );
2016-03-05 20:29:55 +01:00
m_iLogo = 0;
m_iFOV = 0;
m_pSpriteList = NULL;
// Clear any old HUD list
2016-07-03 20:43:32 +02:00
for( HUDLIST *pList = m_pHudList; pList; pList = m_pHudList )
2016-03-05 20:29:55 +01:00
{
2016-07-03 20:43:32 +02:00
m_pHudList = m_pHudList->pNext;
delete pList;
2016-03-05 20:29:55 +01:00
}
2016-07-03 20:43:32 +02:00
m_pHudList = NULL;
2016-03-05 20:29:55 +01:00
// In case we get messages before the first update -- time will be valid
m_flTime = 1.0;
m_iNoConsolePrint = 0;
2016-03-20 00:40:36 +01:00
Localize_Init();
2016-03-05 20:29:55 +01:00
// fullscreen overlays
m_SniperScope.Init();
m_NVG.Init();
m_SpectatorGui.Init();
2016-03-05 20:29:55 +01:00
// Game HUD things
m_Ammo.Init();
m_Health.Init();
m_Radio.Init();
m_Timer.Init();
m_Money.Init();
m_AmmoSecondary.Init();
m_Train.Init();
m_Battery.Init();
m_StatusIcons.Init();
m_Radar.Init();
// chat, death notice, status bars and other
m_SayText.Init();
m_Spectator.Init();
m_Geiger.Init();
m_Flash.Init();
m_Message.Init();
m_StatusBar.Init();
m_DeathNotice.Init();
m_TextMessage.Init();
m_MOTD.Init();
// all things that have own background and must be drawn last
m_ProgressBar.Init();
m_Menu.Init();
m_Scoreboard.Init();
InitRain();
//ServersInit();
2016-04-16 21:02:14 +02:00
gEngfuncs.Cvar_SetValue( "hand", 1 );
gEngfuncs.Cvar_SetValue( "sv_skipshield", 1.0f );
#ifdef __ANDROID__
gEngfuncs.Cvar_SetValue( "hud_fastswitch", 1 );
#endif
if( g_iMobileAPIVersion )
{
static byte color[] = {255, 255, 255, 255};
gMobileAPI.pfnTouchResetDefaultButtons();
gMobileAPI.pfnTouchAddDefaultButton("_settings", "touch_defaults/settings.tga", "menu_touchoptions",
0.4, 0.4, 0.6, 0.6, color, 0, 1.0f, TOUCH_FL_NOEDIT | TOUCH_FL_DEF_SHOW );
gEngfuncs.pfnClientCmd("alias touch_loaddefaults menu_touchoptions");
}
2016-03-05 20:29:55 +01:00
MsgFunc_ResetHUD(0, 0, NULL );
}
// CHud destructor
// cleans up memory allocated for m_rg* arrays
CHud :: ~CHud()
{
delete [] m_rghSprites;
delete [] m_rgrcRects;
delete [] m_rgszSpriteNames;
2016-07-03 20:43:32 +02:00
// Clear any old HUD list
for( HUDLIST *pList = m_pHudList; pList; pList = m_pHudList )
2016-03-05 20:29:55 +01:00
{
2016-07-03 20:43:32 +02:00
m_pHudList = m_pHudList->pNext;
delete pList;
2016-03-05 20:29:55 +01:00
}
2016-07-03 20:43:32 +02:00
m_pHudList = NULL;
2016-03-05 20:29:55 +01:00
}
void CHud :: VidInit( void )
{
m_scrinfo.iSize = sizeof(m_scrinfo);
GetScreenInfo(&m_scrinfo);
m_truescrinfo.iWidth = CVAR_GET_FLOAT("width");
m_truescrinfo.iHeight = CVAR_GET_FLOAT("height");
// ----------
// Load Sprites
// ---------
// m_hsprFont = LoadSprite("sprites/%d_font.spr");
m_hsprLogo = 0;
2016-03-17 23:45:34 +01:00
if( ScreenWidth < 640 && CVAR_GET_FLOAT("hud_scale") <= 1.0f )
{
gEngfuncs.Cvar_SetValue("hud_scale", ScreenWidth / 640.0f );
}
else if( CVAR_GET_FLOAT("hud_scale") < 1.0f )
{
gEngfuncs.Cvar_SetValue("hud_scale", 1.0f );
}
GetScreenInfo(&m_scrinfo);
2016-04-16 21:02:14 +02:00
2016-03-17 23:45:34 +01:00
m_iRes = 640;
2016-03-05 20:29:55 +01:00
// 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;
int j;
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];
2016-07-03 20:43:32 +02:00
m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH];;
2016-03-05 20:29:55 +01:00
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;
int index = 0;
for ( int 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);
index++;
}
p++;
}
}
// assumption: number_1, number_2, etc, are all listed and loaded sequentially
m_HUD_number_0 = GetSpriteIndex( "number_0" );
m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top;
m_hGasPuff = SPR_Load("sprites/gas_puff_01.spr");
2016-03-05 20:29:55 +01:00
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();
m_Scoreboard.VidInit();
m_MOTD.VidInit();
m_Timer.VidInit();
m_Money.VidInit();
m_ProgressBar.VidInit();
m_SniperScope.VidInit();
m_Radar.VidInit();
m_SpectatorGui.VidInit();
2016-03-05 20:29:55 +01:00
}
void CHud::Shutdown( void )
{
for( HUDLIST *pList = m_pHudList; pList; pList = m_pHudList->pNext )
{
pList->p->Shutdown();
}
}
2016-03-05 20:29:55 +01:00
int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf)
{
BufferReader reader( pszName, pbuf, iSize );
2016-03-05 20:29:55 +01:00
// update Train data
m_iLogo = reader.ReadByte();
2016-03-05 20:29:55 +01:00
return 1;
}
/*
============
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
2016-07-03 20:43:32 +02:00
unsigned char buf[ sizeof(float) ];
2016-03-05 20:29:55 +01:00
// Active
2016-07-03 20:43:32 +02:00
*( float * )&buf = g_lastFOV;
2016-03-05 20:29:55 +01:00
2016-07-03 20:43:32 +02:00
Demo_WriteBuffer( TYPE_ZOOM, sizeof(float), buf );
2016-03-05 20:29:55 +01:00
}
if ( gEngfuncs.pDemoAPI->IsPlayingback() )
{
g_lastFOV = g_demozoom;
}
return g_lastFOV;
}
int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
{
//Weapon prediction already takes care of changing the fog. ( g_lastFOV ).
#if 0 // VALVEWHY: original client checks for "tfc" here.
2016-03-05 20:29:55 +01:00
if ( cl_lw && cl_lw->value )
return 1;
#endif
BufferReader reader( pszName, pbuf, iSize );
int newfov = reader.ReadByte();
int def_fov = default_fov->value;
2016-03-05 20:29:55 +01:00
g_lastFOV = newfov;
2016-07-03 20:43:32 +02:00
m_iFOV = newfov ? newfov : def_fov;
2016-03-05 20:29:55 +01:00
// the clients fov is actually set in the client data update section of the hud
2016-07-03 20:43:32 +02:00
if ( m_iFOV == def_fov ) // reset to saved sensitivity
2016-03-05 20:29:55 +01:00
m_flMouseSensitivity = 0;
2016-07-03 20:43:32 +02:00
else // set a new sensitivity that is proportional to the change from the FOV default
m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * zoom_sens_ratio->value;
2016-03-05 20:29:55 +01:00
return 1;
}
void CHud::AddHudElem(CHudBase *phudelem)
{
2016-07-03 20:43:32 +02:00
assert( phudelem );
2016-03-05 20:29:55 +01:00
2016-07-03 20:43:32 +02:00
HUDLIST *pdl, *ptemp;
2016-03-05 20:29:55 +01:00
2016-07-03 20:43:32 +02:00
pdl = new(std::nothrow) HUDLIST;
if( !pdl )
{
ConsolePrint( "Cannot allocate memory!\n" );
2016-03-05 20:29:55 +01:00
return;
2016-07-03 20:43:32 +02:00
}
2016-03-05 20:29:55 +01:00
pdl->p = phudelem;
2016-07-03 20:43:32 +02:00
pdl->pNext = NULL;
2016-03-05 20:29:55 +01:00
if (!m_pHudList)
{
m_pHudList = pdl;
return;
}
2016-07-03 20:43:32 +02:00
// find last
for( ptemp = m_pHudList; ptemp->pNext; ptemp = ptemp->pNext );
2016-03-05 20:29:55 +01:00
ptemp->pNext = pdl;
}