From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/cdll_util.cpp | 2642 +++++++++++++++++++------------------- 1 file changed, 1321 insertions(+), 1321 deletions(-) (limited to 'mp/src/game/client/cdll_util.cpp') diff --git a/mp/src/game/client/cdll_util.cpp b/mp/src/game/client/cdll_util.cpp index 0a930647..4e877530 100644 --- a/mp/src/game/client/cdll_util.cpp +++ b/mp/src/game/client/cdll_util.cpp @@ -1,1321 +1,1321 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $Workfile: $ -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include -#include "hud.h" -#include "itextmessage.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/itexture.h" -#include "materialsystem/imaterialsystem.h" -#include "imovehelper.h" -#include "checksum_crc.h" -#include "decals.h" -#include "iefx.h" -#include "view_scene.h" -#include "filesystem.h" -#include "model_types.h" -#include "engine/IEngineTrace.h" -#include "engine/ivmodelinfo.h" -#include "c_te_effect_dispatch.h" -#include -#include -#include -#include "view.h" -#include "ixboxsystem.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -ConVar localplayer_visionflags( "localplayer_visionflags", "0", FCVAR_DEVELOPMENTONLY ); - -//----------------------------------------------------------------------------- -// ConVars -//----------------------------------------------------------------------------- -#ifdef _DEBUG - -ConVar r_FadeProps( "r_FadeProps", "1" ); - -#endif -bool g_MakingDevShots = false; -extern ConVar cl_leveloverview; - -//----------------------------------------------------------------------------- -// Purpose: Performs a var args printf into a static return buffer -// Input : *format - -// ... - -// Output : char -//----------------------------------------------------------------------------- -char *VarArgs( const char *format, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, format); - Q_vsnprintf (string, sizeof( string ), format,argptr); - va_end (argptr); - - return string; -} - -//----------------------------------------------------------------------------- -// Purpose: Returns true if the entity index corresponds to a player slot -// Input : index - -// Output : bool -//----------------------------------------------------------------------------- -bool IsPlayerIndex( int index ) -{ - return ( index >= 1 && index <= gpGlobals->maxClients ) ? true : false; -} - -int GetLocalPlayerIndex( void ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - return player->entindex(); - else - return 0; // game not started yet -} - -int GetLocalPlayerVisionFilterFlags( bool bWeaponsCheck /*= false */ ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - return player->GetVisionFilterFlags( bWeaponsCheck ); - else - return 0; -} - -bool IsLocalPlayerUsingVisionFilterFlags( int nFlags, bool bWeaponsCheck /* = false */ ) -{ - int nLocalPlayerFlags = GetLocalPlayerVisionFilterFlags( bWeaponsCheck ); - - if ( !bWeaponsCheck ) - { - // We can only modify the RJ flags with normal checks that won't take the forced kill cam flags that can happen in weapon checks - int nRJShaderFlags = nLocalPlayerFlags; - if ( nRJShaderFlags != 0 && GameRules() && !GameRules()->AllowMapVisionFilterShaders() ) - { - nRJShaderFlags = 0; - } - - if ( nRJShaderFlags != localplayer_visionflags.GetInt() ) - { - localplayer_visionflags.SetValue( nRJShaderFlags ); - } - } - - return ( nLocalPlayerFlags & nFlags ) == nFlags; -} - -bool IsLocalPlayerSpectator( void ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - return player->IsObserver(); - else - return false; // game not started yet -} - -int GetSpectatorMode( void ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - return player->GetObserverMode(); - else - return OBS_MODE_NONE; // game not started yet -} - -int GetSpectatorTarget( void ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - { - CBaseEntity * target = player->GetObserverTarget(); - - if ( target ) - return target->entindex(); - else - return 0; - } - else - { - return 0; // game not started yet - } -} - -int GetLocalPlayerTeam( void ) -{ - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - - if ( pPlayer ) - return pPlayer->GetTeamNumber(); - else - return TEAM_UNASSIGNED; -} - -//----------------------------------------------------------------------------- -// Purpose: Convert angles to -180 t 180 range -// Input : angles - -//----------------------------------------------------------------------------- -void NormalizeAngles( QAngle& angles ) -{ - int i; - - // Normalize angles to -180 to 180 range - for ( i = 0; i < 3; i++ ) - { - if ( angles[i] > 180.0 ) - { - angles[i] -= 360.0; - } - else if ( angles[i] < -180.0 ) - { - angles[i] += 360.0; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Interpolate Euler angles using quaternions to avoid singularities -// Input : start - -// end - -// output - -// frac - -//----------------------------------------------------------------------------- -void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac ) -{ - Quaternion src, dest; - - // Convert to quaternions - AngleQuaternion( start, src ); - AngleQuaternion( end, dest ); - - Quaternion result; - - // Slerp - QuaternionSlerp( src, dest, frac, result ); - - // Convert to euler - QuaternionAngles( result, output ); -} - -//----------------------------------------------------------------------------- -// Purpose: Simple linear interpolation -// Input : frac - -// src - -// dest - -// output - -//----------------------------------------------------------------------------- -void InterpolateVector( float frac, const Vector& src, const Vector& dest, Vector& output ) -{ - int i; - - for ( i = 0; i < 3; i++ ) - { - output[ i ] = src[ i ] + frac * ( dest[ i ] - src[ i ] ); - } -} - -client_textmessage_t *TextMessageGet( const char *pName ) -{ - return engine->TextMessageGet( pName ); -} - -//----------------------------------------------------------------------------- -// Purpose: ScreenHeight returns the height of the screen, in pixels -// Output : int -//----------------------------------------------------------------------------- -int ScreenHeight( void ) -{ - int w, h; - GetHudSize( w, h ); - return h; -} - -//----------------------------------------------------------------------------- -// Purpose: ScreenWidth returns the width of the screen, in pixels -// Output : int -//----------------------------------------------------------------------------- -int ScreenWidth( void ) -{ - int w, h; - GetHudSize( w, h ); - return w; -} - -//----------------------------------------------------------------------------- -// Purpose: Return the difference between two angles -// Input : destAngle - -// srcAngle - -// Output : float -//----------------------------------------------------------------------------- -float UTIL_AngleDiff( float destAngle, float srcAngle ) -{ - float delta; - - delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) - { - while ( delta >= 180 ) - delta -= 360; - } - else - { - while ( delta <= -180 ) - delta += 360; - } - return delta; -} - - -float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) -{ - Vector midUp = position; - midUp.z = minz; - - if ( !(UTIL_PointContents(midUp) & MASK_WATER) ) - return minz; - - midUp.z = maxz; - if ( UTIL_PointContents(midUp) & MASK_WATER ) - return maxz; - - float diff = maxz - minz; - while (diff > 1.0) - { - midUp.z = minz + diff/2.0; - if ( UTIL_PointContents(midUp) & MASK_WATER ) - { - minz = midUp.z; - } - else - { - maxz = midUp.z; - } - diff = maxz - minz; - } - - return midUp.z; -} - -void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count ) -{ - Vector mid = (mins + maxs) * 0.5; - - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); - flHeight = flHeight - mins.z; - - CPASFilter filter( mid ); - - int bubbles = modelinfo->GetModelIndex( "sprites/bubble.vmt" ); - - te->Bubbles( filter, 0.0, - &mins, &maxs, flHeight, bubbles, count, 8.0 ); -} - -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake ) -{ - // Nothing for now -} - -char TEXTURETYPE_Find( trace_t *ptr ) -{ - surfacedata_t *psurfaceData = physprops->GetSurfaceData( ptr->surface.surfaceProps ); - - return psurfaceData->game.material; -} - -//----------------------------------------------------------------------------- -// Purpose: Make a tracer effect -//----------------------------------------------------------------------------- -void UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex, int iAttachment, float flVelocity, bool bWhiz, char *pCustomTracerName ) -{ - CEffectData data; - data.m_vStart = vecStart; - data.m_vOrigin = vecEnd; - data.m_hEntity = ClientEntityList().EntIndexToHandle( iEntIndex ); - data.m_flScale = flVelocity; - - // Flags - if ( bWhiz ) - { - data.m_fFlags |= TRACER_FLAG_WHIZ; - } - if ( iAttachment != TRACER_DONT_USE_ATTACHMENT ) - { - data.m_fFlags |= TRACER_FLAG_USEATTACHMENT; - // Stomp the start, since it's not going to be used anyway - data.m_vStart[0] = iAttachment; - } - - // Fire it off - if ( pCustomTracerName ) - { - DispatchEffect( pCustomTracerName, data ); - } - else - { - DispatchEffect( "Tracer", data ); - } -} - - -//------------------------------------------------------------------------------ -// Purpose : Creates both an decal and any associated impact effects (such -// as flecks) for the given iDamageType and the trace's end position -// Input : -// Output : -//------------------------------------------------------------------------------ -void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) -{ - C_BaseEntity *pEntity = pTrace->m_pEnt; - - // Is the entity valid, is the surface sky? - if ( !pEntity || (pTrace->surface.flags & SURF_SKY) ) - return; - - if (pTrace->fraction == 1.0) - return; - - // don't decal nodraw surfaces - if ( pTrace->surface.flags & SURF_NODRAW ) - return; - - pEntity->ImpactTrace( pTrace, iDamageType, pCustomImpactName ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int UTIL_PrecacheDecal( const char *name, bool preload ) -{ - return effects->Draw_DecalIndexFromName( (char*)name ); -} - -extern short g_sModelIndexSmoke; - -void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ) -{ - CPVSFilter filter( origin ); - te->Smoke( filter, 0.0f, &origin, g_sModelIndexSmoke, scale, framerate ); -} - -void UTIL_SetOrigin( C_BaseEntity *entity, const Vector &vecOrigin ) -{ - entity->SetLocalOrigin( vecOrigin ); -} - -//#define PRECACHE_OTHER_ONCE -// UNDONE: Do we need this to avoid doing too much of this? Measure startup times and see -#if PRECACHE_OTHER_ONCE - -#include "utlsymbol.h" -class CPrecacheOtherList : public CAutoServerSystem -{ -public: - virtual void LevelInitPreEntity(); - virtual void LevelShutdownPostEntity(); - - bool AddOrMarkPrecached( const char *pClassname ); - -private: - CUtlSymbolTable m_list; -}; - -void CPrecacheOtherList::LevelInitPreEntity() -{ - m_list.RemoveAll(); -} - -void CPrecacheOtherList::LevelShutdownPostEntity() -{ - m_list.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Purpose: mark or add -// Input : *pEntity - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CPrecacheOtherList::AddOrMarkPrecached( const char *pClassname ) -{ - CUtlSymbol sym = m_list.Find( pClassname ); - if ( sym.IsValid() ) - return false; - - m_list.AddString( pClassname ); - return true; -} - -CPrecacheOtherList g_PrecacheOtherList; -#endif - -void UTIL_PrecacheOther( const char *szClassname ) -{ -#if PRECACHE_OTHER_ONCE - // already done this one?, if not, mark as done - if ( !g_PrecacheOtherList.AddOrMarkPrecached( szClassname ) ) - return; -#endif - - // Client should only do this once entities are coming down from server!!! - // Assert( engine->IsConnected() ); - - C_BaseEntity *pEntity = CreateEntityByName( szClassname ); - if ( !pEntity ) - { - Warning( "NULL Ent in UTIL_PrecacheOther\n" ); - return; - } - - if (pEntity) - { - pEntity->Precache( ); - } - - // Bye bye - pEntity->Release(); -} - -static csurface_t g_NullSurface = { "**empty**", 0 }; -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void UTIL_SetTrace(trace_t& trace, const Ray_t& ray, C_BaseEntity *ent, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept ) -{ - trace.startsolid = (fraction == 0.0f); - trace.fraction = fraction; - VectorCopy( ray.m_Start, trace.startpos ); - VectorMA( ray.m_Start, fraction, ray.m_Delta, trace.endpos ); - VectorCopy( normal, trace.plane.normal ); - trace.plane.dist = intercept; - trace.m_pEnt = C_BaseEntity::Instance( ent ); - trace.hitgroup = hitgroup; - trace.surface = g_NullSurface; - trace.contents = contents; -} - -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of a world position in screenspace -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) -{ - Vector screen; - - // Apply the offset, if one was specified - if ( vecOffset != NULL ) - pos += *vecOffset; - - // Transform to screen space - int iFacing = ScreenTransform( pos, screen ); - iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); - iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); - - // Make sure the player's facing it - if ( iFacing ) - { - // We're actually facing away from the Target. Stomp the screen position. - iX = -640; - iY = -640; - return false; - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of a world position in HUD space -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetVectorInHudSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) -{ - Vector screen; - - // Apply the offset, if one was specified - if ( vecOffset != NULL ) - pos += *vecOffset; - - // Transform to HUD space - int iFacing = HudTransform( pos, screen ); - iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); - iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); - - // Make sure the player's facing it - if ( iFacing ) - { - // We're actually facing away from the Target. Stomp the screen position. - iX = -640; - iY = -640; - return false; - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of an entity in screenspace -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset ) -{ - return GetVectorInScreenSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); -} - -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of an entity in Vgui space -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetTargetInHudSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset ) -{ - return GetVectorInHudSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *player - -// msg_dest - -// *msg_name - -// *param1 - -// *param2 - -// *param3 - -// *param4 - -//----------------------------------------------------------------------------- -void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, const char *param1 /*= NULL*/, const char *param2 /*= NULL*/, const char *param3 /*= NULL*/, const char *param4 /*= NULL*/ ) -{ -} - -//----------------------------------------------------------------------------- -// class CFlaggedEntitiesEnum -//----------------------------------------------------------------------------- -// enumerate entities that match a set of edict flags into a static array -class CFlaggedEntitiesEnum : public IPartitionEnumerator -{ -public: - CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ); - // This gets called by the enumeration methods with each element - // that passes the test. - virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); - - int GetCount() { return m_count; } - bool AddToList( C_BaseEntity *pEntity ); - -private: - C_BaseEntity **m_pList; - int m_listMax; - int m_flagMask; - int m_count; -}; - -CFlaggedEntitiesEnum::CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ) -{ - m_pList = pList; - m_listMax = listMax; - m_flagMask = flagMask; - m_count = 0; -} - -bool CFlaggedEntitiesEnum::AddToList( C_BaseEntity *pEntity ) -{ - if ( m_count >= m_listMax ) - return false; - m_pList[m_count] = pEntity; - m_count++; - return true; -} - -IterationRetval_t CFlaggedEntitiesEnum::EnumElement( IHandleEntity *pHandleEntity ) -{ - IClientEntity *pClientEntity = cl_entitylist->GetClientEntityFromHandle( pHandleEntity->GetRefEHandle() ); - C_BaseEntity *pEntity = pClientEntity ? pClientEntity->GetBaseEntity() : NULL; - if ( pEntity ) - { - if ( m_flagMask && !(pEntity->GetFlags() & m_flagMask) ) // Does it meet the criteria? - return ITERATION_CONTINUE; - - if ( !AddToList( pEntity ) ) - return ITERATION_STOP; - } - - return ITERATION_CONTINUE; -} - -//----------------------------------------------------------------------------- -// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted -// Input : **pList - -// listMax - -// &mins - -// &maxs - -// flagMask - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_EntitiesInBox( C_BaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask, int partitionMask ) -{ - CFlaggedEntitiesEnum boxEnum( pList, listMax, flagMask ); - partition->EnumerateElementsInBox( partitionMask, mins, maxs, false, &boxEnum ); - - return boxEnum.GetCount(); - -} - -//----------------------------------------------------------------------------- -// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted -// Input : **pList - -// listMax - -// ¢er - -// radius - -// flagMask - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector ¢er, float radius, int flagMask, int partitionMask ) -{ - CFlaggedEntitiesEnum sphereEnum( pList, listMax, flagMask ); - partition->EnumerateElementsInSphere( partitionMask, center, radius, false, &sphereEnum ); - - return sphereEnum.GetCount(); - -} - -//----------------------------------------------------------------------------- -// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted -// Input : **pList - -// listMax - -// &ray - -// flagMask - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_EntitiesAlongRay( C_BaseEntity **pList, int listMax, const Ray_t &ray, int flagMask, int partitionMask ) -{ - CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask ); - partition->EnumerateElementsAlongRay( partitionMask, ray, false, &rayEnum ); - - return rayEnum.GetCount(); -} - -CEntitySphereQuery::CEntitySphereQuery( const Vector ¢er, float radius, int flagMask, int partitionMask ) -{ - m_listIndex = 0; - m_listCount = UTIL_EntitiesInSphere( m_pList, ARRAYSIZE(m_pList), center, radius, flagMask, partitionMask ); -} - -CBaseEntity *CEntitySphereQuery::GetCurrentEntity() -{ - if ( m_listIndex < m_listCount ) - return m_pList[m_listIndex]; - return NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: Slightly modified strtok. Does not modify the input string. Does -// not skip over more than one separator at a time. This allows parsing -// strings where tokens between separators may or may not be present: -// -// Door01,,,0 would be parsed as "Door01" "" "" "0" -// Door01,Open,,0 would be parsed as "Door01" "Open" "" "0" -// -// Input : token - Returns with a token, or zero length if the token was missing. -// str - String to parse. -// sep - Character to use as separator. UNDONE: allow multiple separator chars -// Output : Returns a pointer to the next token to be parsed. -//----------------------------------------------------------------------------- -const char *nexttoken(char *token, const char *str, char sep) -{ - if ((str == NULL) || (*str == '\0')) - { - *token = '\0'; - return(NULL); - } - - // - // Copy everything up to the first separator into the return buffer. - // Do not include separators in the return buffer. - // - while ((*str != sep) && (*str != '\0')) - { - *token++ = *str++; - } - *token = '\0'; - - // - // Advance the pointer unless we hit the end of the input string. - // - if (*str == '\0') - { - return(str); - } - - return(++str); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : font - -// *str - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str ) -{ - float pixels = 0; - const char *p = str; - const char *pAfter = p + 1; - const char *pBefore = "\0"; - while ( *p ) - { -#if USE_GETKERNEDCHARWIDTH - float wide, abcA; - vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); - pixels += wide; -#else - pixels += vgui::surface()->GetCharacterWidth( font, *p ); -#endif - pBefore = p; - p++; - if ( *p ) - pAfter = p + 1; - else - pAfter = "\0"; - } - return (int)ceil(pixels); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : font - -// *str - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ) -{ - float pixels = 0; - const wchar_t *p = str; - const wchar_t *pAfter = p + 1; - const wchar_t *pBefore = L"\0"; - while ( *p ) - { -#if USE_GETKERNEDCHARWIDTH - float wide, abcA; - vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); - pixels += wide; -#else - pixels += vgui::surface()->GetCharacterWidth( font, *p ); -#endif - pBefore = p; - p++; - if ( *p ) - pAfter = p + 1; - else - pAfter = L"\0"; - } - return (int)ceil(pixels); -} - -//----------------------------------------------------------------------------- -// Purpose: Scans player names -//Passes the player name to be checked in a KeyValues pointer -//with the keyname "name" -// - replaces '&' with '&&' so they will draw in the scoreboard -// - replaces '#' at the start of the name with '*' -//----------------------------------------------------------------------------- - -void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize ) -{ - Assert( newNameBufSize >= sizeof(newName[0]) ); - - int newpos = 0; - - for( const char *p=oldName; *p != 0 && newpos < newNameBufSize-1; p++ ) - { - //check for a '#' char at the beginning - if( p == oldName && *p == '#' ) - { - newName[newpos] = '*'; - newpos++; - } - else if( *p == '%' ) - { - // remove % chars - newName[newpos] = '*'; - newpos++; - } - else if( *p == '&' ) - { - //insert another & after this one - if ( newpos+2 < newNameBufSize ) - { - newName[newpos] = '&'; - newName[newpos+1] = '&'; - newpos+=2; - } - } - else - { - newName[newpos] = *p; - newpos++; - } - } - newName[newpos] = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: Scans player names and replaces characters that vgui won't -// display properly -// Input : *oldName - player name to be fixed up -// Output : *char - static buffer with the safe name -//----------------------------------------------------------------------------- - -const char * UTIL_SafeName( const char *oldName ) -{ - static char safeName[ MAX_PLAYER_NAME_LENGTH * 2 + 1 ]; - UTIL_MakeSafeName( oldName, safeName, sizeof( safeName ) ); - - return safeName; -} - - -//----------------------------------------------------------------------------- -// Purpose: Looks up key bindings for commands and replaces them in string. -// %% will get replaced with its bound control, e.g. %attack2% -// Input buffer sizes are in bytes rather than unicode character count -// for consistency with other APIs. If inbufsizebytes is 0 a NULL-terminated -// input buffer is assumed, or you can pass the size of the input buffer if -// not NULL-terminated. -//----------------------------------------------------------------------------- -void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t *outbuf, int outbufsizebytes ) -{ - Assert( outbufsizebytes >= sizeof(outbuf[0]) ); - // copy to a new buf if there are vars - outbuf[0]=0; - - if ( !inbuf || !inbuf[0] ) - return; - - int pos = 0; - const wchar_t *inbufend = NULL; - if ( inbufsizebytes > 0 ) - { - inbufend = inbuf + ( inbufsizebytes / 2 ); - } - - while( inbuf != inbufend && *inbuf != 0 ) - { - // check for variables - if ( *inbuf == '%' ) - { - ++inbuf; - - const wchar_t *end = wcschr( inbuf, '%' ); - if ( end && ( end != inbuf ) ) // make sure we handle %% in the string, which should be treated in the output as % - { - wchar_t token[64]; - wcsncpy( token, inbuf, end - inbuf ); - token[end - inbuf] = 0; - - inbuf += end - inbuf; - - // lookup key names - char binding[64]; - g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); - - const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); - if ( !key ) - { - key = IsX360() ? "" : "< not bound >"; - } - - //!! change some key names into better names - char friendlyName[64]; - bool bAddBrackets = false; - if ( IsX360() ) - { - if ( !key || !key[0] ) - { - Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_None" ); - bAddBrackets = true; - } - else - { - Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_KeyNames_%s", key ); - } - } - else - { - Q_snprintf( friendlyName, sizeof(friendlyName), "%s", key ); - } - Q_strupr( friendlyName ); - - wchar_t *locName = g_pVGuiLocalize->Find( friendlyName ); - if ( !locName || wcslen(locName) <= 0) - { - g_pVGuiLocalize->ConvertANSIToUnicode( friendlyName, token, sizeof(token) ); - - outbuf[pos] = '\0'; - wcscat( outbuf, token ); - pos += wcslen(token); - } - else - { - outbuf[pos] = '\0'; - if ( bAddBrackets ) - { - wcscat( outbuf, L"[" ); - pos += 1; - } - wcscat( outbuf, locName ); - pos += wcslen(locName); - if ( bAddBrackets ) - { - wcscat( outbuf, L"]" ); - pos += 1; - } - } - } - else - { - outbuf[pos] = *inbuf; - ++pos; - } - } - else - { - outbuf[pos] = *inbuf; - ++pos; - } - - ++inbuf; - } - - outbuf[pos] = '\0'; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *filename - -// *pLength - -// Output : byte -//----------------------------------------------------------------------------- -byte *UTIL_LoadFileForMe( const char *filename, int *pLength ) -{ - byte *buffer; - - FileHandle_t file; - file = filesystem->Open( filename, "rb", "GAME" ); - if ( FILESYSTEM_INVALID_HANDLE == file ) - { - if ( pLength ) *pLength = 0; - return NULL; - } - - int size = filesystem->Size( file ); - buffer = new byte[ size + 1 ]; - if ( !buffer ) - { - Warning( "UTIL_LoadFileForMe: Couldn't allocate buffer of size %i for file %s\n", size + 1, filename ); - filesystem->Close( file ); - return NULL; - } - filesystem->Read( buffer, size, file ); - filesystem->Close( file ); - - // Ensure null terminator - buffer[ size ] =0; - - if ( pLength ) - { - *pLength = size; - } - - return buffer; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *buffer - -//----------------------------------------------------------------------------- -void UTIL_FreeFile( byte *buffer ) -{ - delete[] buffer; -} - - -//----------------------------------------------------------------------------- -// Compute distance fade -//----------------------------------------------------------------------------- -static unsigned char ComputeDistanceFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist ) -{ - if ((flMinDist <= 0) && (flMaxDist <= 0)) - return 255; - - if( flMinDist > flMaxDist ) - { - ::V_swap( flMinDist, flMaxDist ); - } - - // If a negative value is provided for the min fade distance, then base it off the max. - if( flMinDist < 0 ) - { - flMinDist = flMaxDist - 400; - if( flMinDist < 0 ) - { - flMinDist = 0; - } - } - - flMinDist *= flMinDist; - flMaxDist *= flMaxDist; - - float flCurrentDistanceSq = CurrentViewOrigin().DistToSqr( pEntity->WorldSpaceCenter() ); - C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); - if ( pLocal ) - { - float flDistFactor = pLocal->GetFOVDistanceAdjustFactor(); - flCurrentDistanceSq *= flDistFactor * flDistFactor; - } - - // If I'm inside the minimum range than don't resort to alpha trickery - if ( flCurrentDistanceSq <= flMinDist ) - return 255; - - if ( flCurrentDistanceSq >= flMaxDist ) - return 0; - - // NOTE: Because of the if-checks above, flMinDist != flMinDist here - float flFalloffFactor = 255.0f / (flMaxDist - flMinDist); - int nAlpha = flFalloffFactor * (flMaxDist - flCurrentDistanceSq); - return clamp( nAlpha, 0, 255 ); -} - - -//----------------------------------------------------------------------------- -// Compute fade amount -//----------------------------------------------------------------------------- -unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale ) -{ - unsigned char nAlpha = 255; - - // If we're taking devshots, don't fade props at all - if ( g_MakingDevShots || cl_leveloverview.GetFloat() > 0 ) - return 255; - -#ifdef _DEBUG - if ( r_FadeProps.GetBool() ) -#endif - { - nAlpha = ComputeDistanceFade( pEntity, flMinDist, flMaxDist ); - - // NOTE: This computation for the center + radius is invalid! - // The center of the sphere is at the center of the OBB, which is not necessarily - // at the render origin. But it should be close enough. - Vector vecMins, vecMaxs; - pEntity->GetRenderBounds( vecMins, vecMaxs ); - float flRadius = vecMins.DistTo( vecMaxs ) * 0.5f; - - Vector vecAbsCenter; - if ( modelinfo->GetModelType( pEntity->GetModel() ) == mod_brush ) - { - Vector vecRenderMins, vecRenderMaxs; - pEntity->GetRenderBoundsWorldspace( vecRenderMins, vecRenderMaxs ); - VectorAdd( vecRenderMins, vecRenderMaxs, vecAbsCenter ); - vecAbsCenter *= 0.5f; - } - else - { - vecAbsCenter = pEntity->GetRenderOrigin(); - } - - unsigned char nGlobalAlpha = IsXbox() ? 255 : modelinfo->ComputeLevelScreenFade( vecAbsCenter, flRadius, flFadeScale ); - unsigned char nDistAlpha; - - if ( !engine->IsLevelMainMenuBackground() ) - { - nDistAlpha = modelinfo->ComputeViewScreenFade( vecAbsCenter, flRadius, flFadeScale ); - } - else - { - nDistAlpha = 255; - } - - if ( nDistAlpha < nGlobalAlpha ) - { - nGlobalAlpha = nDistAlpha; - } - - if ( nGlobalAlpha < nAlpha ) - { - nAlpha = nGlobalAlpha; - } - } - - return nAlpha; -} - - -//----------------------------------------------------------------------------- -// Purpose: Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h -// Input : *pVecPos - -//----------------------------------------------------------------------------- -void UTIL_BoundToWorldSize( Vector *pVecPos ) -{ - Assert( pVecPos ); - for ( int i = 0; i < 3; ++i ) - { - (*pVecPos)[ i ] = clamp( (*pVecPos)[ i ], MIN_COORD_FLOAT, MAX_COORD_FLOAT ); - } -} - -#ifdef _X360 -#define MAP_KEY_FILE_DIR "cfg" -#else -#define MAP_KEY_FILE_DIR "media" -#endif - -//----------------------------------------------------------------------------- -// Purpose: Returns the filename to count map loads in -//----------------------------------------------------------------------------- -bool UTIL_GetMapLoadCountFileName( const char *pszFilePrependName, char *pszBuffer, int iBuflen ) -{ - if ( IsX360() ) - { -#ifdef _X360 - if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ) - return false; -#endif - } - - if ( IsX360() ) - { - Q_snprintf( pszBuffer, iBuflen, "%s:/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); - } - else - { - Q_snprintf( pszBuffer, iBuflen, "%s/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); - } - - return true; -} - -#ifdef TF_CLIENT_DLL -#define MAP_KEY_FILE "viewed.res" -#else -#define MAP_KEY_FILE "mapkeys.res" -#endif - -void UTIL_IncrementMapKey( const char *pszCustomKey ) -{ - if ( !pszCustomKey ) - return; - - char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) - return; - - int iCount = 1; - - KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); - if ( kvMapLoadFile ) - { - kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); - - char mapname[MAX_MAP_NAME]; - Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); - Q_strlower( mapname ); - - // Increment existing, or add a new one - KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); - if ( pMapKey ) - { - iCount = pMapKey->GetInt( pszCustomKey, 0 ) + 1; - pMapKey->SetInt( pszCustomKey, iCount ); - } - else - { - KeyValues *pNewKey = new KeyValues( mapname ); - if ( pNewKey ) - { - pNewKey->SetString( pszCustomKey, "1" ); - kvMapLoadFile->AddSubKey( pNewKey ); - } - } - - // Write it out - - // force create this directory incase it doesn't exist - filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); - - CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); - kvMapLoadFile->RecursiveSaveToFile( buf, 0 ); - g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); - - kvMapLoadFile->deleteThis(); - } - - if ( IsX360() ) - { -#ifdef _X360 - xboxsystem->FinishContainerWrites(); -#endif - } -} - -int UTIL_GetMapKeyCount( const char *pszCustomKey ) -{ - if ( !pszCustomKey ) - return 0; - - char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) - return 0; - - int iCount = 0; - - KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); - if ( kvMapLoadFile ) - { - // create an empty file if none exists - if ( !g_pFullFileSystem->FileExists( szFilename, "MOD" ) ) - { - // force create this directory incase it doesn't exist - filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); - - CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); - g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); - } - - kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); - - char mapname[MAX_MAP_NAME]; - Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); - Q_strlower( mapname ); - - KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); - if ( pMapKey ) - { - iCount = pMapKey->GetInt( pszCustomKey ); - } - - kvMapLoadFile->deleteThis(); - } - - return iCount; -} - -bool UTIL_HasLoadedAnyMap() -{ - char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) - return false; - - return g_pFullFileSystem->FileExists( szFilename, "MOD" ); -} +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include +#include "hud.h" +#include "itextmessage.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imaterialsystem.h" +#include "imovehelper.h" +#include "checksum_crc.h" +#include "decals.h" +#include "iefx.h" +#include "view_scene.h" +#include "filesystem.h" +#include "model_types.h" +#include "engine/IEngineTrace.h" +#include "engine/ivmodelinfo.h" +#include "c_te_effect_dispatch.h" +#include +#include +#include +#include "view.h" +#include "ixboxsystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar localplayer_visionflags( "localplayer_visionflags", "0", FCVAR_DEVELOPMENTONLY ); + +//----------------------------------------------------------------------------- +// ConVars +//----------------------------------------------------------------------------- +#ifdef _DEBUG + +ConVar r_FadeProps( "r_FadeProps", "1" ); + +#endif +bool g_MakingDevShots = false; +extern ConVar cl_leveloverview; + +//----------------------------------------------------------------------------- +// Purpose: Performs a var args printf into a static return buffer +// Input : *format - +// ... - +// Output : char +//----------------------------------------------------------------------------- +char *VarArgs( const char *format, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, format); + Q_vsnprintf (string, sizeof( string ), format,argptr); + va_end (argptr); + + return string; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the entity index corresponds to a player slot +// Input : index - +// Output : bool +//----------------------------------------------------------------------------- +bool IsPlayerIndex( int index ) +{ + return ( index >= 1 && index <= gpGlobals->maxClients ) ? true : false; +} + +int GetLocalPlayerIndex( void ) +{ + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player ) + return player->entindex(); + else + return 0; // game not started yet +} + +int GetLocalPlayerVisionFilterFlags( bool bWeaponsCheck /*= false */ ) +{ + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player ) + return player->GetVisionFilterFlags( bWeaponsCheck ); + else + return 0; +} + +bool IsLocalPlayerUsingVisionFilterFlags( int nFlags, bool bWeaponsCheck /* = false */ ) +{ + int nLocalPlayerFlags = GetLocalPlayerVisionFilterFlags( bWeaponsCheck ); + + if ( !bWeaponsCheck ) + { + // We can only modify the RJ flags with normal checks that won't take the forced kill cam flags that can happen in weapon checks + int nRJShaderFlags = nLocalPlayerFlags; + if ( nRJShaderFlags != 0 && GameRules() && !GameRules()->AllowMapVisionFilterShaders() ) + { + nRJShaderFlags = 0; + } + + if ( nRJShaderFlags != localplayer_visionflags.GetInt() ) + { + localplayer_visionflags.SetValue( nRJShaderFlags ); + } + } + + return ( nLocalPlayerFlags & nFlags ) == nFlags; +} + +bool IsLocalPlayerSpectator( void ) +{ + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player ) + return player->IsObserver(); + else + return false; // game not started yet +} + +int GetSpectatorMode( void ) +{ + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player ) + return player->GetObserverMode(); + else + return OBS_MODE_NONE; // game not started yet +} + +int GetSpectatorTarget( void ) +{ + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player ) + { + CBaseEntity * target = player->GetObserverTarget(); + + if ( target ) + return target->entindex(); + else + return 0; + } + else + { + return 0; // game not started yet + } +} + +int GetLocalPlayerTeam( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer ) + return pPlayer->GetTeamNumber(); + else + return TEAM_UNASSIGNED; +} + +//----------------------------------------------------------------------------- +// Purpose: Convert angles to -180 t 180 range +// Input : angles - +//----------------------------------------------------------------------------- +void NormalizeAngles( QAngle& angles ) +{ + int i; + + // Normalize angles to -180 to 180 range + for ( i = 0; i < 3; i++ ) + { + if ( angles[i] > 180.0 ) + { + angles[i] -= 360.0; + } + else if ( angles[i] < -180.0 ) + { + angles[i] += 360.0; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Interpolate Euler angles using quaternions to avoid singularities +// Input : start - +// end - +// output - +// frac - +//----------------------------------------------------------------------------- +void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac ) +{ + Quaternion src, dest; + + // Convert to quaternions + AngleQuaternion( start, src ); + AngleQuaternion( end, dest ); + + Quaternion result; + + // Slerp + QuaternionSlerp( src, dest, frac, result ); + + // Convert to euler + QuaternionAngles( result, output ); +} + +//----------------------------------------------------------------------------- +// Purpose: Simple linear interpolation +// Input : frac - +// src - +// dest - +// output - +//----------------------------------------------------------------------------- +void InterpolateVector( float frac, const Vector& src, const Vector& dest, Vector& output ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + output[ i ] = src[ i ] + frac * ( dest[ i ] - src[ i ] ); + } +} + +client_textmessage_t *TextMessageGet( const char *pName ) +{ + return engine->TextMessageGet( pName ); +} + +//----------------------------------------------------------------------------- +// Purpose: ScreenHeight returns the height of the screen, in pixels +// Output : int +//----------------------------------------------------------------------------- +int ScreenHeight( void ) +{ + int w, h; + GetHudSize( w, h ); + return h; +} + +//----------------------------------------------------------------------------- +// Purpose: ScreenWidth returns the width of the screen, in pixels +// Output : int +//----------------------------------------------------------------------------- +int ScreenWidth( void ) +{ + int w, h; + GetHudSize( w, h ); + return w; +} + +//----------------------------------------------------------------------------- +// Purpose: Return the difference between two angles +// Input : destAngle - +// srcAngle - +// Output : float +//----------------------------------------------------------------------------- +float UTIL_AngleDiff( float destAngle, float srcAngle ) +{ + float delta; + + delta = destAngle - srcAngle; + if ( destAngle > srcAngle ) + { + while ( delta >= 180 ) + delta -= 360; + } + else + { + while ( delta <= -180 ) + delta += 360; + } + return delta; +} + + +float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) +{ + Vector midUp = position; + midUp.z = minz; + + if ( !(UTIL_PointContents(midUp) & MASK_WATER) ) + return minz; + + midUp.z = maxz; + if ( UTIL_PointContents(midUp) & MASK_WATER ) + return maxz; + + float diff = maxz - minz; + while (diff > 1.0) + { + midUp.z = minz + diff/2.0; + if ( UTIL_PointContents(midUp) & MASK_WATER ) + { + minz = midUp.z; + } + else + { + maxz = midUp.z; + } + diff = maxz - minz; + } + + return midUp.z; +} + +void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count ) +{ + Vector mid = (mins + maxs) * 0.5; + + float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); + flHeight = flHeight - mins.z; + + CPASFilter filter( mid ); + + int bubbles = modelinfo->GetModelIndex( "sprites/bubble.vmt" ); + + te->Bubbles( filter, 0.0, + &mins, &maxs, flHeight, bubbles, count, 8.0 ); +} + +void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake ) +{ + // Nothing for now +} + +char TEXTURETYPE_Find( trace_t *ptr ) +{ + surfacedata_t *psurfaceData = physprops->GetSurfaceData( ptr->surface.surfaceProps ); + + return psurfaceData->game.material; +} + +//----------------------------------------------------------------------------- +// Purpose: Make a tracer effect +//----------------------------------------------------------------------------- +void UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex, int iAttachment, float flVelocity, bool bWhiz, char *pCustomTracerName ) +{ + CEffectData data; + data.m_vStart = vecStart; + data.m_vOrigin = vecEnd; + data.m_hEntity = ClientEntityList().EntIndexToHandle( iEntIndex ); + data.m_flScale = flVelocity; + + // Flags + if ( bWhiz ) + { + data.m_fFlags |= TRACER_FLAG_WHIZ; + } + if ( iAttachment != TRACER_DONT_USE_ATTACHMENT ) + { + data.m_fFlags |= TRACER_FLAG_USEATTACHMENT; + // Stomp the start, since it's not going to be used anyway + data.m_vStart[0] = iAttachment; + } + + // Fire it off + if ( pCustomTracerName ) + { + DispatchEffect( pCustomTracerName, data ); + } + else + { + DispatchEffect( "Tracer", data ); + } +} + + +//------------------------------------------------------------------------------ +// Purpose : Creates both an decal and any associated impact effects (such +// as flecks) for the given iDamageType and the trace's end position +// Input : +// Output : +//------------------------------------------------------------------------------ +void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) +{ + C_BaseEntity *pEntity = pTrace->m_pEnt; + + // Is the entity valid, is the surface sky? + if ( !pEntity || (pTrace->surface.flags & SURF_SKY) ) + return; + + if (pTrace->fraction == 1.0) + return; + + // don't decal nodraw surfaces + if ( pTrace->surface.flags & SURF_NODRAW ) + return; + + pEntity->ImpactTrace( pTrace, iDamageType, pCustomImpactName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int UTIL_PrecacheDecal( const char *name, bool preload ) +{ + return effects->Draw_DecalIndexFromName( (char*)name ); +} + +extern short g_sModelIndexSmoke; + +void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ) +{ + CPVSFilter filter( origin ); + te->Smoke( filter, 0.0f, &origin, g_sModelIndexSmoke, scale, framerate ); +} + +void UTIL_SetOrigin( C_BaseEntity *entity, const Vector &vecOrigin ) +{ + entity->SetLocalOrigin( vecOrigin ); +} + +//#define PRECACHE_OTHER_ONCE +// UNDONE: Do we need this to avoid doing too much of this? Measure startup times and see +#if PRECACHE_OTHER_ONCE + +#include "utlsymbol.h" +class CPrecacheOtherList : public CAutoServerSystem +{ +public: + virtual void LevelInitPreEntity(); + virtual void LevelShutdownPostEntity(); + + bool AddOrMarkPrecached( const char *pClassname ); + +private: + CUtlSymbolTable m_list; +}; + +void CPrecacheOtherList::LevelInitPreEntity() +{ + m_list.RemoveAll(); +} + +void CPrecacheOtherList::LevelShutdownPostEntity() +{ + m_list.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: mark or add +// Input : *pEntity - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CPrecacheOtherList::AddOrMarkPrecached( const char *pClassname ) +{ + CUtlSymbol sym = m_list.Find( pClassname ); + if ( sym.IsValid() ) + return false; + + m_list.AddString( pClassname ); + return true; +} + +CPrecacheOtherList g_PrecacheOtherList; +#endif + +void UTIL_PrecacheOther( const char *szClassname ) +{ +#if PRECACHE_OTHER_ONCE + // already done this one?, if not, mark as done + if ( !g_PrecacheOtherList.AddOrMarkPrecached( szClassname ) ) + return; +#endif + + // Client should only do this once entities are coming down from server!!! + // Assert( engine->IsConnected() ); + + C_BaseEntity *pEntity = CreateEntityByName( szClassname ); + if ( !pEntity ) + { + Warning( "NULL Ent in UTIL_PrecacheOther\n" ); + return; + } + + if (pEntity) + { + pEntity->Precache( ); + } + + // Bye bye + pEntity->Release(); +} + +static csurface_t g_NullSurface = { "**empty**", 0 }; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void UTIL_SetTrace(trace_t& trace, const Ray_t& ray, C_BaseEntity *ent, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept ) +{ + trace.startsolid = (fraction == 0.0f); + trace.fraction = fraction; + VectorCopy( ray.m_Start, trace.startpos ); + VectorMA( ray.m_Start, fraction, ray.m_Delta, trace.endpos ); + VectorCopy( normal, trace.plane.normal ); + trace.plane.dist = intercept; + trace.m_pEnt = C_BaseEntity::Instance( ent ); + trace.hitgroup = hitgroup; + trace.surface = g_NullSurface; + trace.contents = contents; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the x & y positions of a world position in screenspace +// Returns true if it's onscreen +//----------------------------------------------------------------------------- +bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) +{ + Vector screen; + + // Apply the offset, if one was specified + if ( vecOffset != NULL ) + pos += *vecOffset; + + // Transform to screen space + int iFacing = ScreenTransform( pos, screen ); + iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); + iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); + + // Make sure the player's facing it + if ( iFacing ) + { + // We're actually facing away from the Target. Stomp the screen position. + iX = -640; + iY = -640; + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the x & y positions of a world position in HUD space +// Returns true if it's onscreen +//----------------------------------------------------------------------------- +bool GetVectorInHudSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) +{ + Vector screen; + + // Apply the offset, if one was specified + if ( vecOffset != NULL ) + pos += *vecOffset; + + // Transform to HUD space + int iFacing = HudTransform( pos, screen ); + iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); + iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); + + // Make sure the player's facing it + if ( iFacing ) + { + // We're actually facing away from the Target. Stomp the screen position. + iX = -640; + iY = -640; + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the x & y positions of an entity in screenspace +// Returns true if it's onscreen +//----------------------------------------------------------------------------- +bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset ) +{ + return GetVectorInScreenSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); +} + +//----------------------------------------------------------------------------- +// Purpose: Get the x & y positions of an entity in Vgui space +// Returns true if it's onscreen +//----------------------------------------------------------------------------- +bool GetTargetInHudSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset ) +{ + return GetVectorInHudSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *player - +// msg_dest - +// *msg_name - +// *param1 - +// *param2 - +// *param3 - +// *param4 - +//----------------------------------------------------------------------------- +void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, const char *param1 /*= NULL*/, const char *param2 /*= NULL*/, const char *param3 /*= NULL*/, const char *param4 /*= NULL*/ ) +{ +} + +//----------------------------------------------------------------------------- +// class CFlaggedEntitiesEnum +//----------------------------------------------------------------------------- +// enumerate entities that match a set of edict flags into a static array +class CFlaggedEntitiesEnum : public IPartitionEnumerator +{ +public: + CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ); + // This gets called by the enumeration methods with each element + // that passes the test. + virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + + int GetCount() { return m_count; } + bool AddToList( C_BaseEntity *pEntity ); + +private: + C_BaseEntity **m_pList; + int m_listMax; + int m_flagMask; + int m_count; +}; + +CFlaggedEntitiesEnum::CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ) +{ + m_pList = pList; + m_listMax = listMax; + m_flagMask = flagMask; + m_count = 0; +} + +bool CFlaggedEntitiesEnum::AddToList( C_BaseEntity *pEntity ) +{ + if ( m_count >= m_listMax ) + return false; + m_pList[m_count] = pEntity; + m_count++; + return true; +} + +IterationRetval_t CFlaggedEntitiesEnum::EnumElement( IHandleEntity *pHandleEntity ) +{ + IClientEntity *pClientEntity = cl_entitylist->GetClientEntityFromHandle( pHandleEntity->GetRefEHandle() ); + C_BaseEntity *pEntity = pClientEntity ? pClientEntity->GetBaseEntity() : NULL; + if ( pEntity ) + { + if ( m_flagMask && !(pEntity->GetFlags() & m_flagMask) ) // Does it meet the criteria? + return ITERATION_CONTINUE; + + if ( !AddToList( pEntity ) ) + return ITERATION_STOP; + } + + return ITERATION_CONTINUE; +} + +//----------------------------------------------------------------------------- +// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted +// Input : **pList - +// listMax - +// &mins - +// &maxs - +// flagMask - +// Output : int +//----------------------------------------------------------------------------- +int UTIL_EntitiesInBox( C_BaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask, int partitionMask ) +{ + CFlaggedEntitiesEnum boxEnum( pList, listMax, flagMask ); + partition->EnumerateElementsInBox( partitionMask, mins, maxs, false, &boxEnum ); + + return boxEnum.GetCount(); + +} + +//----------------------------------------------------------------------------- +// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted +// Input : **pList - +// listMax - +// ¢er - +// radius - +// flagMask - +// Output : int +//----------------------------------------------------------------------------- +int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector ¢er, float radius, int flagMask, int partitionMask ) +{ + CFlaggedEntitiesEnum sphereEnum( pList, listMax, flagMask ); + partition->EnumerateElementsInSphere( partitionMask, center, radius, false, &sphereEnum ); + + return sphereEnum.GetCount(); + +} + +//----------------------------------------------------------------------------- +// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted +// Input : **pList - +// listMax - +// &ray - +// flagMask - +// Output : int +//----------------------------------------------------------------------------- +int UTIL_EntitiesAlongRay( C_BaseEntity **pList, int listMax, const Ray_t &ray, int flagMask, int partitionMask ) +{ + CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask ); + partition->EnumerateElementsAlongRay( partitionMask, ray, false, &rayEnum ); + + return rayEnum.GetCount(); +} + +CEntitySphereQuery::CEntitySphereQuery( const Vector ¢er, float radius, int flagMask, int partitionMask ) +{ + m_listIndex = 0; + m_listCount = UTIL_EntitiesInSphere( m_pList, ARRAYSIZE(m_pList), center, radius, flagMask, partitionMask ); +} + +CBaseEntity *CEntitySphereQuery::GetCurrentEntity() +{ + if ( m_listIndex < m_listCount ) + return m_pList[m_listIndex]; + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Slightly modified strtok. Does not modify the input string. Does +// not skip over more than one separator at a time. This allows parsing +// strings where tokens between separators may or may not be present: +// +// Door01,,,0 would be parsed as "Door01" "" "" "0" +// Door01,Open,,0 would be parsed as "Door01" "Open" "" "0" +// +// Input : token - Returns with a token, or zero length if the token was missing. +// str - String to parse. +// sep - Character to use as separator. UNDONE: allow multiple separator chars +// Output : Returns a pointer to the next token to be parsed. +//----------------------------------------------------------------------------- +const char *nexttoken(char *token, const char *str, char sep) +{ + if ((str == NULL) || (*str == '\0')) + { + *token = '\0'; + return(NULL); + } + + // + // Copy everything up to the first separator into the return buffer. + // Do not include separators in the return buffer. + // + while ((*str != sep) && (*str != '\0')) + { + *token++ = *str++; + } + *token = '\0'; + + // + // Advance the pointer unless we hit the end of the input string. + // + if (*str == '\0') + { + return(str); + } + + return(++str); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : font - +// *str - +// Output : int +//----------------------------------------------------------------------------- +int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str ) +{ + float pixels = 0; + const char *p = str; + const char *pAfter = p + 1; + const char *pBefore = "\0"; + while ( *p ) + { +#if USE_GETKERNEDCHARWIDTH + float wide, abcA; + vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); + pixels += wide; +#else + pixels += vgui::surface()->GetCharacterWidth( font, *p ); +#endif + pBefore = p; + p++; + if ( *p ) + pAfter = p + 1; + else + pAfter = "\0"; + } + return (int)ceil(pixels); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : font - +// *str - +// Output : int +//----------------------------------------------------------------------------- +int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ) +{ + float pixels = 0; + const wchar_t *p = str; + const wchar_t *pAfter = p + 1; + const wchar_t *pBefore = L"\0"; + while ( *p ) + { +#if USE_GETKERNEDCHARWIDTH + float wide, abcA; + vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); + pixels += wide; +#else + pixels += vgui::surface()->GetCharacterWidth( font, *p ); +#endif + pBefore = p; + p++; + if ( *p ) + pAfter = p + 1; + else + pAfter = L"\0"; + } + return (int)ceil(pixels); +} + +//----------------------------------------------------------------------------- +// Purpose: Scans player names +//Passes the player name to be checked in a KeyValues pointer +//with the keyname "name" +// - replaces '&' with '&&' so they will draw in the scoreboard +// - replaces '#' at the start of the name with '*' +//----------------------------------------------------------------------------- + +void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize ) +{ + Assert( newNameBufSize >= sizeof(newName[0]) ); + + int newpos = 0; + + for( const char *p=oldName; *p != 0 && newpos < newNameBufSize-1; p++ ) + { + //check for a '#' char at the beginning + if( p == oldName && *p == '#' ) + { + newName[newpos] = '*'; + newpos++; + } + else if( *p == '%' ) + { + // remove % chars + newName[newpos] = '*'; + newpos++; + } + else if( *p == '&' ) + { + //insert another & after this one + if ( newpos+2 < newNameBufSize ) + { + newName[newpos] = '&'; + newName[newpos+1] = '&'; + newpos+=2; + } + } + else + { + newName[newpos] = *p; + newpos++; + } + } + newName[newpos] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Scans player names and replaces characters that vgui won't +// display properly +// Input : *oldName - player name to be fixed up +// Output : *char - static buffer with the safe name +//----------------------------------------------------------------------------- + +const char * UTIL_SafeName( const char *oldName ) +{ + static char safeName[ MAX_PLAYER_NAME_LENGTH * 2 + 1 ]; + UTIL_MakeSafeName( oldName, safeName, sizeof( safeName ) ); + + return safeName; +} + + +//----------------------------------------------------------------------------- +// Purpose: Looks up key bindings for commands and replaces them in string. +// %% will get replaced with its bound control, e.g. %attack2% +// Input buffer sizes are in bytes rather than unicode character count +// for consistency with other APIs. If inbufsizebytes is 0 a NULL-terminated +// input buffer is assumed, or you can pass the size of the input buffer if +// not NULL-terminated. +//----------------------------------------------------------------------------- +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t *outbuf, int outbufsizebytes ) +{ + Assert( outbufsizebytes >= sizeof(outbuf[0]) ); + // copy to a new buf if there are vars + outbuf[0]=0; + + if ( !inbuf || !inbuf[0] ) + return; + + int pos = 0; + const wchar_t *inbufend = NULL; + if ( inbufsizebytes > 0 ) + { + inbufend = inbuf + ( inbufsizebytes / 2 ); + } + + while( inbuf != inbufend && *inbuf != 0 ) + { + // check for variables + if ( *inbuf == '%' ) + { + ++inbuf; + + const wchar_t *end = wcschr( inbuf, '%' ); + if ( end && ( end != inbuf ) ) // make sure we handle %% in the string, which should be treated in the output as % + { + wchar_t token[64]; + wcsncpy( token, inbuf, end - inbuf ); + token[end - inbuf] = 0; + + inbuf += end - inbuf; + + // lookup key names + char binding[64]; + g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); + + const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); + if ( !key ) + { + key = IsX360() ? "" : "< not bound >"; + } + + //!! change some key names into better names + char friendlyName[64]; + bool bAddBrackets = false; + if ( IsX360() ) + { + if ( !key || !key[0] ) + { + Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_None" ); + bAddBrackets = true; + } + else + { + Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_KeyNames_%s", key ); + } + } + else + { + Q_snprintf( friendlyName, sizeof(friendlyName), "%s", key ); + } + Q_strupr( friendlyName ); + + wchar_t *locName = g_pVGuiLocalize->Find( friendlyName ); + if ( !locName || wcslen(locName) <= 0) + { + g_pVGuiLocalize->ConvertANSIToUnicode( friendlyName, token, sizeof(token) ); + + outbuf[pos] = '\0'; + wcscat( outbuf, token ); + pos += wcslen(token); + } + else + { + outbuf[pos] = '\0'; + if ( bAddBrackets ) + { + wcscat( outbuf, L"[" ); + pos += 1; + } + wcscat( outbuf, locName ); + pos += wcslen(locName); + if ( bAddBrackets ) + { + wcscat( outbuf, L"]" ); + pos += 1; + } + } + } + else + { + outbuf[pos] = *inbuf; + ++pos; + } + } + else + { + outbuf[pos] = *inbuf; + ++pos; + } + + ++inbuf; + } + + outbuf[pos] = '\0'; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *filename - +// *pLength - +// Output : byte +//----------------------------------------------------------------------------- +byte *UTIL_LoadFileForMe( const char *filename, int *pLength ) +{ + byte *buffer; + + FileHandle_t file; + file = filesystem->Open( filename, "rb", "GAME" ); + if ( FILESYSTEM_INVALID_HANDLE == file ) + { + if ( pLength ) *pLength = 0; + return NULL; + } + + int size = filesystem->Size( file ); + buffer = new byte[ size + 1 ]; + if ( !buffer ) + { + Warning( "UTIL_LoadFileForMe: Couldn't allocate buffer of size %i for file %s\n", size + 1, filename ); + filesystem->Close( file ); + return NULL; + } + filesystem->Read( buffer, size, file ); + filesystem->Close( file ); + + // Ensure null terminator + buffer[ size ] =0; + + if ( pLength ) + { + *pLength = size; + } + + return buffer; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *buffer - +//----------------------------------------------------------------------------- +void UTIL_FreeFile( byte *buffer ) +{ + delete[] buffer; +} + + +//----------------------------------------------------------------------------- +// Compute distance fade +//----------------------------------------------------------------------------- +static unsigned char ComputeDistanceFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist ) +{ + if ((flMinDist <= 0) && (flMaxDist <= 0)) + return 255; + + if( flMinDist > flMaxDist ) + { + ::V_swap( flMinDist, flMaxDist ); + } + + // If a negative value is provided for the min fade distance, then base it off the max. + if( flMinDist < 0 ) + { + flMinDist = flMaxDist - 400; + if( flMinDist < 0 ) + { + flMinDist = 0; + } + } + + flMinDist *= flMinDist; + flMaxDist *= flMaxDist; + + float flCurrentDistanceSq = CurrentViewOrigin().DistToSqr( pEntity->WorldSpaceCenter() ); + C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); + if ( pLocal ) + { + float flDistFactor = pLocal->GetFOVDistanceAdjustFactor(); + flCurrentDistanceSq *= flDistFactor * flDistFactor; + } + + // If I'm inside the minimum range than don't resort to alpha trickery + if ( flCurrentDistanceSq <= flMinDist ) + return 255; + + if ( flCurrentDistanceSq >= flMaxDist ) + return 0; + + // NOTE: Because of the if-checks above, flMinDist != flMinDist here + float flFalloffFactor = 255.0f / (flMaxDist - flMinDist); + int nAlpha = flFalloffFactor * (flMaxDist - flCurrentDistanceSq); + return clamp( nAlpha, 0, 255 ); +} + + +//----------------------------------------------------------------------------- +// Compute fade amount +//----------------------------------------------------------------------------- +unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale ) +{ + unsigned char nAlpha = 255; + + // If we're taking devshots, don't fade props at all + if ( g_MakingDevShots || cl_leveloverview.GetFloat() > 0 ) + return 255; + +#ifdef _DEBUG + if ( r_FadeProps.GetBool() ) +#endif + { + nAlpha = ComputeDistanceFade( pEntity, flMinDist, flMaxDist ); + + // NOTE: This computation for the center + radius is invalid! + // The center of the sphere is at the center of the OBB, which is not necessarily + // at the render origin. But it should be close enough. + Vector vecMins, vecMaxs; + pEntity->GetRenderBounds( vecMins, vecMaxs ); + float flRadius = vecMins.DistTo( vecMaxs ) * 0.5f; + + Vector vecAbsCenter; + if ( modelinfo->GetModelType( pEntity->GetModel() ) == mod_brush ) + { + Vector vecRenderMins, vecRenderMaxs; + pEntity->GetRenderBoundsWorldspace( vecRenderMins, vecRenderMaxs ); + VectorAdd( vecRenderMins, vecRenderMaxs, vecAbsCenter ); + vecAbsCenter *= 0.5f; + } + else + { + vecAbsCenter = pEntity->GetRenderOrigin(); + } + + unsigned char nGlobalAlpha = IsXbox() ? 255 : modelinfo->ComputeLevelScreenFade( vecAbsCenter, flRadius, flFadeScale ); + unsigned char nDistAlpha; + + if ( !engine->IsLevelMainMenuBackground() ) + { + nDistAlpha = modelinfo->ComputeViewScreenFade( vecAbsCenter, flRadius, flFadeScale ); + } + else + { + nDistAlpha = 255; + } + + if ( nDistAlpha < nGlobalAlpha ) + { + nGlobalAlpha = nDistAlpha; + } + + if ( nGlobalAlpha < nAlpha ) + { + nAlpha = nGlobalAlpha; + } + } + + return nAlpha; +} + + +//----------------------------------------------------------------------------- +// Purpose: Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h +// Input : *pVecPos - +//----------------------------------------------------------------------------- +void UTIL_BoundToWorldSize( Vector *pVecPos ) +{ + Assert( pVecPos ); + for ( int i = 0; i < 3; ++i ) + { + (*pVecPos)[ i ] = clamp( (*pVecPos)[ i ], MIN_COORD_FLOAT, MAX_COORD_FLOAT ); + } +} + +#ifdef _X360 +#define MAP_KEY_FILE_DIR "cfg" +#else +#define MAP_KEY_FILE_DIR "media" +#endif + +//----------------------------------------------------------------------------- +// Purpose: Returns the filename to count map loads in +//----------------------------------------------------------------------------- +bool UTIL_GetMapLoadCountFileName( const char *pszFilePrependName, char *pszBuffer, int iBuflen ) +{ + if ( IsX360() ) + { +#ifdef _X360 + if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ) + return false; +#endif + } + + if ( IsX360() ) + { + Q_snprintf( pszBuffer, iBuflen, "%s:/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); + } + else + { + Q_snprintf( pszBuffer, iBuflen, "%s/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); + } + + return true; +} + +#ifdef TF_CLIENT_DLL +#define MAP_KEY_FILE "viewed.res" +#else +#define MAP_KEY_FILE "mapkeys.res" +#endif + +void UTIL_IncrementMapKey( const char *pszCustomKey ) +{ + if ( !pszCustomKey ) + return; + + char szFilename[ _MAX_PATH ]; + if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + return; + + int iCount = 1; + + KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); + if ( kvMapLoadFile ) + { + kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); + + char mapname[MAX_MAP_NAME]; + Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); + Q_strlower( mapname ); + + // Increment existing, or add a new one + KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); + if ( pMapKey ) + { + iCount = pMapKey->GetInt( pszCustomKey, 0 ) + 1; + pMapKey->SetInt( pszCustomKey, iCount ); + } + else + { + KeyValues *pNewKey = new KeyValues( mapname ); + if ( pNewKey ) + { + pNewKey->SetString( pszCustomKey, "1" ); + kvMapLoadFile->AddSubKey( pNewKey ); + } + } + + // Write it out + + // force create this directory incase it doesn't exist + filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + kvMapLoadFile->RecursiveSaveToFile( buf, 0 ); + g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); + + kvMapLoadFile->deleteThis(); + } + + if ( IsX360() ) + { +#ifdef _X360 + xboxsystem->FinishContainerWrites(); +#endif + } +} + +int UTIL_GetMapKeyCount( const char *pszCustomKey ) +{ + if ( !pszCustomKey ) + return 0; + + char szFilename[ _MAX_PATH ]; + if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + return 0; + + int iCount = 0; + + KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE ); + if ( kvMapLoadFile ) + { + // create an empty file if none exists + if ( !g_pFullFileSystem->FileExists( szFilename, "MOD" ) ) + { + // force create this directory incase it doesn't exist + filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD"); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + g_pFullFileSystem->WriteFile( szFilename, "MOD", buf ); + } + + kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" ); + + char mapname[MAX_MAP_NAME]; + Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) ); + Q_strlower( mapname ); + + KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname ); + if ( pMapKey ) + { + iCount = pMapKey->GetInt( pszCustomKey ); + } + + kvMapLoadFile->deleteThis(); + } + + return iCount; +} + +bool UTIL_HasLoadedAnyMap() +{ + char szFilename[ _MAX_PATH ]; + if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + return false; + + return g_pFullFileSystem->FileExists( szFilename, "MOD" ); +} -- cgit v1.2.3