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.

749 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "vehicle_base.h"
  9. #include "engine/IEngineSound.h"
  10. #include "in_buttons.h"
  11. #include "soundenvelope.h"
  12. #include "soundent.h"
  13. #include "physics_saverestore.h"
  14. #include "vphysics/constraints.h"
  15. #include "vcollide_parse.h"
  16. #include "ndebugoverlay.h"
  17. #include "npc_vehicledriver.h"
  18. #include "hl2_player.h"
  19. #include "explode.h"
  20. #include "particle_smokegrenade.h"
  21. #include "te_effect_dispatch.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. class CPropCannon;
  25. // Crane bones that have physics followers
  26. static const char *pCannonFollowerBoneNames[] =
  27. {
  28. "base",
  29. "arm",
  30. "platform",
  31. };
  32. #define CANNON_EXTENSION_RATE_MAX 0.01
  33. #define CANNON_TURN_RATE_MAX 1.2
  34. #define MAX_CANNON_FLAT_REACH 1400.0
  35. #define MIN_CANNON_FLAT_REACH 700.0
  36. #define CANNON_EXTENSION_ACCEL 0.006
  37. #define CANNON_EXTENSION_DECEL 0.02
  38. #define CANNON_TURN_ACCEL 0.2
  39. #define CANNON_DECEL 0.5
  40. #define CANNON_SLOWRAISE_TIME 5.0
  41. #define CANNON_PROJECTILE_MODEL "models/props_combine/headcrabcannister01a.mdl"
  42. ConVar g_cannon_reloadtime( "g_cannon_reloadtime", "3", FCVAR_CHEAT | FCVAR_GAMEDLL );
  43. ConVar g_cannon_max_traveltime( "g_cannon_max_traveltime", "1.5", FCVAR_CHEAT | FCVAR_GAMEDLL );
  44. ConVar g_cannon_debug( "g_cannon_debug", "0", FCVAR_CHEAT | FCVAR_GAMEDLL );
  45. ConVar g_cannon_damageandradius( "g_cannon_damageandradius", "512", FCVAR_CHEAT | FCVAR_GAMEDLL );
  46. // Turning stats
  47. enum
  48. {
  49. CANNON_TURNING_NOT,
  50. CANNON_TURNING_LEFT,
  51. CANNON_TURNING_RIGHT,
  52. };
  53. //-----------------------------------------------------------------------------
  54. // Purpose: Crane vehicle server
  55. //-----------------------------------------------------------------------------
  56. class CCannonServerVehicle : public CBaseServerVehicle
  57. {
  58. typedef CBaseServerVehicle BaseClass;
  59. // IServerVehicle
  60. public:
  61. void GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV = NULL );
  62. protected:
  63. CPropCannon *GetCannon( void );
  64. };
  65. //-----------------------------------------------------------------------------
  66. // Purpose:
  67. //-----------------------------------------------------------------------------
  68. class CPropCannon : public CBaseProp, public IDrivableVehicle
  69. {
  70. DECLARE_CLASS( CPropCannon, CBaseProp );
  71. public:
  72. DECLARE_DATADESC();
  73. DECLARE_SERVERCLASS();
  74. CPropCannon( void )
  75. {
  76. m_ServerVehicle.SetVehicle( this );
  77. }
  78. //IDrivableVehicle's Pure Virtuals
  79. virtual CBaseEntity *GetDriver( void );
  80. virtual void ItemPostFrame( CBasePlayer *pPlayer );
  81. virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
  82. virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData ) { return; }
  83. virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move ) { return; }
  84. virtual bool CanEnterVehicle( CBaseEntity *pEntity );
  85. virtual bool CanExitVehicle( CBaseEntity *pEntity );
  86. virtual void SetVehicleEntryAnim( bool bOn ) { m_bEnterAnimOn = bOn; }
  87. virtual void SetVehicleExitAnim( bool bOn, Vector vecEyeExitEndpoint ) { m_bExitAnimOn = bOn; if ( bOn ) m_vecEyeExitEndpoint = vecEyeExitEndpoint; }
  88. virtual void EnterVehicle( CBaseCombatCharacter *pPassenger );
  89. virtual bool AllowBlockedExit( CBaseCombatCharacter *pPassenger, int nRole ) { return true; }
  90. virtual bool AllowMidairExit( CBaseCombatCharacter *pPassenger, int nRole ) { return false; }
  91. virtual void PreExitVehicle( CBaseCombatCharacter *pPassenger, int nRole ) {}
  92. virtual void ExitVehicle( int nRole );
  93. virtual string_t GetVehicleScriptName() { return m_vehicleScript; }
  94. virtual bool PassengerShouldReceiveDamage( CTakeDamageInfo &info ) { return false; }
  95. // If this is a vehicle, returns the vehicle interface
  96. virtual IServerVehicle *GetServerVehicle() { return &m_ServerVehicle; }
  97. virtual void Precache( void );
  98. virtual void Spawn( void );
  99. virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; };
  100. virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  101. virtual void Think( void );
  102. virtual bool CreateVPhysics( void );
  103. virtual void UpdateOnRemove( void );
  104. void DriveCannon( int iDriverButtons, int iButtonsPressed );
  105. void ResetUseKey( CBasePlayer *pPlayer );
  106. void InitCannonSpeeds( void );
  107. void RunCraneMovement( float flTime );
  108. void LaunchProjectile( void );
  109. void ProjectileExplosion( void );
  110. private:
  111. string_t m_vehicleScript;
  112. // Entering / Exiting
  113. bool m_bLocked;
  114. CNetworkVar( bool, m_bEnterAnimOn );
  115. CNetworkVar( bool, m_bExitAnimOn );
  116. CNetworkVector( m_vecEyeExitEndpoint );
  117. CNetworkHandle( CBasePlayer, m_hPlayer );
  118. COutputEvent m_playerOn;
  119. COutputEvent m_playerOff;
  120. int m_iTurning;
  121. float m_flTurn;
  122. // Crane arm extension / retraction
  123. bool m_bExtending;
  124. float m_flExtension;
  125. float m_flExtensionRate;
  126. // Speeds
  127. float m_flMaxExtensionSpeed;
  128. float m_flMaxTurnSpeed;
  129. float m_flExtensionAccel;
  130. float m_flExtensionDecel;
  131. float m_flTurnAccel;
  132. float m_flTurnDecel;
  133. float m_flFlyTime;
  134. Vector m_vCrashPoint;
  135. float m_flNextAttackTime;
  136. protected:
  137. // Contained IServerVehicle
  138. CCannonServerVehicle m_ServerVehicle;
  139. // Contained Bone Follower manager
  140. CBoneFollowerManager m_BoneFollowerManager;
  141. };
  142. LINK_ENTITY_TO_CLASS( prop_vehicle_cannon, CPropCannon );
  143. BEGIN_DATADESC( CPropCannon )
  144. DEFINE_KEYFIELD( m_vehicleScript, FIELD_STRING, "vehiclescript" ),
  145. DEFINE_OUTPUT( m_playerOn, "PlayerOn" ),
  146. DEFINE_OUTPUT( m_playerOff, "PlayerOff" ),
  147. DEFINE_EMBEDDED( m_BoneFollowerManager ),
  148. DEFINE_FIELD( m_iTurning, FIELD_INTEGER ),
  149. DEFINE_FIELD( m_flTurn, FIELD_FLOAT ),
  150. DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ),
  151. DEFINE_FIELD( m_bExtending, FIELD_BOOLEAN ),
  152. DEFINE_FIELD( m_flExtension, FIELD_FLOAT ),
  153. DEFINE_FIELD( m_flExtensionRate, FIELD_FLOAT ),
  154. DEFINE_FIELD( m_flMaxExtensionSpeed, FIELD_FLOAT ),
  155. DEFINE_FIELD( m_flMaxTurnSpeed, FIELD_FLOAT ),
  156. DEFINE_FIELD( m_flExtensionAccel, FIELD_FLOAT ),
  157. DEFINE_FIELD( m_flExtensionDecel, FIELD_FLOAT ),
  158. DEFINE_FIELD( m_flTurnAccel, FIELD_FLOAT ),
  159. DEFINE_FIELD( m_flTurnDecel, FIELD_FLOAT ),
  160. DEFINE_FIELD( m_flFlyTime, FIELD_TIME ),
  161. DEFINE_FIELD( m_vCrashPoint, FIELD_POSITION_VECTOR ),
  162. DEFINE_FIELD( m_flNextAttackTime, FIELD_TIME ),
  163. END_DATADESC()
  164. IMPLEMENT_SERVERCLASS_ST(CPropCannon, DT_PropCannon)
  165. SendPropEHandle(SENDINFO(m_hPlayer)),
  166. SendPropBool(SENDINFO(m_bEnterAnimOn)),
  167. SendPropBool(SENDINFO(m_bExitAnimOn)),
  168. SendPropVector(SENDINFO(m_vecEyeExitEndpoint), -1, SPROP_COORD),
  169. END_SEND_TABLE();
  170. //------------------------------------------------
  171. // Precache
  172. //------------------------------------------------
  173. void CPropCannon::Precache( void )
  174. {
  175. BaseClass::Precache();
  176. m_ServerVehicle.Initialize( STRING( m_vehicleScript ) );
  177. PrecacheModel( CANNON_PROJECTILE_MODEL );
  178. PrecacheScriptSound( "HeadcrabCanister.LaunchSound" );
  179. PrecacheScriptSound( "HeadcrabCanister.Explosion" );
  180. PrecacheScriptSound( "Weapon_Mortar.Incomming" );
  181. }
  182. //------------------------------------------------
  183. // Spawn
  184. //------------------------------------------------
  185. void CPropCannon::Spawn( void )
  186. {
  187. Precache();
  188. SetModel( STRING( GetModelName() ) );
  189. SetCollisionGroup( COLLISION_GROUP_VEHICLE );
  190. BaseClass::Spawn();
  191. SetSolid( SOLID_BBOX );
  192. AddSolidFlags( FSOLID_NOT_SOLID );
  193. SetMoveType( MOVETYPE_NOCLIP );
  194. m_takedamage = DAMAGE_EVENTS_ONLY;
  195. m_takedamage = DAMAGE_EVENTS_ONLY;
  196. m_flTurn = 0;
  197. m_flExtension = 0;
  198. m_flFlyTime = 0.0f;
  199. m_flNextAttackTime = gpGlobals->curtime;
  200. InitCannonSpeeds();
  201. SetPoseParameter( "armextensionpose", m_flExtension );
  202. CreateVPhysics();
  203. SetNextThink( gpGlobals->curtime );
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose:
  207. //-----------------------------------------------------------------------------
  208. void CPropCannon::InitCannonSpeeds( void )
  209. {
  210. m_flMaxExtensionSpeed = CANNON_EXTENSION_RATE_MAX * 2;
  211. m_flMaxTurnSpeed = CANNON_TURN_RATE_MAX * 2;
  212. m_flExtensionAccel = CANNON_EXTENSION_ACCEL * 2;
  213. m_flExtensionDecel = CANNON_EXTENSION_DECEL * 2;
  214. m_flTurnAccel = CANNON_TURN_ACCEL * 2;
  215. m_flTurnDecel = CANNON_DECEL * 2;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose:
  219. //-----------------------------------------------------------------------------
  220. CBaseEntity *CPropCannon::GetDriver( void )
  221. {
  222. return m_hPlayer;
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose:
  226. //-----------------------------------------------------------------------------
  227. void CPropCannon::EnterVehicle( CBaseCombatCharacter *pPassenger )
  228. {
  229. if ( pPassenger == NULL )
  230. return;
  231. CBasePlayer *pPlayer = ToBasePlayer( pPassenger );
  232. if ( pPlayer != NULL )
  233. {
  234. // Remove any player who may be in the vehicle at the moment
  235. if ( m_hPlayer )
  236. {
  237. ExitVehicle( VEHICLE_ROLE_DRIVER );
  238. }
  239. m_hPlayer = pPlayer;
  240. m_playerOn.FireOutput( pPlayer, this, 0 );
  241. //m_ServerVehicle.SoundStart();
  242. }
  243. else
  244. {
  245. // NPCs not supported yet - jdw
  246. Assert( 0 );
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose:
  251. //-----------------------------------------------------------------------------
  252. void CPropCannon::ExitVehicle( int nRole )
  253. {
  254. CBasePlayer *pPlayer = m_hPlayer;
  255. if ( !pPlayer )
  256. return;
  257. m_hPlayer = NULL;
  258. ResetUseKey( pPlayer );
  259. m_playerOff.FireOutput( pPlayer, this, 0 );
  260. m_bEnterAnimOn = false;
  261. //m_ServerVehicle.SoundShutdown( 1.0 );
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose: Return true of the player's allowed to enter / exit the vehicle
  265. //-----------------------------------------------------------------------------
  266. bool CPropCannon::CanEnterVehicle( CBaseEntity *pEntity )
  267. {
  268. // Prevent entering if the vehicle's being driven by an NPC
  269. if ( GetDriver() && GetDriver() != pEntity )
  270. return false;
  271. // Prevent entering if the vehicle's locked
  272. return ( !m_bLocked );
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Purpose: Return true of the player's allowed to enter / exit the vehicle
  276. //-----------------------------------------------------------------------------
  277. bool CPropCannon::CanExitVehicle( CBaseEntity *pEntity )
  278. {
  279. // Prevent exiting if the vehicle's locked, or rotating
  280. // Adrian: Check also if I'm currently jumping in or out.
  281. return ( !m_bLocked && (GetLocalAngularVelocity() == vec3_angle) && m_bExitAnimOn == false && m_bEnterAnimOn == false );
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose:
  285. //-----------------------------------------------------------------------------
  286. void CPropCannon::ResetUseKey( CBasePlayer *pPlayer )
  287. {
  288. pPlayer->m_afButtonPressed &= ~IN_USE;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Pass player movement into the crane's driving system
  292. //-----------------------------------------------------------------------------
  293. void CPropCannon::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
  294. {
  295. // If the player's entering/exiting the vehicle, prevent movement
  296. if ( !m_bEnterAnimOn && !m_bExitAnimOn )
  297. {
  298. DriveCannon( ucmd->buttons, player->m_afButtonPressed );
  299. }
  300. // Run the crane's movement
  301. RunCraneMovement( gpGlobals->frametime );
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose: Crane rotates around with +left and +right, and extends/retracts
  305. // the cable with +forward and +back.
  306. //-----------------------------------------------------------------------------
  307. void CPropCannon::DriveCannon( int iDriverButtons, int iButtonsPressed )
  308. {
  309. bool bWasExtending = m_bExtending;
  310. // Handle rotation of the crane
  311. if ( iDriverButtons & IN_MOVELEFT )
  312. {
  313. // Try adding some randomness to make it feel shaky?
  314. float flTurnAdd = m_flTurnAccel;
  315. // If we're turning back on ourselves, use decel speed
  316. if ( m_flTurn < 0 )
  317. {
  318. flTurnAdd = MAX( flTurnAdd, m_flTurnDecel );
  319. }
  320. m_flTurn = UTIL_Approach( m_flMaxTurnSpeed, m_flTurn, flTurnAdd * gpGlobals->frametime );
  321. m_iTurning = CANNON_TURNING_LEFT;
  322. }
  323. else if ( iDriverButtons & IN_MOVERIGHT )
  324. {
  325. // Try adding some randomness to make it feel shaky?
  326. float flTurnAdd = m_flTurnAccel;
  327. // If we're turning back on ourselves, increase the rate
  328. if ( m_flTurn > 0 )
  329. {
  330. flTurnAdd = MAX( flTurnAdd, m_flTurnDecel );
  331. }
  332. m_flTurn = UTIL_Approach( -m_flMaxTurnSpeed, m_flTurn, flTurnAdd * gpGlobals->frametime );
  333. m_iTurning = CANNON_TURNING_RIGHT;
  334. }
  335. else
  336. {
  337. m_flTurn = UTIL_Approach( 0, m_flTurn, m_flTurnDecel * gpGlobals->frametime );
  338. m_iTurning = CANNON_TURNING_NOT;
  339. }
  340. SetLocalAngularVelocity( QAngle(0,m_flTurn * 10,0) );
  341. // Handle extension / retraction of the arm
  342. if ( iDriverButtons & IN_FORWARD )
  343. {
  344. m_flExtensionRate = UTIL_Approach( m_flMaxExtensionSpeed, m_flExtensionRate, m_flExtensionAccel * gpGlobals->frametime );
  345. m_bExtending = true;
  346. }
  347. else if ( iDriverButtons & IN_BACK )
  348. {
  349. m_flExtensionRate = UTIL_Approach( -m_flMaxExtensionSpeed, m_flExtensionRate, m_flExtensionAccel * gpGlobals->frametime );
  350. m_bExtending = true;
  351. }
  352. else
  353. {
  354. m_flExtensionRate = UTIL_Approach( 0, m_flExtensionRate, m_flExtensionDecel * gpGlobals->frametime );
  355. m_bExtending = false;
  356. }
  357. //Msg("Turn: %f\nExtensionRate: %f\n", m_flTurn, m_flExtensionRate );
  358. //If we're holding down an attack button, update our state
  359. if ( iButtonsPressed & (IN_ATTACK | IN_ATTACK2) )
  360. {
  361. if ( m_flNextAttackTime <= gpGlobals->curtime )
  362. {
  363. LaunchProjectile();
  364. }
  365. }
  366. float flSpeedPercentage = clamp( fabs(m_flTurn) / m_flMaxTurnSpeed, 0, 1 );
  367. vbs_sound_update_t params;
  368. params.Defaults();
  369. params.bThrottleDown = (m_iTurning != CANNON_TURNING_NOT);
  370. params.flCurrentSpeedFraction = flSpeedPercentage;
  371. params.flWorldSpaceSpeed = 0;
  372. m_ServerVehicle.SoundUpdate( params );
  373. // Play sounds for arm extension / retraction
  374. if ( m_bExtending && !bWasExtending )
  375. {
  376. m_ServerVehicle.StopSound( VS_ENGINE2_STOP );
  377. m_ServerVehicle.PlaySound( VS_ENGINE2_START );
  378. }
  379. else if ( !m_bExtending && bWasExtending )
  380. {
  381. m_ServerVehicle.StopSound( VS_ENGINE2_START );
  382. m_ServerVehicle.PlaySound( VS_ENGINE2_STOP );
  383. }
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Purpose:
  387. // Input : *pPlayer -
  388. // *pMoveData -
  389. //-----------------------------------------------------------------------------
  390. void CPropCannon::RunCraneMovement( float flTime )
  391. {
  392. if ( m_flExtensionRate )
  393. {
  394. // Extend / Retract the crane
  395. m_flExtension = clamp( m_flExtension + (m_flExtensionRate * 10 * flTime), 0, 2 );
  396. SetPoseParameter( "armextensionpose", m_flExtension );
  397. StudioFrameAdvance();
  398. }
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose:
  402. // Input : *player -
  403. //-----------------------------------------------------------------------------
  404. void CPropCannon::ItemPostFrame( CBasePlayer *player )
  405. {
  406. }
  407. void CPropCannon::ProjectileExplosion( void )
  408. {
  409. ExplosionCreate( m_vCrashPoint, vec3_angle, NULL, 512, 512, false );
  410. // do damage
  411. CTakeDamageInfo info( this, this, g_cannon_damageandradius.GetInt(), DMG_BLAST );
  412. info.SetDamagePosition( m_vCrashPoint );
  413. RadiusDamage( info, m_vCrashPoint, g_cannon_damageandradius.GetInt(), CLASS_NONE, NULL );
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose:
  417. //-----------------------------------------------------------------------------
  418. void CPropCannon::Think( void )
  419. {
  420. SetNextThink( gpGlobals->curtime + 0.1 );
  421. if ( GetDriver() )
  422. {
  423. BaseClass::Think();
  424. }
  425. if ( GetDriver() )
  426. {
  427. BaseClass::Think();
  428. // play enter animation
  429. StudioFrameAdvance();
  430. // If the enter or exit animation has finished, tell the server vehicle
  431. if ( IsSequenceFinished() && (m_bExitAnimOn || m_bEnterAnimOn) )
  432. {
  433. if ( m_bEnterAnimOn )
  434. {
  435. // Finished entering, display the hint for using the crane
  436. //UTIL_HudHintText( m_hPlayer, "#Valve_Hint_CraneKeys" );
  437. }
  438. GetServerVehicle()->HandleEntryExitFinish( m_bExitAnimOn, true );
  439. }
  440. }
  441. else
  442. {
  443. // Run the crane's movement
  444. // RunCraneMovement( 0.1 );
  445. }
  446. // Update follower bones
  447. m_BoneFollowerManager.UpdateBoneFollowers(this);
  448. if ( m_flFlyTime > 0.0f )
  449. {
  450. if ( m_flFlyTime - 1.0f <= gpGlobals->curtime && m_flFlyTime - 0.8f > gpGlobals->curtime)
  451. {
  452. CPASAttenuationFilter filter( this );
  453. EmitSound_t ep;
  454. ep.m_nChannel = CHAN_STATIC;
  455. ep.m_pSoundName = "Weapon_Mortar.Incomming";
  456. ep.m_flVolume = 255;
  457. ep.m_SoundLevel = SNDLVL_180dB;
  458. EmitSound( filter, entindex(), ep );
  459. }
  460. if ( m_flFlyTime <= gpGlobals->curtime )
  461. {
  462. if ( m_vCrashPoint != vec3_origin )
  463. {
  464. ProjectileExplosion();
  465. }
  466. CEffectData data;
  467. data.m_vOrigin = m_vCrashPoint;
  468. data.m_flScale = 512;
  469. DispatchEffect( "ThumperDust", data );
  470. m_flFlyTime = 0.0f;
  471. }
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose:
  476. //-----------------------------------------------------------------------------
  477. void CPropCannon::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  478. {
  479. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  480. if ( !pPlayer )
  481. return;
  482. ResetUseKey( pPlayer );
  483. GetServerVehicle()->HandlePassengerEntry( pPlayer, (value>0) );
  484. }
  485. void CPropCannon::LaunchProjectile( void )
  486. {
  487. //ADRIANTODO: Come back to this once we get the right model and remove all the fix ups caused by temp content.
  488. Vector vTipPos, vTipForward, vTipRight, vUp;
  489. GetAttachment( "cable_tip", vTipPos, &vTipForward, &vTipRight, &vUp );
  490. bool bCollided = false;
  491. bool bInSky = false;
  492. float gravity = -gpGlobals->frametime * 600;
  493. Vector vOrigin = vTipPos;
  494. Vector vVelocity = vTipRight * 2500;
  495. float flDistance = 0.0f;
  496. int iFailSafe = 0;
  497. while ( bCollided == false && iFailSafe < 100000 )
  498. {
  499. Vector vOldOrigin = vOrigin;
  500. vOrigin = vOrigin + vVelocity * gpGlobals->frametime;
  501. flDistance += (vOrigin - vOldOrigin).Length();
  502. if ( g_cannon_debug.GetBool() == true )
  503. {
  504. NDebugOverlay::Line( vOldOrigin, vOrigin, 0, 255, 0, true, 5 );
  505. }
  506. trace_t pm;
  507. UTIL_TraceLine( vOldOrigin, vOrigin, MASK_SOLID, this, COLLISION_GROUP_NONE, &pm );
  508. if ( pm.surface.flags & SURF_SKY || pm.allsolid == true )
  509. {
  510. bInSky = true;
  511. iFailSafe++;
  512. }
  513. else
  514. {
  515. bInSky = false;
  516. }
  517. iFailSafe++;
  518. if ( pm.fraction != 1.0f && bInSky == false )
  519. {
  520. bCollided = true;
  521. vOrigin = pm.endpos;
  522. if ( g_cannon_debug.GetBool() == true )
  523. {
  524. NDebugOverlay::Box( vOrigin, Vector( 256, 256, 256 ), Vector( -256, -256, -256 ), 255, 0, 0, 0, 5 );
  525. }
  526. }
  527. else
  528. {
  529. vVelocity[2] += gravity;
  530. }
  531. }
  532. float flTravelTime = flDistance / vVelocity.Length();
  533. if ( flTravelTime > g_cannon_max_traveltime.GetFloat() )
  534. {
  535. flTravelTime = g_cannon_max_traveltime.GetFloat();
  536. if ( bCollided == false )
  537. {
  538. vOrigin = vec3_origin;
  539. }
  540. }
  541. m_flFlyTime = gpGlobals->curtime + flTravelTime;
  542. m_vCrashPoint = vOrigin;
  543. m_flNextAttackTime = gpGlobals->curtime + g_cannon_reloadtime.GetFloat();
  544. EmitSound( "HeadcrabCanister.LaunchSound" );
  545. UTIL_ScreenShake( GetDriver()->GetAbsOrigin(), 50.0, 150.0, 1.0, 750, SHAKE_START, true );
  546. }
  547. //========================================================================================================================================
  548. // CRANE VEHICLE SERVER VEHICLE
  549. //========================================================================================================================================
  550. CPropCannon *CCannonServerVehicle::GetCannon( void )
  551. {
  552. return (CPropCannon*)GetDrivableVehicle();
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose:
  556. // Output : Returns true on success, false on failure.
  557. //-----------------------------------------------------------------------------
  558. bool CPropCannon::CreateVPhysics( void )
  559. {
  560. BaseClass::CreateVPhysics();
  561. m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pCannonFollowerBoneNames), pCannonFollowerBoneNames );
  562. return true;
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Purpose:
  566. //-----------------------------------------------------------------------------
  567. void CPropCannon::UpdateOnRemove( void )
  568. {
  569. m_BoneFollowerManager.DestroyBoneFollowers();
  570. BaseClass::UpdateOnRemove();
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. //-----------------------------------------------------------------------------
  575. void CCannonServerVehicle::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*= NULL*/ )
  576. {
  577. Assert( nRole == VEHICLE_ROLE_DRIVER );
  578. CBasePlayer *pPlayer = ToBasePlayer( GetDrivableVehicle()->GetDriver() );
  579. Assert( pPlayer );
  580. *pAbsAngles = pPlayer->EyeAngles(); // yuck. this is an in/out parameter.
  581. float flPitchFactor = 1.0;
  582. matrix3x4_t vehicleEyePosToWorld;
  583. Vector vehicleEyeOrigin;
  584. QAngle vehicleEyeAngles;
  585. GetCannon()->GetAttachment( "vehicle_driver_eyes", vehicleEyeOrigin, vehicleEyeAngles );
  586. AngleMatrix( vehicleEyeAngles, vehicleEyePosToWorld );
  587. // Compute the relative rotation between the unperterbed eye attachment + the eye angles
  588. matrix3x4_t cameraToWorld;
  589. AngleMatrix( *pAbsAngles, cameraToWorld );
  590. matrix3x4_t worldToEyePos;
  591. MatrixInvert( vehicleEyePosToWorld, worldToEyePos );
  592. matrix3x4_t vehicleCameraToEyePos;
  593. ConcatTransforms( worldToEyePos, cameraToWorld, vehicleCameraToEyePos );
  594. // Now perterb the attachment point
  595. vehicleEyeAngles.x = RemapAngleRange( PITCH_CURVE_ZERO * flPitchFactor, PITCH_CURVE_LINEAR, vehicleEyeAngles.x );
  596. vehicleEyeAngles.z = RemapAngleRange( ROLL_CURVE_ZERO * flPitchFactor, ROLL_CURVE_LINEAR, vehicleEyeAngles.z );
  597. AngleMatrix( vehicleEyeAngles, vehicleEyeOrigin, vehicleEyePosToWorld );
  598. // Now treat the relative eye angles as being relative to this new, perterbed view position...
  599. matrix3x4_t newCameraToWorld;
  600. ConcatTransforms( vehicleEyePosToWorld, vehicleCameraToEyePos, newCameraToWorld );
  601. // output new view abs angles
  602. MatrixAngles( newCameraToWorld, *pAbsAngles );
  603. // UNDONE: *pOrigin would already be correct in single player if the HandleView() on the server ran after vphysics
  604. MatrixGetColumn( newCameraToWorld, 3, *pAbsOrigin );
  605. }