|
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
|
|
//
|
|
|
|
// Purpose: Weapon data file parsing, shared by game & client dlls.
|
|
|
|
//
|
|
|
|
// $NoKeywords: $
|
|
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
|
|
#include <KeyValues.h>
|
|
|
|
#include <tier0/mem.h>
|
|
|
|
#include "filesystem.h"
|
|
|
|
#include "utldict.h"
|
|
|
|
#include "ammodef.h"
|
|
|
|
|
|
|
|
#include "playerclass_info_parse.h"
|
|
|
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
|
|
static CUtlDict< FilePlayerClassInfo_t*, unsigned short > m_PlayerClassInfoDatabase;
|
|
|
|
|
|
|
|
#define MAX_PLAYERCLASSES 32
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
|
|
// used to track whether or not two player classes have been mistakenly assigned the same slot
|
|
|
|
bool g_bUsedPlayerClassSlots[MAX_PLAYERCLASSES] = { 0 };
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
void CC_ReloadPlayerClasses_f (void)
|
|
|
|
{
|
|
|
|
//ResetFilePlayerClassInfoDatabase();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ConCommand dod_reloadplayerclasses("dod_reloadplayerclasses", CC_ReloadPlayerClasses_f, "Reset player class info cache" );
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input : *name -
|
|
|
|
// Output : FilePlayerClassInfo_t
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static PLAYERCLASS_FILE_INFO_HANDLE FindPlayerClassInfoSlot( const char *name )
|
|
|
|
{
|
|
|
|
// Complain about duplicately defined metaclass names...
|
|
|
|
unsigned short lookup = m_PlayerClassInfoDatabase.Find( name );
|
|
|
|
if ( lookup != m_PlayerClassInfoDatabase.InvalidIndex() )
|
|
|
|
{
|
|
|
|
return lookup;
|
|
|
|
}
|
|
|
|
|
|
|
|
FilePlayerClassInfo_t *insert = CreatePlayerClassInfo();
|
|
|
|
|
|
|
|
lookup = m_PlayerClassInfoDatabase.Insert( name, insert );
|
|
|
|
Assert( lookup != m_PlayerClassInfoDatabase.InvalidIndex() );
|
|
|
|
return lookup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a class slot, assuming the weapon's data has already been loaded.
|
|
|
|
PLAYERCLASS_FILE_INFO_HANDLE LookupPlayerClassInfoSlot( const char *name )
|
|
|
|
{
|
|
|
|
return m_PlayerClassInfoDatabase.Find( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME, handle differently?
|
|
|
|
static FilePlayerClassInfo_t gNullPlayerClassInfo;
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Input : handle -
|
|
|
|
// Output : FilePlayerClassInfo_t
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
FilePlayerClassInfo_t *GetFilePlayerClassInfoFromHandle( PLAYERCLASS_FILE_INFO_HANDLE handle )
|
|
|
|
{
|
|
|
|
if ( handle == GetInvalidPlayerClassInfoHandle() )
|
|
|
|
{
|
|
|
|
Assert( !"bad index into playerclass info UtlDict" );
|
|
|
|
return &gNullPlayerClassInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_PlayerClassInfoDatabase[ handle ];
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
// Output : PLAYERCLASS_FILE_INFO_HANDLE
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
PLAYERCLASS_FILE_INFO_HANDLE GetInvalidPlayerClassInfoHandle( void )
|
|
|
|
{
|
|
|
|
return (PLAYERCLASS_FILE_INFO_HANDLE)m_PlayerClassInfoDatabase.InvalidIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ResetFilePlayerClassInfoDatabase( void )
|
|
|
|
{
|
|
|
|
m_PlayerClassInfoDatabase.PurgeAndDeleteElements();
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
memset(g_bUsedPlayerClassSlots, 0, sizeof(g_bUsedPlayerClassSlots));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _XBOX
|
|
|
|
KeyValues* ReadEncryptedKVPlayerClassFile( IFileSystem *filesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey )
|
|
|
|
{
|
|
|
|
Assert( strchr( szFilenameWithoutExtension, '.' ) == NULL );
|
|
|
|
char szFullName[512];
|
|
|
|
|
|
|
|
// Open the weapon data file, and abort if we can't
|
|
|
|
KeyValues *pKV = new KeyValues( "PlayerClassDatafile" );
|
|
|
|
|
|
|
|
Q_snprintf(szFullName,sizeof(szFullName), "%s.txt", szFilenameWithoutExtension);
|
|
|
|
|
|
|
|
if ( !pKV->LoadFromFile( filesystem, szFullName, "GAME" ) ) // try to load the normal .txt file first
|
|
|
|
{
|
|
|
|
if ( pICEKey )
|
|
|
|
{
|
|
|
|
Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", szFilenameWithoutExtension); // fall back to the .ctx file
|
|
|
|
|
|
|
|
FileHandle_t f = filesystem->Open( szFullName, "rb", "GAME");
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
pKV->deleteThis();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// load file into a null-terminated buffer
|
|
|
|
int fileSize = filesystem->Size(f);
|
|
|
|
char *buffer = (char*)MemAllocScratch(fileSize + 1);
|
|
|
|
|
|
|
|
Assert(buffer);
|
|
|
|
|
|
|
|
filesystem->Read(buffer, fileSize, f); // read into local buffer
|
|
|
|
buffer[fileSize] = 0; // null terminate file as EOF
|
|
|
|
filesystem->Close( f ); // close file after reading
|
|
|
|
|
|
|
|
UTIL_DecodeICE( (unsigned char*)buffer, fileSize, pICEKey );
|
|
|
|
|
|
|
|
bool retOK = pKV->LoadFromBuffer( szFullName, buffer, filesystem );
|
|
|
|
|
|
|
|
MemFreeScratch();
|
|
|
|
|
|
|
|
if ( !retOK )
|
|
|
|
{
|
|
|
|
pKV->deleteThis();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pKV->deleteThis();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pKV;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: Read data on weapon from script file
|
|
|
|
// Output: true - if data2 successfully read
|
|
|
|
// false - if data load fails
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool ReadPlayerClassDataFromFileForSlot( IFileSystem* filesystem, const char *szPlayerClassName, PLAYERCLASS_FILE_INFO_HANDLE *phandle, const unsigned char *pICEKey )
|
|
|
|
{
|
|
|
|
if ( !phandle )
|
|
|
|
{
|
|
|
|
Assert( 0 );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*phandle = FindPlayerClassInfoSlot( szPlayerClassName );
|
|
|
|
FilePlayerClassInfo_t *pFileInfo = GetFilePlayerClassInfoFromHandle( *phandle );
|
|
|
|
Assert( pFileInfo );
|
|
|
|
|
|
|
|
if ( pFileInfo->m_bParsedScript )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
char sz[128];
|
|
|
|
Q_snprintf( sz, sizeof( sz ), "scripts/playerclass_%s", szPlayerClassName );
|
|
|
|
KeyValues *pKV = ReadEncryptedKVFile( filesystem, sz, pICEKey );
|
|
|
|
if ( !pKV )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
pFileInfo->Parse( pKV, szPlayerClassName );
|
|
|
|
|
|
|
|
pKV->deleteThis();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// FilePlayerClassInfo_t implementation.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FilePlayerClassInfo_t::FilePlayerClassInfo_t()
|
|
|
|
{
|
|
|
|
m_bParsedScript = false;
|
|
|
|
|
|
|
|
m_szPlayerClassName[0] = 0;
|
|
|
|
m_szPrintName[0] = 0;
|
|
|
|
m_szPlayerModel[0] = 0;
|
|
|
|
m_szSelectCmd[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FilePlayerClassInfo_t::Parse( KeyValues *pKeyValuesData, const char *szPlayerClassName )
|
|
|
|
{
|
|
|
|
// Okay, we tried at least once to look this up...
|
|
|
|
m_bParsedScript = true;
|
|
|
|
|
|
|
|
// Classname
|
|
|
|
Q_strncpy( m_szPlayerClassName, szPlayerClassName, MAX_WEAPON_STRING );
|
|
|
|
|
|
|
|
// Printable name
|
|
|
|
Q_strncpy( m_szPrintName, pKeyValuesData->GetString( "printname", "!! Missing printname on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH );
|
|
|
|
|
|
|
|
// Player Model
|
|
|
|
Q_strncpy( m_szPlayerModel, pKeyValuesData->GetString( "playermodel", "!! Missing playermodel on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH );
|
|
|
|
|
|
|
|
// Select command
|
|
|
|
Q_strncpy( m_szSelectCmd, pKeyValuesData->GetString( "selectcmd", "!! Missing selectcmd on Player Class" ), 32 );
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_DEBUG) && defined(HL2_CLIENT_DLL)
|
|
|
|
|
|
|
|
// Use this for class select keys
|
|
|
|
|
|
|
|
/*
|
|
|
|
// make sure two weapons aren't in the same slot & position
|
|
|
|
if (g_bUsedPlayerClassSlots[iSlot])
|
|
|
|
{
|
|
|
|
Msg( "Weapon slot info: %s (%d, %d)\n", szPrintName, iSlot, iPosition );
|
|
|
|
Warning( "Duplicately assigned weapon to slots in selection hud\n" );
|
|
|
|
}
|
|
|
|
g_bUsedPlayerClassSlots[iSlot][iPosition] = true;
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|