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.

251 lines
5.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Definition for client-side advisor.
  4. //
  5. //=====================================================================================//
  6. #include "cbase.h"
  7. // this file contains the definitions for the message ID constants (eg ADVISOR_MSG_START_BEAM etc)
  8. #include "npc_advisor_shared.h"
  9. #if NPC_ADVISOR_HAS_BEHAVIOR
  10. #include "particles_simple.h"
  11. #include "citadel_effects_shared.h"
  12. #include "particles_attractor.h"
  13. #include "clienteffectprecachesystem.h"
  14. #include "c_te_effect_dispatch.h"
  15. #include "c_ai_basenpc.h"
  16. #include "dlight.h"
  17. #include "iefx.h"
  18. //-----------------------------------------------------------------------------
  19. // Purpose: unpack a networked entity index into a basehandle.
  20. //-----------------------------------------------------------------------------
  21. inline C_BaseEntity *IndexToEntity( int eindex )
  22. {
  23. return ClientEntityList().GetBaseEntityFromHandle(ClientEntityList().EntIndexToHandle(eindex));
  24. }
  25. #define ADVISOR_ELIGHT_CVARS 1 // enable/disable tuning advisor elight with console variables
  26. #if ADVISOR_ELIGHT_CVARS
  27. ConVar advisor_elight_e("advisor_elight_e","3");
  28. ConVar advisor_elight_rfeet("advisor_elight_rfeet","52");
  29. #endif
  30. /*! Client-side reflection of the advisor class.
  31. */
  32. class C_NPC_Advisor : public C_AI_BaseNPC
  33. {
  34. DECLARE_CLASS( C_NPC_Advisor, C_AI_BaseNPC );
  35. DECLARE_CLIENTCLASS();
  36. public:
  37. // Server to client message received
  38. virtual void ReceiveMessage( int classID, bf_read &msg );
  39. virtual void ClientThink( void );
  40. private:
  41. /*
  42. // broken into its own function so I can move it if necesasry
  43. void Initialize();
  44. */
  45. // start/stop beam particle effect from me to a pelting object
  46. void StartBeamFX( C_BaseEntity *pOnEntity );
  47. void StopBeamFX( C_BaseEntity *pOnEntity );
  48. void StartElight();
  49. void StopElight();
  50. int m_ElightKey; // test using an elight to make the escape sequence more visible. 0 is invalid.
  51. };
  52. IMPLEMENT_CLIENTCLASS_DT( C_NPC_Advisor, DT_NPC_Advisor, CNPC_Advisor )
  53. END_RECV_TABLE()
  54. // Server to client message received
  55. void C_NPC_Advisor::ReceiveMessage( int classID, bf_read &msg )
  56. {
  57. if ( classID != GetClientClass()->m_ClassID )
  58. {
  59. // message is for subclass
  60. BaseClass::ReceiveMessage( classID, msg );
  61. return;
  62. }
  63. int messageType = msg.ReadByte();
  64. switch( messageType )
  65. {
  66. case ADVISOR_MSG_START_BEAM:
  67. {
  68. int eindex = msg.ReadLong();
  69. StartBeamFX(IndexToEntity(eindex));
  70. }
  71. break;
  72. case ADVISOR_MSG_STOP_BEAM:
  73. {
  74. int eindex = msg.ReadLong();
  75. StopBeamFX(IndexToEntity(eindex));
  76. }
  77. break;
  78. case ADVISOR_MSG_STOP_ALL_BEAMS:
  79. {
  80. ParticleProp()->StopEmission();
  81. }
  82. break;
  83. case ADVISOR_MSG_START_ELIGHT:
  84. {
  85. StartElight();
  86. }
  87. break;
  88. case ADVISOR_MSG_STOP_ELIGHT:
  89. {
  90. StopElight();
  91. }
  92. break;
  93. default:
  94. AssertMsg1( false, "Received unknown message %d", messageType);
  95. }
  96. }
  97. /// only use of the clientthink on the advisor is to update the elight
  98. void C_NPC_Advisor::ClientThink( void )
  99. {
  100. // if the elight has gone away, bail out
  101. if (m_ElightKey == 0)
  102. {
  103. SetNextClientThink( CLIENT_THINK_NEVER );
  104. return;
  105. }
  106. // get the elight
  107. dlight_t * el = effects->GetElightByKey(m_ElightKey);
  108. if (!el)
  109. {
  110. // the elight has been invalidated. bail out.
  111. m_ElightKey = 0;
  112. SetNextClientThink( CLIENT_THINK_NEVER );
  113. return;
  114. }
  115. else
  116. {
  117. el->origin = WorldSpaceCenter();
  118. #if ADVISOR_ELIGHT_CVARS
  119. el->color.exponent = advisor_elight_e.GetFloat();
  120. el->radius = advisor_elight_rfeet.GetFloat() * 12.0f;
  121. #endif
  122. }
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Create a telekinetic beam effect from my head to an object
  126. // TODO: use a point attachment.
  127. //-----------------------------------------------------------------------------
  128. void C_NPC_Advisor::StartBeamFX( C_BaseEntity *pOnEntity )
  129. {
  130. Assert(pOnEntity);
  131. if (!pOnEntity)
  132. return;
  133. CNewParticleEffect *pEffect = ParticleProp()->Create( "Advisor_Psychic_Beam", PATTACH_ABSORIGIN_FOLLOW );
  134. Assert(pEffect);
  135. if (!pEffect) return;
  136. ParticleProp()->AddControlPoint( pEffect, 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
  137. }
  138. //-----------------------------------------------------------------------------
  139. // terminate a telekinetic beam effect from my head to an object
  140. //-----------------------------------------------------------------------------
  141. void C_NPC_Advisor::StopBeamFX( C_BaseEntity *pOnEntity )
  142. {
  143. Assert(pOnEntity);
  144. if (!pOnEntity)
  145. return;
  146. ParticleProp()->StopParticlesInvolving( pOnEntity );
  147. }
  148. void C_NPC_Advisor::StartElight()
  149. {
  150. AssertMsg(m_ElightKey == 0 , "Advisor trying to create new elight on top of old one!");
  151. if ( m_ElightKey != 0 )
  152. {
  153. Warning("Advisor tried to start his elight when it was already one.\n");
  154. }
  155. else
  156. {
  157. m_ElightKey = LIGHT_INDEX_TE_DYNAMIC + this->entindex();
  158. dlight_t * el = effects->CL_AllocElight( m_ElightKey );
  159. if ( el )
  160. {
  161. // create an elight on top of me
  162. el->origin = this->WorldSpaceCenter();
  163. el->color.r = 235;
  164. el->color.g = 255;
  165. el->color.b = 255;
  166. el->color.exponent = 3;
  167. el->radius = 52*12;
  168. el->decay = 0.0f;
  169. el->die = gpGlobals->curtime + 2000.0f; // 1000 just means " a long time "
  170. SetNextClientThink( CLIENT_THINK_ALWAYS );
  171. }
  172. else
  173. { // null out the light value
  174. m_ElightKey = 0;
  175. }
  176. }
  177. }
  178. void C_NPC_Advisor::StopElight()
  179. {
  180. AssertMsg( m_ElightKey != 0, "Advisor tried to stop elight when none existed!");
  181. dlight_t * el;
  182. // note: the following conditional sets el if not short-circuited
  183. if ( m_ElightKey == 0 || (el = effects->GetElightByKey(m_ElightKey)) == NULL )
  184. {
  185. Warning("Advisor tried to stop its elight when it had none.\n");
  186. }
  187. else
  188. {
  189. // kill the elight by setting the die value to now
  190. el->die = gpGlobals->curtime;
  191. }
  192. }
  193. #endif
  194. /******************************************************
  195. * Tenser, said the Tensor. *
  196. * Tenser, said the Tensor. *
  197. * Tension, apprehension and dissension have begun. *
  198. ******************************************************/