text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  //=============================================================================//
  
  #include "cbase.h"
  #include <KeyValues.h>
  #include "cs_weapon_parse.h"
  #include "cs_shareddefs.h"
  #include "weapon_csbase.h"
  #include "icvar.h"
  #include "cs_gamerules.h"
  #include "cs_blackmarket.h"
  
  
  //--------------------------------------------------------------------------------------------------------
  struct WeaponTypeInfo
  {
  	CSWeaponType type;
  	const char * name;
  };
  
  
  //--------------------------------------------------------------------------------------------------------
  WeaponTypeInfo s_weaponTypeInfo[] =
  {
  	{ WEAPONTYPE_KNIFE,			"Knife" },
  	{ WEAPONTYPE_PISTOL,		"Pistol" },
  	{ WEAPONTYPE_SUBMACHINEGUN,	"Submachine Gun" },	// First match is printable
  	{ WEAPONTYPE_SUBMACHINEGUN,	"submachinegun" },
  	{ WEAPONTYPE_SUBMACHINEGUN,	"smg" },
  	{ WEAPONTYPE_RIFLE,			"Rifle" },
  	{ WEAPONTYPE_SHOTGUN,		"Shotgun" },
  	{ WEAPONTYPE_SNIPER_RIFLE,	"Sniper Rifle" },	// First match is printable
  	{ WEAPONTYPE_SNIPER_RIFLE,	"SniperRifle" },
  	{ WEAPONTYPE_MACHINEGUN,	"Machine Gun" },		// First match is printable
  	{ WEAPONTYPE_MACHINEGUN,	"machinegun" },
  	{ WEAPONTYPE_MACHINEGUN,	"mg" },
  	{ WEAPONTYPE_C4,			"C4" },
  	{ WEAPONTYPE_GRENADE,		"Grenade" },
  };
  
  
  struct WeaponNameInfo
  {
  	CSWeaponID id;
  	const char *name;
  };
  
  WeaponNameInfo s_weaponNameInfo[] =
  {
  	{ WEAPON_P228,				"weapon_p228" },
  	{ WEAPON_GLOCK,				"weapon_glock" },
  	{ WEAPON_SCOUT,				"weapon_scout" },
  	{ WEAPON_HEGRENADE,			"weapon_hegrenade" },
  	{ WEAPON_XM1014,			"weapon_xm1014" },
  	{ WEAPON_C4,				"weapon_c4" },
  	{ WEAPON_MAC10,				"weapon_mac10" },
  	{ WEAPON_AUG,				"weapon_aug" },
  	{ WEAPON_SMOKEGRENADE,		"weapon_smokegrenade" },
  	{ WEAPON_ELITE,				"weapon_elite" },
  	{ WEAPON_FIVESEVEN,			"weapon_fiveseven" },
  	{ WEAPON_UMP45,				"weapon_ump45" },
  	{ WEAPON_SG550,				"weapon_sg550" },
  
  	{ WEAPON_GALIL,				"weapon_galil" },
  	{ WEAPON_FAMAS,				"weapon_famas" },
  	{ WEAPON_USP,				"weapon_usp" },
  	{ WEAPON_AWP,				"weapon_awp" },
  	{ WEAPON_MP5NAVY,			"weapon_mp5navy" },
  	{ WEAPON_M249,				"weapon_m249" },
  	{ WEAPON_M3,				"weapon_m3" },
  	{ WEAPON_M4A1,				"weapon_m4a1" },
  	{ WEAPON_TMP,				"weapon_tmp" },
  	{ WEAPON_G3SG1,				"weapon_g3sg1" },
  	{ WEAPON_FLASHBANG,			"weapon_flashbang" },
  	{ WEAPON_DEAGLE,			"weapon_deagle" },
  	{ WEAPON_SG552,				"weapon_sg552" },
  	{ WEAPON_AK47,				"weapon_ak47" },
  	{ WEAPON_KNIFE,				"weapon_knife" },
  	{ WEAPON_P90,				"weapon_p90" },
  
  	// not sure any of these are needed
  	{ WEAPON_SHIELDGUN,			"weapon_shieldgun" },
  	{ WEAPON_KEVLAR,			"weapon_kevlar" },
  	{ WEAPON_ASSAULTSUIT,		"weapon_assaultsuit" },
  	{ WEAPON_NVG,				"weapon_nvg" },
  
  	{ WEAPON_NONE,				"weapon_none" },
  };
  
  
  
  //--------------------------------------------------------------------------------------------------------------
  
  
  CCSWeaponInfo g_EquipmentInfo[MAX_EQUIPMENT];
  
  void PrepareEquipmentInfo( void )
  {
  	memset( g_EquipmentInfo, 0, ARRAYSIZE( g_EquipmentInfo ) );
  
  	g_EquipmentInfo[2].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR ) );
  	g_EquipmentInfo[2].SetDefaultPrice( KEVLAR_PRICE );
  	g_EquipmentInfo[2].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_KEVLAR ) );
  	g_EquipmentInfo[2].m_iTeam = TEAM_UNASSIGNED;
  	Q_strcpy( g_EquipmentInfo[2].szClassName, "weapon_vest" );
  
  #ifdef CLIENT_DLL
  	g_EquipmentInfo[2].iconActive = new CHudTexture;
  	g_EquipmentInfo[2].iconActive->cCharacterInFont = 't';
  #endif
  
  	g_EquipmentInfo[1].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_ASSAULTSUIT ) );
  	g_EquipmentInfo[1].SetDefaultPrice( ASSAULTSUIT_PRICE );
  	g_EquipmentInfo[1].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_ASSAULTSUIT ) );
  	g_EquipmentInfo[1].m_iTeam = TEAM_UNASSIGNED;
  	Q_strcpy( g_EquipmentInfo[1].szClassName, "weapon_vesthelm" );
  
  #ifdef CLIENT_DLL
  	g_EquipmentInfo[1].iconActive = new CHudTexture;
  	g_EquipmentInfo[1].iconActive->cCharacterInFont = 'u';
  #endif
  
  	g_EquipmentInfo[0].SetWeaponPrice( CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_NVG ) );
  	g_EquipmentInfo[0].SetPreviousPrice( CSGameRules()->GetBlackMarketPreviousPriceForWeapon( WEAPON_NVG ) );
  	g_EquipmentInfo[0].SetDefaultPrice( NVG_PRICE );
  	g_EquipmentInfo[0].m_iTeam = TEAM_UNASSIGNED;
  	Q_strcpy( g_EquipmentInfo[0].szClassName, "weapon_nvgs" );
  
  #ifdef CLIENT_DLL
  	g_EquipmentInfo[0].iconActive = new CHudTexture;
  	g_EquipmentInfo[0].iconActive->cCharacterInFont = 's';
  #endif
  
  }
  
  //--------------------------------------------------------------------------------------------------------------
  CCSWeaponInfo * GetWeaponInfo( CSWeaponID weaponID )
  {
  	if ( weaponID == WEAPON_NONE )
  		return NULL;
  
  	if ( weaponID >= WEAPON_KEVLAR )
  	{
  		int iIndex = (WEAPON_MAX - weaponID) - 1;
  
  		return &g_EquipmentInfo[iIndex];
  
  	}
  
  	const char *weaponName = WeaponIdAsString(weaponID);
  	WEAPON_FILE_INFO_HANDLE	hWpnInfo = LookupWeaponInfoSlot( weaponName );
  	if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
  	{
  		return NULL;
  	}
  
  	CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  
  	return pWeaponInfo;
  }
  
  //--------------------------------------------------------------------------------------------------------
  const char* WeaponClassAsString( CSWeaponType weaponType )
  {
  	for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
  	{
  		if ( s_weaponTypeInfo[i].type == weaponType )
  		{
  			return s_weaponTypeInfo[i].name;
  		}
  	}
  
  	return NULL;
  }
  
  
  //--------------------------------------------------------------------------------------------------------
  CSWeaponType WeaponClassFromString( const char* weaponType )
  {
  	for ( int i = 0; i < ARRAYSIZE(s_weaponTypeInfo); ++i )
  	{
  		if ( !Q_stricmp( s_weaponTypeInfo[i].name, weaponType ) )
  		{
  			return s_weaponTypeInfo[i].type;
  		}
  	}
  
  	return WEAPONTYPE_UNKNOWN;
  }
  
  
  //--------------------------------------------------------------------------------------------------------
  CSWeaponType WeaponClassFromWeaponID( CSWeaponID weaponID )
  {
  	const char *weaponStr = WeaponIDToAlias( weaponID );
  	const char *translatedAlias = GetTranslatedWeaponAlias( weaponStr );
  
  	char wpnName[128];
  	Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", translatedAlias );
  	WEAPON_FILE_INFO_HANDLE	hWpnInfo = LookupWeaponInfoSlot( wpnName );
  	if ( hWpnInfo != GetInvalidWeaponInfoHandle() )
  	{
  		CCSWeaponInfo *pWeaponInfo = dynamic_cast< CCSWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  		if ( pWeaponInfo )
  		{
  			return pWeaponInfo->m_WeaponType;
  		}
  	}
  
  	return WEAPONTYPE_UNKNOWN;
  }
  
  
  //--------------------------------------------------------------------------------------------------------
  const char * WeaponIdAsString( CSWeaponID weaponID )
  {
  	for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
  	{
  		if (s_weaponNameInfo[i].id == weaponID )
  			return s_weaponNameInfo[i].name;
  	}
  
  	return NULL;
  }
  
  
  //--------------------------------------------------------------------------------------------------------
  CSWeaponID WeaponIdFromString( const char *szWeaponName )
  {
  	for ( int i = 0; i < ARRAYSIZE(s_weaponNameInfo); ++i )
  	{
  		if ( Q_stricmp(s_weaponNameInfo[i].name, szWeaponName) == 0 )
  			return s_weaponNameInfo[i].id;
  	}
  
  	return WEAPON_NONE;
  }
  
  
  //--------------------------------------------------------------------------------------------------------
  void ParseVector( KeyValues *keyValues, const char *keyName, Vector& vec )
  {
  	vec.x = vec.y = vec.z = 0.0f;
  
  	if ( !keyValues || !keyName )
  		return;
  
  	const char *vecString = keyValues->GetString( keyName, "0 0 0" );
  	if ( vecString && *vecString )
  	{
  		float x = 0.0f, y = 0.0f, z = 0.0f;
  		if ( 3 == sscanf( vecString, "%f %f %f", &x, &y, &z ) )
  		{
  			vec.x = x;
  			vec.y = y;
  			vec.z = z;
  		}
  	}
  }
  
  
  FileWeaponInfo_t* CreateWeaponInfo()
  {
  	return new CCSWeaponInfo;
  }
  
  
  CCSWeaponInfo::CCSWeaponInfo()
  {
  	m_flMaxSpeed = 1; // This should always be set in the script.
  	m_szAddonModel[0] = 0;
  }
  
  int	CCSWeaponInfo::GetWeaponPrice( void ) const
  {
  	return m_iWeaponPrice;
  }
  
  int	CCSWeaponInfo::GetDefaultPrice( void )
  {
  	return m_iDefaultPrice;
  }
  
  int	CCSWeaponInfo::GetPrevousPrice( void )
  {
  	return m_iPreviousPrice;
  }
  
  
  void CCSWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName )
  {
  	BaseClass::Parse( pKeyValuesData, szWeaponName );
  
  	m_flMaxSpeed = (float)pKeyValuesData->GetInt( "MaxPlayerSpeed", 1 );
  
  	m_iDefaultPrice = m_iWeaponPrice = pKeyValuesData->GetInt( "WeaponPrice", -1 );
  	if ( m_iWeaponPrice == -1 )
  	{
  		// This weapon should have the price in its script.
  		Assert( false );
  	}
  
  	if ( CSGameRules()->IsBlackMarket() )
  	{
  		CSWeaponID iWeaponID = AliasToWeaponID( GetTranslatedWeaponAlias ( szWeaponName ) );
  
  		m_iDefaultPrice = m_iWeaponPrice;
  		m_iPreviousPrice = CSGameRules()->GetBlackMarketPreviousPriceForWeapon( iWeaponID );
  		m_iWeaponPrice = CSGameRules()->GetBlackMarketPriceForWeapon( iWeaponID );
  	}
  		
  	m_flArmorRatio				= pKeyValuesData->GetFloat( "WeaponArmorRatio", 1 );
  	m_iCrosshairMinDistance		= pKeyValuesData->GetInt( "CrosshairMinDistance", 4 );
  	m_iCrosshairDeltaDistance	= pKeyValuesData->GetInt( "CrosshairDeltaDistance", 3 );
  	m_bCanUseWithShield			= !!pKeyValuesData->GetInt( "CanEquipWithShield", false );
  	m_flMuzzleScale				= pKeyValuesData->GetFloat( "MuzzleFlashScale", 1 );
  
  	const char *pMuzzleFlashStyle = pKeyValuesData->GetString( "MuzzleFlashStyle", "CS_MUZZLEFLASH_NORM" );
  	
  	if( pMuzzleFlashStyle )
  	{
  		if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_X" ) == 0 )
  		{
  			m_iMuzzleFlashStyle = CS_MUZZLEFLASH_X;
  		}
  		else if ( Q_stricmp( pMuzzleFlashStyle, "CS_MUZZLEFLASH_NONE" ) == 0 )
  		{
  			m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NONE;
  		}
  		else
  		{
  			m_iMuzzleFlashStyle = CS_MUZZLEFLASH_NORM;
  		}
  	}
  	else
  	{
  		Assert( false );
  	}
  
  	m_iPenetration		= pKeyValuesData->GetInt( "Penetration", 1 );
  	m_iDamage			= pKeyValuesData->GetInt( "Damage", 42 ); // Douglas Adams 1952 - 2001
  	m_flRange			= pKeyValuesData->GetFloat( "Range", 8192.0f );
  	m_flRangeModifier	= pKeyValuesData->GetFloat( "RangeModifier", 0.98f );
  	m_iBullets			= pKeyValuesData->GetInt( "Bullets", 1 );
  	m_flCycleTime		= pKeyValuesData->GetFloat( "CycleTime", 0.15 );
  	m_bAccuracyQuadratic= pKeyValuesData->GetInt( "AccuracyQuadratic", 0 );
  	m_flAccuracyDivisor	= pKeyValuesData->GetFloat( "AccuracyDivisor", -1 ); // -1 = off
  	m_flAccuracyOffset	= pKeyValuesData->GetFloat( "AccuracyOffset", 0 );
  	m_flMaxInaccuracy	= pKeyValuesData->GetFloat( "MaxInaccuracy", 0 );
  
  	// new accuracy model parameters
  	m_fSpread[0]				= pKeyValuesData->GetFloat("Spread", 0.0f);
  	m_fInaccuracyCrouch[0]		= pKeyValuesData->GetFloat("InaccuracyCrouch", 0.0f);
  	m_fInaccuracyStand[0]		= pKeyValuesData->GetFloat("InaccuracyStand", 0.0f);
  	m_fInaccuracyJump[0]		= pKeyValuesData->GetFloat("InaccuracyJump", 0.0f);
  	m_fInaccuracyLand[0]		= pKeyValuesData->GetFloat("InaccuracyLand", 0.0f);
  	m_fInaccuracyLadder[0]		= pKeyValuesData->GetFloat("InaccuracyLadder", 0.0f);
  	m_fInaccuracyImpulseFire[0]	= pKeyValuesData->GetFloat("InaccuracyFire", 0.0f);
  	m_fInaccuracyMove[0]		= pKeyValuesData->GetFloat("InaccuracyMove", 0.0f);
  
  	m_fSpread[1]				= pKeyValuesData->GetFloat("SpreadAlt", 0.0f);
  	m_fInaccuracyCrouch[1]		= pKeyValuesData->GetFloat("InaccuracyCrouchAlt", 0.0f);
  	m_fInaccuracyStand[1]		= pKeyValuesData->GetFloat("InaccuracyStandAlt", 0.0f);
  	m_fInaccuracyJump[1]		= pKeyValuesData->GetFloat("InaccuracyJumpAlt", 0.0f);
  	m_fInaccuracyLand[1]		= pKeyValuesData->GetFloat("InaccuracyLandAlt", 0.0f);
  	m_fInaccuracyLadder[1]		= pKeyValuesData->GetFloat("InaccuracyLadderAlt", 0.0f);
  	m_fInaccuracyImpulseFire[1]	= pKeyValuesData->GetFloat("InaccuracyFireAlt", 0.0f);
  	m_fInaccuracyMove[1]		= pKeyValuesData->GetFloat("InaccuracyMoveAlt", 0.0f);
  
  	m_fInaccuracyReload			= pKeyValuesData->GetFloat("InaccuracyReload", 0.0f);
  	m_fInaccuracyAltSwitch		= pKeyValuesData->GetFloat("InaccuracyAltSwitch", 0.0f);
  
  	m_fRecoveryTimeCrouch		= pKeyValuesData->GetFloat("RecoveryTimeCrouch", 1.0f);
  	m_fRecoveryTimeStand		= pKeyValuesData->GetFloat("RecoveryTimeStand", 1.0f);
  
  	m_flTimeToIdleAfterFire	= pKeyValuesData->GetFloat( "TimeToIdle", 2 );
  	m_flIdleInterval	= pKeyValuesData->GetFloat( "IdleInterval", 20 );
  
  	// Figure out what team can have this weapon.
  	m_iTeam = TEAM_UNASSIGNED;
  	const char *pTeam = pKeyValuesData->GetString( "Team", NULL );
  	if ( pTeam )
  	{
  		if ( Q_stricmp( pTeam, "CT" ) == 0 )
  		{
  			m_iTeam = TEAM_CT;
  		}
  		else if ( Q_stricmp( pTeam, "TERRORIST" ) == 0 )
  		{
  			m_iTeam = TEAM_TERRORIST;
  		}
  		else if ( Q_stricmp( pTeam, "ANY" ) == 0 )
  		{
  			m_iTeam = TEAM_UNASSIGNED;
  		}
  		else
  		{
  			Assert( false );
  		}
  	}
  	else
  	{
  		Assert( false );
  	}
  
  	
  	const char *pWrongTeamMsg = pKeyValuesData->GetString( "WrongTeamMsg", "" );
  	Q_strncpy( m_WrongTeamMsg, pWrongTeamMsg, sizeof( m_WrongTeamMsg ) );
  
  	const char *pShieldViewModel = pKeyValuesData->GetString( "shieldviewmodel", "" );
  	Q_strncpy( m_szShieldViewModel, pShieldViewModel, sizeof( m_szShieldViewModel ) );
  	
  	const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "m4" );
  	Q_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) );
  
  	// Default is 2000.
  	m_flBotAudibleRange = pKeyValuesData->GetFloat( "BotAudibleRange", 2000.0f );
  	
  	const char *pTypeString = pKeyValuesData->GetString( "WeaponType", "" );
  	m_WeaponType = WeaponClassFromString(pTypeString);
  
  	m_bFullAuto = pKeyValuesData->GetBool("FullAuto");
  
  	// Read the addon model.
  	Q_strncpy( m_szAddonModel, pKeyValuesData->GetString( "AddonModel" ), sizeof( m_szAddonModel ) );
  
  	// Read the dropped model.
  	Q_strncpy( m_szDroppedModel, pKeyValuesData->GetString( "DroppedModel" ), sizeof( m_szDroppedModel ) );
  
  	// Read the silencer model.
  	Q_strncpy( m_szSilencerModel, pKeyValuesData->GetString( "SilencerModel" ), sizeof( m_szSilencerModel ) );
  
  #ifndef CLIENT_DLL
  	// Enforce consistency for the weapon here, since that way we don't need to save off the model bounds
  	// for all time.
  	// Moved to pure_server_minimal.txt
  //	engine->ForceExactFile( UTIL_VarArgs("scripts/%s.ctx", szWeaponName ) );
  
  	// Model bounds are rounded to the nearest integer, then extended by 1
  	engine->ForceModelBounds( szWorldModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  	if ( m_szAddonModel[0] )
  	{
  		engine->ForceModelBounds( m_szAddonModel, Vector( -5, -5, -6 ), Vector( 13, 5, 7 ) );
  	}
  	if ( m_szSilencerModel[0] )
  	{
  		engine->ForceModelBounds( m_szSilencerModel, Vector( -15, -12, -18 ), Vector( 44, 16, 19 ) );
  	}
  #endif // !CLIENT_DLL
  }
  
  
  