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.

366 lines
9.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Player for HL1.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "sdk_player.h"
  9. #include "sdk_gamerules.h"
  10. #include "weapon_sdkbase.h"
  11. #include "predicted_viewmodel.h"
  12. #include "iservervehicle.h"
  13. #include "viewport_panel_names.h"
  14. extern int gEvilImpulse101;
  15. ConVar sv_motd_unload_on_dismissal( "sv_motd_unload_on_dismissal", "0", 0, "If enabled, the MOTD contents will be unloaded when the player closes the MOTD." );
  16. #define SDK_PLAYER_MODEL "models/player/terror.mdl"
  17. // -------------------------------------------------------------------------------- //
  18. // Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
  19. // -------------------------------------------------------------------------------- //
  20. class CTEPlayerAnimEvent : public CBaseTempEntity
  21. {
  22. public:
  23. DECLARE_CLASS( CTEPlayerAnimEvent, CBaseTempEntity );
  24. DECLARE_SERVERCLASS();
  25. CTEPlayerAnimEvent( const char *name ) : CBaseTempEntity( name )
  26. {
  27. }
  28. CNetworkHandle( CBasePlayer, m_hPlayer );
  29. CNetworkVar( int, m_iEvent );
  30. CNetworkVar( int, m_nData );
  31. };
  32. #define THROWGRENADE_COUNTER_BITS 3
  33. IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEPlayerAnimEvent, DT_TEPlayerAnimEvent )
  34. SendPropEHandle( SENDINFO( m_hPlayer ) ),
  35. SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ),
  36. SendPropInt( SENDINFO( m_nData ), 32 )
  37. END_SEND_TABLE()
  38. static CTEPlayerAnimEvent g_TEPlayerAnimEvent( "PlayerAnimEvent" );
  39. void TE_PlayerAnimEvent( CBasePlayer *pPlayer, PlayerAnimEvent_t event, int nData )
  40. {
  41. CPVSFilter filter( (const Vector&)pPlayer->EyePosition() );
  42. g_TEPlayerAnimEvent.m_hPlayer = pPlayer;
  43. g_TEPlayerAnimEvent.m_iEvent = event;
  44. g_TEPlayerAnimEvent.m_nData = nData;
  45. g_TEPlayerAnimEvent.Create( filter, 0 );
  46. }
  47. // -------------------------------------------------------------------------------- //
  48. // Tables.
  49. // -------------------------------------------------------------------------------- //
  50. BEGIN_DATADESC( CSDKPlayer )
  51. DEFINE_THINKFUNC( SDKPushawayThink ),
  52. END_DATADESC()
  53. LINK_ENTITY_TO_CLASS( player, CSDKPlayer );
  54. PRECACHE_REGISTER(player);
  55. BEGIN_SEND_TABLE_NOBASE( CSDKPlayer, DT_SDKLocalPlayerExclusive )
  56. SendPropInt( SENDINFO( m_iShotsFired ), 8, SPROP_UNSIGNED ),
  57. END_SEND_TABLE()
  58. IMPLEMENT_SERVERCLASS_ST( CSDKPlayer, DT_SDKPlayer )
  59. SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
  60. SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ),
  61. SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
  62. SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
  63. SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ),
  64. // playeranimstate and clientside animation takes care of these on the client
  65. SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
  66. SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  67. // Data that only gets sent to the local player.
  68. SendPropDataTable( "sdklocaldata", 0, &REFERENCE_SEND_TABLE(DT_SDKLocalPlayerExclusive), SendProxy_SendLocalDataTable ),
  69. SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11 ),
  70. SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11 ),
  71. SendPropEHandle( SENDINFO( m_hRagdoll ) ),
  72. SendPropInt( SENDINFO( m_iThrowGrenadeCounter ), THROWGRENADE_COUNTER_BITS, SPROP_UNSIGNED ),
  73. END_SEND_TABLE()
  74. class CSDKRagdoll : public CBaseAnimatingOverlay
  75. {
  76. public:
  77. DECLARE_CLASS( CSDKRagdoll, CBaseAnimatingOverlay );
  78. DECLARE_SERVERCLASS();
  79. // Transmit ragdolls to everyone.
  80. virtual int UpdateTransmitState()
  81. {
  82. return SetTransmitState( FL_EDICT_ALWAYS );
  83. }
  84. public:
  85. // In case the client has the player entity, we transmit the player index.
  86. // In case the client doesn't have it, we transmit the player's model index, origin, and angles
  87. // so they can create a ragdoll in the right place.
  88. CNetworkHandle( CBaseEntity, m_hPlayer ); // networked entity handle
  89. CNetworkVector( m_vecRagdollVelocity );
  90. CNetworkVector( m_vecRagdollOrigin );
  91. };
  92. LINK_ENTITY_TO_CLASS( sdk_ragdoll, CSDKRagdoll );
  93. IMPLEMENT_SERVERCLASS_ST_NOBASE( CSDKRagdoll, DT_SDKRagdoll )
  94. SendPropVector( SENDINFO(m_vecRagdollOrigin), -1, SPROP_COORD ),
  95. SendPropEHandle( SENDINFO( m_hPlayer ) ),
  96. SendPropModelIndex( SENDINFO( m_nModelIndex ) ),
  97. SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ),
  98. SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ),
  99. SendPropVector( SENDINFO( m_vecRagdollVelocity ) )
  100. END_SEND_TABLE()
  101. // -------------------------------------------------------------------------------- //
  102. void cc_CreatePredictionError_f()
  103. {
  104. CBaseEntity *pEnt = CBaseEntity::Instance( 1 );
  105. pEnt->SetAbsOrigin( pEnt->GetAbsOrigin() + Vector( 63, 0, 0 ) );
  106. }
  107. ConCommand cc_CreatePredictionError( "CreatePredictionError", cc_CreatePredictionError_f, "Create a prediction error", FCVAR_CHEAT );
  108. CSDKPlayer::CSDKPlayer()
  109. {
  110. m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true );
  111. UseClientSideAnimation();
  112. m_angEyeAngles.Init();
  113. SetViewOffset( SDK_PLAYER_VIEW_OFFSET );
  114. m_iThrowGrenadeCounter = 0;
  115. }
  116. CSDKPlayer::~CSDKPlayer()
  117. {
  118. m_PlayerAnimState->Release();
  119. }
  120. CSDKPlayer *CSDKPlayer::CreatePlayer( const char *className, edict_t *ed )
  121. {
  122. CSDKPlayer::s_PlayerEdict = ed;
  123. return (CSDKPlayer*)CreateEntityByName( className );
  124. }
  125. void CSDKPlayer::LeaveVehicle( const Vector &vecExitPoint, const QAngle &vecExitAngles )
  126. {
  127. BaseClass::LeaveVehicle( vecExitPoint, vecExitAngles );
  128. //teleport physics shadow too
  129. // Vector newPos = GetAbsOrigin();
  130. // QAngle newAng = GetAbsAngles();
  131. // Teleport( &newPos, &newAng, &vec3_origin );
  132. }
  133. void CSDKPlayer::PreThink(void)
  134. {
  135. // Riding a vehicle?
  136. if ( IsInAVehicle() )
  137. {
  138. // make sure we update the client, check for timed damage and update suit even if we are in a vehicle
  139. UpdateClientData();
  140. CheckTimeBasedDamage();
  141. // Allow the suit to recharge when in the vehicle.
  142. CheckSuitUpdate();
  143. WaterMove();
  144. return;
  145. }
  146. BaseClass::PreThink();
  147. }
  148. void CSDKPlayer::PostThink()
  149. {
  150. BaseClass::PostThink();
  151. QAngle angles = GetLocalAngles();
  152. angles[PITCH] = 0;
  153. SetLocalAngles( angles );
  154. // Store the eye angles pitch so the client can compute its animation state correctly.
  155. m_angEyeAngles = EyeAngles();
  156. m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
  157. }
  158. void CSDKPlayer::Precache()
  159. {
  160. PrecacheModel( SDK_PLAYER_MODEL );
  161. BaseClass::Precache();
  162. }
  163. void CSDKPlayer::Spawn()
  164. {
  165. SetModel( SDK_PLAYER_MODEL );
  166. SetMoveType( MOVETYPE_WALK );
  167. RemoveSolidFlags( FSOLID_NOT_SOLID );
  168. m_hRagdoll = NULL;
  169. BaseClass::Spawn();
  170. }
  171. void CSDKPlayer::InitialSpawn( void )
  172. {
  173. BaseClass::InitialSpawn();
  174. const ConVar *hostname = cvar->FindVar( "hostname" );
  175. const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY";
  176. // open info panel on client showing MOTD:
  177. KeyValues *data = new KeyValues("data");
  178. data->SetString( "title", title ); // info panel title
  179. data->SetString( "type", "1" ); // show userdata from stringtable entry
  180. data->SetString( "msg", "motd" ); // use this stringtable entry
  181. data->SetInt( "cmd", TEXTWINDOW_CMD_IMPULSE101 );// exec this command if panel closed
  182. data->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() );
  183. ShowViewPortPanel( PANEL_INFO, true, data );
  184. data->deleteThis();
  185. }
  186. void CSDKPlayer::Event_Killed( const CTakeDamageInfo &info )
  187. {
  188. // Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
  189. // because we still want to transmit to the clients in our PVS.
  190. BaseClass::Event_Killed( info );
  191. CreateRagdollEntity();
  192. }
  193. void CSDKPlayer::CreateRagdollEntity()
  194. {
  195. // If we already have a ragdoll, don't make another one.
  196. CSDKRagdoll *pRagdoll = dynamic_cast< CSDKRagdoll* >( m_hRagdoll.Get() );
  197. if ( !pRagdoll )
  198. {
  199. // create a new one
  200. pRagdoll = dynamic_cast< CSDKRagdoll* >( CreateEntityByName( "sdk_ragdoll" ) );
  201. }
  202. if ( pRagdoll )
  203. {
  204. pRagdoll->m_hPlayer = this;
  205. pRagdoll->m_vecRagdollOrigin = GetAbsOrigin();
  206. pRagdoll->m_vecRagdollVelocity = GetAbsVelocity();
  207. pRagdoll->m_nModelIndex = m_nModelIndex;
  208. pRagdoll->m_nForceBone = m_nForceBone;
  209. pRagdoll->m_vecForce = Vector(0,0,0);
  210. }
  211. // ragdolls will be removed on round restart automatically
  212. m_hRagdoll = pRagdoll;
  213. }
  214. void CSDKPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
  215. {
  216. if ( event == PLAYERANIMEVENT_THROW_GRENADE )
  217. {
  218. // Grenade throwing has to synchronize exactly with the player's grenade weapon going away,
  219. // and events get delayed a bit, so we let CCSPlayerAnimState pickup the change to this
  220. // variable.
  221. m_iThrowGrenadeCounter = (m_iThrowGrenadeCounter+1) % (1<<THROWGRENADE_COUNTER_BITS);
  222. }
  223. else
  224. {
  225. m_PlayerAnimState->DoAnimationEvent( event, nData );
  226. TE_PlayerAnimEvent( this, event, nData ); // Send to any clients who can see this guy.
  227. }
  228. }
  229. CWeaponSDKBase* CSDKPlayer::GetActiveSDKWeapon() const
  230. {
  231. return dynamic_cast< CWeaponSDKBase* >( GetActiveWeapon() );
  232. }
  233. void CSDKPlayer::CreateViewModel( int index /*=0*/ )
  234. {
  235. Assert( index >= 0 && index < MAX_VIEWMODELS );
  236. if ( GetViewModel( index ) )
  237. return;
  238. CPredictedViewModel *vm = ( CPredictedViewModel * )CreateEntityByName( "predicted_viewmodel" );
  239. if ( vm )
  240. {
  241. vm->SetAbsOrigin( GetAbsOrigin() );
  242. vm->SetOwner( this );
  243. vm->SetIndex( index );
  244. DispatchSpawn( vm );
  245. vm->FollowEntity( this, false );
  246. m_hViewModel.Set( index, vm );
  247. }
  248. }
  249. void CSDKPlayer::CheatImpulseCommands( int iImpulse )
  250. {
  251. if ( iImpulse != 101 )
  252. {
  253. BaseClass::CheatImpulseCommands( iImpulse );
  254. return ;
  255. }
  256. gEvilImpulse101 = true;
  257. EquipSuit();
  258. GiveNamedItem( "weapon_mp5" );
  259. GiveNamedItem( "weapon_grenade" );
  260. GiveNamedItem( "weapon_shotgun" );
  261. // Give the player everything!
  262. GiveAmmo( 90, AMMO_BULLETS );
  263. GiveAmmo( 3, AMMO_GRENADE );
  264. if ( GetHealth() < 100 )
  265. {
  266. TakeHealth( 25, DMG_GENERIC );
  267. }
  268. gEvilImpulse101 = false;
  269. }
  270. void CSDKPlayer::FlashlightTurnOn( void )
  271. {
  272. AddEffects( EF_DIMLIGHT );
  273. }
  274. void CSDKPlayer::FlashlightTurnOff( void )
  275. {
  276. RemoveEffects( EF_DIMLIGHT );
  277. }
  278. int CSDKPlayer::FlashlightIsOn( void )
  279. {
  280. return IsEffectActive( EF_DIMLIGHT );
  281. }