Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
9.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_shareddefs.h"
  8. #include "tf_classdata.h"
  9. extern bool UseHWMorphModels();
  10. // Player class files
  11. #define TF_CLASS_UNDEFINED_FILE ""
  12. #define TF_CLASS_SCOUT_FILE "scripts/playerclasses/scout"
  13. #define TF_CLASS_SNIPER_FILE "scripts/playerclasses/sniper"
  14. #define TF_CLASS_SOLDIER_FILE "scripts/playerclasses/soldier"
  15. #define TF_CLASS_DEMOMAN_FILE "scripts/playerclasses/demoman"
  16. #define TF_CLASS_MEDIC_FILE "scripts/playerclasses/medic"
  17. #define TF_CLASS_HEAVYWEAPONS_FILE "scripts/playerclasses/heavyweapons"
  18. #define TF_CLASS_PYRO_FILE "scripts/playerclasses/pyro"
  19. #define TF_CLASS_SPY_FILE "scripts/playerclasses/spy"
  20. #define TF_CLASS_ENGINEER_FILE "scripts/playerclasses/engineer"
  21. #define TF_CLASS_CIVILIAN_FILE "scripts/playerclasses/civilian"
  22. const char *s_aPlayerClassFiles[] =
  23. {
  24. TF_CLASS_UNDEFINED_FILE,
  25. TF_CLASS_SCOUT_FILE,
  26. TF_CLASS_SNIPER_FILE,
  27. TF_CLASS_SOLDIER_FILE,
  28. TF_CLASS_DEMOMAN_FILE,
  29. TF_CLASS_MEDIC_FILE,
  30. TF_CLASS_HEAVYWEAPONS_FILE,
  31. TF_CLASS_PYRO_FILE,
  32. TF_CLASS_SPY_FILE,
  33. TF_CLASS_ENGINEER_FILE,
  34. TF_CLASS_CIVILIAN_FILE
  35. };
  36. CTFPlayerClassDataMgr s_TFPlayerClassDataMgr;
  37. CTFPlayerClassDataMgr *g_pTFPlayerClassDataMgr = &s_TFPlayerClassDataMgr;
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Constructor
  40. //-----------------------------------------------------------------------------
  41. TFPlayerClassData_t::TFPlayerClassData_t()
  42. {
  43. m_szClassName[0] = '\0';
  44. m_szModelName[0] = '\0';
  45. m_szHWMModelName[0] = '\0';
  46. m_szHandModelName[0] = '\0';
  47. m_szLocalizableName[0] = '\0';
  48. m_flMaxSpeed = 0.0f;
  49. m_nMaxHealth = 0;
  50. m_nMaxArmor = 0;
  51. #ifdef GAME_DLL
  52. for ( int i = 0; i < ARRAYSIZE( m_szDeathSound ); ++i )
  53. {
  54. m_szDeathSound[ i ][ 0 ] = '\0';
  55. }
  56. #endif
  57. for ( int iWeapon = 0; iWeapon < TF_PLAYER_WEAPON_COUNT; ++iWeapon )
  58. {
  59. m_aWeapons[iWeapon] = TF_WEAPON_NONE;
  60. }
  61. for ( int iGrenade = 0; iGrenade < TF_PLAYER_GRENADE_COUNT; ++iGrenade )
  62. {
  63. m_aGrenades[iGrenade] = TF_WEAPON_NONE;
  64. }
  65. for ( int iAmmo = 0; iAmmo < TF_AMMO_COUNT; ++iAmmo )
  66. {
  67. m_aAmmoMax[iAmmo] = TF_AMMO_DUMMY;
  68. }
  69. for ( int iBuildable = 0; iBuildable < TF_PLAYER_BLUEPRINT_COUNT; ++iBuildable )
  70. {
  71. m_aBuildable[iBuildable] = OBJ_LAST;
  72. }
  73. m_bParsed = false;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose:
  77. //-----------------------------------------------------------------------------
  78. const char *TFPlayerClassData_t::GetModelName() const
  79. {
  80. #ifdef CLIENT_DLL
  81. if ( UseHWMorphModels() )
  82. {
  83. if ( m_szHWMModelName[0] != '\0' )
  84. {
  85. return m_szHWMModelName;
  86. }
  87. }
  88. return m_szModelName;
  89. #else
  90. return m_szModelName;
  91. #endif
  92. }
  93. #ifdef GAME_DLL
  94. const char *TFPlayerClassData_t::GetDeathSound( int nType )
  95. {
  96. return m_szDeathSound[ nType ];
  97. }
  98. #endif
  99. //-----------------------------------------------------------------------------
  100. // Purpose:
  101. //-----------------------------------------------------------------------------
  102. void TFPlayerClassData_t::Parse( const char *szName )
  103. {
  104. // Have we parsed this file already?
  105. if ( m_bParsed )
  106. return;
  107. // Parse class file.
  108. const unsigned char *pKey = GetTFEncryptionKey();
  109. KeyValues *pKV = ReadEncryptedKVFile( filesystem, szName, pKey );
  110. if ( pKV )
  111. {
  112. ParseData( pKV );
  113. pKV->deleteThis();
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void TFPlayerClassData_t::ParseData( KeyValues *pKeyValuesData )
  120. {
  121. // Attributes.
  122. Q_strncpy( m_szClassName, pKeyValuesData->GetString( "name" ), TF_NAME_LENGTH );
  123. // Load the high res model or the lower res model.
  124. if ( !IsX360() )
  125. {
  126. Q_strncpy( m_szHWMModelName, pKeyValuesData->GetString( "model_hwm" ), TF_NAME_LENGTH );
  127. }
  128. Q_strncpy( m_szModelName, pKeyValuesData->GetString( "model" ), TF_NAME_LENGTH );
  129. Q_strncpy( m_szHandModelName, pKeyValuesData->GetString( "model_hands" ), TF_NAME_LENGTH );
  130. Q_strncpy( m_szLocalizableName, pKeyValuesData->GetString( "localize_name" ), TF_NAME_LENGTH );
  131. m_flMaxSpeed = pKeyValuesData->GetFloat( "speed_max" );
  132. m_nMaxHealth = pKeyValuesData->GetInt( "health_max" );
  133. m_nMaxArmor = pKeyValuesData->GetInt( "armor_max" );
  134. // Weapons.
  135. int i;
  136. char buf[32];
  137. for ( i=0;i<TF_PLAYER_WEAPON_COUNT;i++ )
  138. {
  139. Q_snprintf( buf, sizeof(buf), "weapon%d", i+1 );
  140. m_aWeapons[i] = GetWeaponId( pKeyValuesData->GetString( buf ) );
  141. }
  142. // Grenades.
  143. m_aGrenades[0] = GetWeaponId( pKeyValuesData->GetString( "grenade1" ) );
  144. m_aGrenades[1] = GetWeaponId( pKeyValuesData->GetString( "grenade2" ) );
  145. // Ammo Max.
  146. KeyValues *pAmmoKeyValuesData = pKeyValuesData->FindKey( "AmmoMax" );
  147. if ( pAmmoKeyValuesData )
  148. {
  149. for ( int iAmmo = 1; iAmmo < TF_AMMO_COUNT; ++iAmmo )
  150. {
  151. m_aAmmoMax[iAmmo] = pAmmoKeyValuesData->GetInt( GetAmmoName( iAmmo ), 0 );
  152. }
  153. }
  154. // Buildables
  155. for ( i=0;i<TF_PLAYER_BLUEPRINT_COUNT;i++ )
  156. {
  157. Q_snprintf( buf, sizeof(buf), "buildable%d", i+1 );
  158. m_aBuildable[i] = GetBuildableId( pKeyValuesData->GetString( buf ) );
  159. }
  160. // Temp animation flags
  161. m_bDontDoAirwalk = ( pKeyValuesData->GetInt( "DontDoAirwalk", 0 ) > 0 );
  162. m_bDontDoNewJump = ( pKeyValuesData->GetInt( "DontDoNewJump", 0 ) > 0 );
  163. m_vecThirdPersonOffset.x = pKeyValuesData->GetFloat( "cameraoffset_forward" );
  164. m_vecThirdPersonOffset.y = pKeyValuesData->GetFloat( "cameraoffset_right" );
  165. m_vecThirdPersonOffset.z = pKeyValuesData->GetFloat( "cameraoffset_up" );
  166. #ifdef GAME_DLL // right now we only emit these sounds from server. if that changes we can do this in both dlls
  167. // Death Sounds
  168. Q_strncpy( m_szDeathSound[ DEATH_SOUND_GENERIC ], pKeyValuesData->GetString( "sound_death", "Player.Death" ), MAX_PLAYERCLASS_SOUND_LENGTH );
  169. Q_strncpy( m_szDeathSound[ DEATH_SOUND_CRIT ], pKeyValuesData->GetString( "sound_crit_death", "TFPlayer.CritDeath" ), MAX_PLAYERCLASS_SOUND_LENGTH );
  170. Q_strncpy( m_szDeathSound[ DEATH_SOUND_MELEE ], pKeyValuesData->GetString( "sound_melee_death", "Player.MeleeDeath" ), MAX_PLAYERCLASS_SOUND_LENGTH );
  171. Q_strncpy( m_szDeathSound[ DEATH_SOUND_EXPLOSION ], pKeyValuesData->GetString( "sound_explosion_death", "Player.ExplosionDeath" ), MAX_PLAYERCLASS_SOUND_LENGTH );
  172. #endif
  173. // The file has been parsed.
  174. m_bParsed = true;
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. void TFPlayerClassData_t::AddAdditionalPlayerDeathSounds( void )
  180. {
  181. #ifdef GAME_DLL
  182. for ( int i = DEATH_SOUND_FIRST; i <= DEATH_SOUND_LAST; ++i )
  183. {
  184. CopySoundNameWithModifierToken( m_szDeathSound[ i + DEATH_SOUND_MVM_FIRST ], m_szDeathSound[ i ], ARRAYSIZE( m_szDeathSound[0] ), "MVM_" );
  185. CopySoundNameWithModifierToken( m_szDeathSound[ i + DEATH_SOUND_GIANT_MVM_FIRST ], m_szDeathSound[ i ], ARRAYSIZE( m_szDeathSound[0] ), "M_MVM_" );
  186. }
  187. #endif
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose:
  191. //-----------------------------------------------------------------------------
  192. CTFPlayerClassDataMgr::CTFPlayerClassDataMgr()
  193. {
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. //-----------------------------------------------------------------------------
  198. bool CTFPlayerClassDataMgr::Init( void )
  199. {
  200. // Special case the undefined class.
  201. TFPlayerClassData_t *pClassData = &m_aTFPlayerClassData[TF_CLASS_UNDEFINED];
  202. Assert( pClassData );
  203. Q_strncpy( pClassData->m_szClassName, "undefined", TF_NAME_LENGTH );
  204. Q_strncpy( pClassData->m_szModelName, "models/player/scout.mdl", TF_NAME_LENGTH ); // Undefined players still need a model
  205. Q_strncpy( pClassData->m_szLocalizableName, "undefined", TF_NAME_LENGTH );
  206. // Initialize the classes.
  207. for ( int iClass = 1; iClass < TF_CLASS_COUNT_ALL; ++iClass )
  208. {
  209. COMPILE_TIME_ASSERT( ARRAYSIZE( s_aPlayerClassFiles ) == TF_CLASS_COUNT_ALL );
  210. pClassData = &m_aTFPlayerClassData[iClass];
  211. Assert( pClassData );
  212. pClassData->Parse( s_aPlayerClassFiles[iClass] );
  213. }
  214. return true;
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose: Helper function to get player class data.
  218. //-----------------------------------------------------------------------------
  219. TFPlayerClassData_t *CTFPlayerClassDataMgr::Get( unsigned int iClass )
  220. {
  221. Assert ( iClass < TF_CLASS_COUNT_ALL );
  222. return &m_aTFPlayerClassData[iClass];
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose:
  226. //-----------------------------------------------------------------------------
  227. TFPlayerClassData_t *GetPlayerClassData( unsigned int iClass )
  228. {
  229. return g_pTFPlayerClassDataMgr->Get( iClass );
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose:
  233. //-----------------------------------------------------------------------------
  234. void CTFPlayerClassDataMgr::AddAdditionalPlayerDeathSounds( void )
  235. {
  236. for ( int iClass = 1; iClass < TF_CLASS_COUNT_ALL; ++iClass )
  237. {
  238. TFPlayerClassData_t *pClassData = &m_aTFPlayerClassData[iClass];
  239. Assert( pClassData );
  240. pClassData->AddAdditionalPlayerDeathSounds();
  241. }
  242. }