Counter Strike : Global Offensive Source Code
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.

1581 lines
42 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: First-class cube entity so we can query by type and generally make inferences
  4. // that are harder to do without an entity of that type.
  5. //
  6. //=====================================================================================//
  7. #include "cbase.h"
  8. #include "props.h"
  9. #include "ai_utils.h"
  10. #include "physics_saverestore.h"
  11. #include "phys_controller.h"
  12. #include "portal_base2d.h"
  13. #include "portal/weapon_physcannon.h"
  14. #include "datacache/imdlcache.h"
  15. #include "prop_weightedcube.h"
  16. #include "portal_player.h"
  17. #include "portal_player_shared.h"
  18. #include "world.h"
  19. #include "vcollide_parse.h"
  20. #include "portal_gamestats.h"
  21. #include "saverestore_utlvector.h"
  22. #include "trigger_portal_cleanser.h"
  23. #include "portal_mp_gamerules.h"
  24. #include "cvisibilitymonitor.h"
  25. ConVar reflector_cube_disabled_think_rate( "reflector_cube_disabled_think_rate", "0.1f", FCVAR_DEVELOPMENTONLY, "The rate at which the cube should think when it is disabled." );
  26. ConVar reflector_cube_disabled_nudge_time( "reflector_cube_disabled_nudge_time", "0.5f", FCVAR_DEVELOPMENTONLY, "The amount of time the cube needs to be touched before it gets enabled again." );
  27. ConVar reflector_cube_disabled_use_touch_check( "reflector_cube_disabled_use_touch_check", "0", FCVAR_DEVELOPMENTONLY, "Use touch checks to determine when to enable the cube." );
  28. ConVar sv_portal2_pickup_hint_range( "sv_portal2_pickup_hint_range", "350.0", FCVAR_NONE );
  29. // FIXME: Bring this back for DLC2
  30. //extern ConVar sv_schrodinger_laser_world_aligned;
  31. //Standard cube skins
  32. enum StandardCubeSkinType_t
  33. {
  34. CUBE_STANDARD_CLEAN_SKIN = 0,
  35. CUBE_STANDARD_CLEAN_ACTIVATED_SKIN = 2,
  36. CUBE_STANDARD_RUSTED_SKIN = 3,
  37. CUBE_STANDARD_RUSTED_ACTIVATED_SKIN = 5,
  38. CUBE_STANDARD_BOUNCE_SKIN = 6,
  39. CUBE_STANDARD_BOUNCE_ACTIVATED_SKIN = 10,
  40. CUBE_STANDARD_SPEED_SKIN = 7,
  41. CUBE_STANDARD_SPEED_ACTIVATED_SKIN = 11
  42. };
  43. //Companion cube skins
  44. enum CompanionCubeSkinType_t
  45. {
  46. CUBE_COMPANION_CLEAN_SKIN = 1,
  47. CUBE_COMPANION_CLEAN_ACTIVATED_SKIN = 4,
  48. CUBE_COMPANION_BOUNCE_SKIN = 8,
  49. CUBE_COMPANION_BOUNCE_ACTIVATED_SKIN = 8,
  50. CUBE_COMPANION_SPEED_SKIN = 9,
  51. CUBE_COMPANION_SPEED_ACTIVATED_SKIN = 9
  52. };
  53. //Reflective cubs skins
  54. enum ReflectiveCubeSkinType_t
  55. {
  56. CUBE_REFLECTIVE_CLEAN_SKIN = 0,
  57. CUBE_REFLECTIVE_RUSTED_SKIN = 1,
  58. CUBE_REFLECTIVE_BOUNCE_SKIN = 2,
  59. CUBE_REFLECTIVE_SPEED_SKIN = 3
  60. };
  61. //Sphere skins
  62. enum WeightedSpherSkinType_t
  63. {
  64. CUBE_SPHERE_CLEAN_SKIN = 0,
  65. CUBE_SPHERE_CLEAN_ACTIVATED_SKIN = 1,
  66. CUBE_SPHERE_BOUNCE_SKIN = 2,
  67. CUBE_SPHERE_BOUNCE_ACTIVATED_SKIN = 2,
  68. CUBE_SPHERE_SPEED_SKIN = 3,
  69. CUBE_SPHERE_SPEED_ACTIVATED_SKIN = 3
  70. };
  71. //Antique cube skins
  72. enum AntiqueCubeSkinType_t
  73. {
  74. CUBE_ANTIQUE_CLEAN_SKIN = 0,
  75. CUBE_ANTIQUE_BOUNCE_SKIN = 1,
  76. CUBE_ANTIQUE_SPEED_SKIN = 2
  77. };
  78. //Schrodinger cube skins
  79. enum SchrodingerCubeSkinType_t
  80. {
  81. CUBE_SCHRODINGER_CLEAN_SKIN = 4,
  82. CUBE_SCHRODINGER_BOUNCE_SKIN = 5,
  83. CUBE_SCHRODINGER_SPEED_SKIN = 6
  84. };
  85. const char SCHRODINGER_THINK_CONTEXT[] = "Schrodinger Think Context";
  86. LINK_ENTITY_TO_CLASS( cube_rotationcontroller, CCubeRotationController );
  87. //---------------------------------------------------------
  88. // Save/Restore
  89. //---------------------------------------------------------
  90. BEGIN_DATADESC( CCubeRotationController )
  91. DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
  92. DEFINE_FIELD( m_flSuspendTime, FIELD_TIME ),
  93. DEFINE_FIELD( m_worldGoalAxis, FIELD_VECTOR ),
  94. DEFINE_FIELD( m_localTestAxis, FIELD_VECTOR ),
  95. DEFINE_PHYSPTR( m_pController ),
  96. DEFINE_FIELD( m_angularLimit, FIELD_FLOAT ),
  97. DEFINE_FIELD( m_pParent, FIELD_CLASSPTR ),
  98. END_DATADESC()
  99. IMPLEMENT_AUTO_LIST( IPropWeightedCubeAutoList );
  100. CCubeRotationController::~CCubeRotationController()
  101. {
  102. if ( m_pController )
  103. {
  104. physenv->DestroyMotionController( m_pController );
  105. m_pController = NULL;
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. //-----------------------------------------------------------------------------
  111. void CCubeRotationController::Spawn( void )
  112. {
  113. m_bEnabled = false;
  114. // align the object's local Z axis
  115. m_localTestAxis.Init( 1, 0, 0 );
  116. // with the world's Z axis
  117. m_worldGoalAxis.Init( 0, 0, 1 );
  118. // recover from up to 25 degrees / sec angular velocity
  119. m_angularLimit = 25;
  120. m_flSuspendTime = 0;
  121. SetMoveType( MOVETYPE_NONE );
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Set the vector we'll try to match
  125. //-----------------------------------------------------------------------------
  126. void CCubeRotationController::SetAlignmentVector( const Vector &vecAlign )
  127. {
  128. m_worldGoalAxis = vecAlign;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose:
  132. //-----------------------------------------------------------------------------
  133. void CCubeRotationController::Activate( void )
  134. {
  135. BaseClass::Activate();
  136. if ( m_pParent == NULL )
  137. {
  138. UTIL_Remove(this);
  139. return;
  140. }
  141. IPhysicsObject *pPhys = m_pParent->VPhysicsGetObject();
  142. if ( pPhys == NULL )
  143. {
  144. UTIL_Remove(this);
  145. return;
  146. }
  147. //Setup the motion controller
  148. if ( !m_pController )
  149. {
  150. m_pController = physenv->CreateMotionController( (IMotionEvent *)this );
  151. m_pController->AttachObject( pPhys, true );
  152. }
  153. else
  154. {
  155. m_pController->SetEventHandler( this );
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose: Simulation will be suspended after this amount of time
  160. //-----------------------------------------------------------------------------
  161. void CCubeRotationController::SuspendAfter( float flSuspendTime )
  162. {
  163. m_flSuspendTime = flSuspendTime;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: Actual simulation for tip controller
  167. //-----------------------------------------------------------------------------
  168. IMotionEvent::simresult_e CCubeRotationController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
  169. {
  170. if ( Enabled() == false )
  171. return SIM_NOTHING;
  172. // Don't simulate if we're being carried by the player
  173. // if ( m_pParent->IsBeingCarriedByPlayer() )
  174. // return SIM_NOTHING;
  175. float flAngularLimit = m_angularLimit;
  176. // If we were just dropped by a friendly player, stabilise better
  177. /*
  178. if ( m_pParent->WasJustDroppedByPlayer() )
  179. {
  180. // Increase the controller strength a little
  181. flAngularLimit += 20;
  182. }
  183. else
  184. */
  185. {
  186. // If the turret has some vertical velocity, don't simulate
  187. /*
  188. Vector vecVelocity;
  189. AngularImpulse angImpulse;
  190. pObject->GetVelocity( &vecVelocity, &angImpulse );
  191. if ( (vecVelocity.LengthSqr() > CNPC_FloorTurret::fMaxTipControllerVelocity) || (angImpulse.LengthSqr() > CNPC_FloorTurret::fMaxTipControllerAngularVelocity) )
  192. return SIM_NOTHING;
  193. */
  194. }
  195. linear.Init();
  196. AngularImpulse angVel;
  197. pObject->GetVelocity( NULL, &angVel );
  198. matrix3x4_t matrix;
  199. // get the object's local to world transform
  200. pObject->GetPositionMatrix( &matrix );
  201. // Get the alignment axis in object space
  202. Vector currentLocalTargetAxis;
  203. VectorIRotate( m_worldGoalAxis, matrix, currentLocalTargetAxis );
  204. float invDeltaTime = (1/deltaTime);
  205. angular = ComputeRotSpeedToAlignAxes( m_localTestAxis, currentLocalTargetAxis, angVel, 1.0, invDeltaTime * invDeltaTime, flAngularLimit * invDeltaTime );
  206. return SIM_LOCAL_ACCELERATION;
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. //-----------------------------------------------------------------------------
  211. void CCubeRotationController::Enable( bool state )
  212. {
  213. m_bEnabled = state;
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. // Output : Returns true on success, false on failure.
  218. //-----------------------------------------------------------------------------
  219. bool CCubeRotationController::Enabled( void )
  220. {
  221. if ( m_flSuspendTime > gpGlobals->curtime )
  222. return true;
  223. return m_bEnabled;
  224. }
  225. CEG_NOINLINE CCubeRotationController * CCubeRotationController::CreateRotationController( CBaseEntity *pOwner )
  226. {
  227. if ( pOwner == NULL )
  228. return NULL;
  229. CCubeRotationController *pController = (CCubeRotationController *) Create( "cube_rotationcontroller", pOwner->GetAbsOrigin(), pOwner->GetAbsAngles() );
  230. if ( pController != NULL )
  231. {
  232. pController->m_pParent = pOwner;
  233. }
  234. return pController;
  235. }
  236. CEG_PROTECT_STATIC_MEMBER_FUNCTION( CCubeRotationController_CreateRotationController, CCubeRotationController::CreateRotationController );
  237. LINK_ENTITY_TO_CLASS( prop_weighted_cube, CPropWeightedCube );
  238. BEGIN_DATADESC( CPropWeightedCube )
  239. DEFINE_FIELD( m_vecCarryAngles, FIELD_VECTOR ),
  240. DEFINE_FIELD( m_pController, FIELD_EHANDLE ),
  241. DEFINE_FIELD( m_bMovementDisabled, FIELD_BOOLEAN ),
  242. DEFINE_FIELD( m_bActivated, FIELD_BOOLEAN ),
  243. DEFINE_FIELD( m_bTouchedByPlayer, FIELD_BOOLEAN ),
  244. DEFINE_FIELD( m_nCurrentPaintedType, FIELD_INTEGER ),
  245. DEFINE_FIELD( m_bPickupDisabled, FIELD_BOOLEAN ),
  246. DEFINE_SOUNDPATCH( m_pSchrodingerSound ),
  247. DEFINE_THINKFUNC( SchrodingerThink ),
  248. DEFINE_THINKFUNC( DisabledThink ),
  249. DEFINE_THINKFUNC( TractorBeamThink ),
  250. DEFINE_THINKFUNC( ExitTractorBeamThink ),
  251. DEFINE_KEYFIELD( m_bRusted, FIELD_BOOLEAN, "SkinType" ),
  252. DEFINE_KEYFIELD( m_nCubeType, FIELD_INTEGER, "CubeType" ),
  253. DEFINE_KEYFIELD( m_bNewSkins, FIELD_BOOLEAN, "NewSkins" ),
  254. DEFINE_INPUTFUNC( FIELD_VOID, "Dissolve", InputDissolve ),
  255. DEFINE_INPUTFUNC( FIELD_VOID, "SilentDissolve", InputSilentDissolve ),
  256. DEFINE_INPUTFUNC( FIELD_VOID, "PreDissolveJoke", InputPreDissolveJoke ),
  257. DEFINE_INPUTFUNC( FIELD_VOID, "DisablePortalFunnel", InputDisablePortalFunnel ),
  258. DEFINE_INPUTFUNC( FIELD_VOID, "EnablePortalFunnel", InputEnablePortalFunnel ),
  259. DEFINE_INPUTFUNC( FIELD_VOID, "ExitDisabledState", InputExitDisabledState ),
  260. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetPaint", InputSetPaint ),
  261. DEFINE_INPUTFUNC( FIELD_VOID, "DisablePickup", InputDisablePickup ),
  262. DEFINE_INPUTFUNC( FIELD_VOID, "EnablePickup", InputEnablePickup ),
  263. DEFINE_OUTPUT( m_OnFizzled, "OnFizzled" ),
  264. DEFINE_OUTPUT( m_OnOrangePickUp, "OnOrangePickUp" ),
  265. DEFINE_OUTPUT( m_OnBluePickUp, "OnBluePickUp" ),
  266. DEFINE_OUTPUT( m_OnPainted, "OnPainted" ),
  267. END_DATADESC()
  268. //no new networked fields, just need entity specific virtual functions defined on the client
  269. IMPLEMENT_SERVERCLASS_ST( CPropWeightedCube, DT_PropWeightedCube )
  270. END_SEND_TABLE()
  271. const char *CUBE_MODEL = "models/props/metal_box.mdl";
  272. const char *CUBE_REFLECT_MODEL = "models/props/reflection_cube.mdl";
  273. const char *CUBE_SPHERE_MODEL = "models/props_gameplay/mp_ball.mdl";
  274. const char *CUBE_FX_FIZZLER_MODEL = "models/props/metal_box_fx_fizzler.mdl";
  275. const char *CUBE_ANTIQUE_MODEL = "models/props_underground/underground_weighted_cube.mdl";
  276. const char *CUBE_SCHRODINGER_MODEL = "models/props/reflection_cube.mdl";
  277. CHandle< CPropWeightedCube > CPropWeightedCube::m_hSchrodingerDangling;
  278. //-----------------------------------------------------------------------------
  279. // Purpose:
  280. //-----------------------------------------------------------------------------
  281. CPropWeightedCube::CPropWeightedCube()
  282. : m_bMovementDisabled( false ),
  283. m_bRusted( false ),
  284. m_bActivated( false ),
  285. m_nCubeType( CUBE_STANDARD ),
  286. m_bTouchedByPlayer( false )
  287. {
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose:
  291. //-----------------------------------------------------------------------------
  292. CEG_NOINLINE void CPropWeightedCube::Spawn( void )
  293. {
  294. // Start out with nothing
  295. m_vecCarryAngles.Init(0,0,0);
  296. ConvertOldSkins();
  297. Precache();
  298. m_nCurrentPaintedType = NO_POWER;
  299. m_bPickupDisabled = false;
  300. SetCubeType();
  301. CEG_PROTECT_VIRTUAL_FUNCTION( CPropWeightedCube_Spawn );
  302. m_nBouncyMaterialIndex = physprops->GetSurfaceIndex( "WeightedCube_Bounce" );
  303. SetInteraction( PROPINTER_PHYSGUN_ALLOW_OVERHEAD );
  304. BaseClass::Spawn();
  305. SetCollisionGroup( COLLISION_GROUP_WEIGHTED_CUBE );
  306. if ( m_nCubeType == CUBE_SCHRODINGER )
  307. {
  308. SetContextThink( &CPropWeightedCube::SchrodingerThink, gpGlobals->curtime + reflector_cube_disabled_think_rate.GetFloat(), SCHRODINGER_THINK_CONTEXT );
  309. }
  310. #if !defined( _GAMECONSOLE ) && !defined( NO_STEAM )
  311. g_PortalGameStats.Event_CubeSpawn();
  312. #endif
  313. VisibilityMonitor_AddEntity_NotVisibleThroughGlass( this, sv_portal2_pickup_hint_range.GetFloat() - 50.0f, NULL, NULL );
  314. SetFadeDistance( -1.0f, 0.0f );
  315. SetGlobalFadeScale( 0.0f );
  316. }
  317. void CPropWeightedCube::Activate( void )
  318. {
  319. SetPaintedMaterial( (PaintPowerType)( m_PrePaintedPower ) );
  320. #if 0
  321. if ( !m_pSchrodingerSound )
  322. {
  323. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
  324. CPASAttenuationFilter filter( this );
  325. m_pSchrodingerSound = controller.SoundCreate( filter, entindex(), "music.laser_node_02.play" );
  326. controller.Play( m_pSchrodingerSound, 0, RandomFloat( 99, 101 ) );
  327. }
  328. #endif
  329. BaseClass::Activate();
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose:
  333. //-----------------------------------------------------------------------------
  334. void CPropWeightedCube::UpdateOnRemove( void )
  335. {
  336. BaseClass::UpdateOnRemove();
  337. if ( m_pController )
  338. {
  339. UTIL_Remove( m_pController );
  340. }
  341. CPropWeightedCube *pTwin = m_hSchrodingerTwin.Get();
  342. if ( pTwin && !pTwin->IsMarkedForDeletion() )
  343. {
  344. CTriggerPortalCleanser::FizzleBaseAnimating( NULL, pTwin );
  345. }
  346. #if 0
  347. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
  348. controller.SoundDestroy( m_pSchrodingerSound );
  349. m_pSchrodingerSound = NULL;
  350. BaseClass::StopLoopingSounds();
  351. #endif
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose:
  355. //-----------------------------------------------------------------------------
  356. void CPropWeightedCube::Precache( void )
  357. {
  358. ConvertOldSkins();
  359. switch ( m_nCubeType )
  360. {
  361. default:
  362. case CUBE_STANDARD:
  363. case CUBE_COMPANION:
  364. PrecacheModel( CUBE_MODEL );
  365. break;
  366. case CUBE_REFLECTIVE:
  367. PrecacheModel( CUBE_REFLECT_MODEL );
  368. break;
  369. case CUBE_SPHERE:
  370. PrecacheModel( CUBE_SPHERE_MODEL );
  371. break;
  372. case CUBE_ANTIQUE:
  373. PrecacheModel( CUBE_ANTIQUE_MODEL );
  374. case CUBE_SCHRODINGER:
  375. PrecacheModel( CUBE_SCHRODINGER_MODEL );
  376. PrecacheScriptSound( "music.laser_node_02.play" );
  377. PrecacheScriptSound( "prop_laser_catcher.poweron" );
  378. PrecacheScriptSound( "prop_laser_catcher.poweroff" );
  379. break;
  380. }
  381. PrecacheModel( CUBE_FX_FIZZLER_MODEL );
  382. PrecacheScriptSound( "WeightedCube.JumpPowerActivateShort" );
  383. PrecacheScriptSound( "WeightedCube.JumpPowerActivateLong" );
  384. BaseClass::Precache();
  385. }
  386. int CPropWeightedCube::ObjectCaps( void )
  387. {
  388. int flags = (BaseClass::ObjectCaps()|FCAP_IMPULSE_USE);
  389. if ( GetPaintedPower() == BOUNCE_POWER )
  390. {
  391. flags |= FCAP_USE_IN_RADIUS;
  392. }
  393. return flags;
  394. }
  395. int CPropWeightedCube::UpdateTransmitState()
  396. {
  397. if ( HasLaser() )
  398. {
  399. return SetTransmitState( FL_EDICT_ALWAYS );
  400. }
  401. return BaseClass::UpdateTransmitState();
  402. }
  403. void CPropWeightedCube::ConvertOldSkins( void )
  404. {
  405. //HACK HACK: Make the cubes choose skins using the new method even though the maps have not been updated to use them.
  406. if( !m_bNewSkins )
  407. {
  408. if( m_nSkin > 1 )
  409. {
  410. m_nSkin--;
  411. }
  412. m_nCubeType = static_cast<WeightedCubeType_e>( m_nSkin.Get() );
  413. m_bNewSkins = true;
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose:
  418. //-----------------------------------------------------------------------------
  419. void CPropWeightedCube::SetCubeType( void )
  420. {
  421. // FIXME: Remove for DLC2
  422. if ( m_nCubeType == CUBE_SCHRODINGER )
  423. {
  424. m_nCubeType = CUBE_REFLECTIVE;
  425. }
  426. switch( m_nCubeType )
  427. {
  428. //Standard cube
  429. case CUBE_STANDARD:
  430. case CUBE_COMPANION:
  431. {
  432. SetModelName( MAKE_STRING( CUBE_MODEL ) );
  433. break;
  434. }
  435. //Reflective cube
  436. case CUBE_REFLECTIVE:
  437. {
  438. SetModelName( MAKE_STRING( CUBE_REFLECT_MODEL ) );
  439. m_pController = CCubeRotationController::CreateRotationController( this );
  440. AddSpawnFlags( SF_PHYSPROP_ENABLE_ON_PHYSCANNON );
  441. break;
  442. }
  443. //Sphere
  444. case CUBE_SPHERE:
  445. {
  446. SetModelName( MAKE_STRING( CUBE_SPHERE_MODEL ) );
  447. break;
  448. }
  449. //Antique cube
  450. case CUBE_ANTIQUE:
  451. {
  452. SetModelName( MAKE_STRING( CUBE_ANTIQUE_MODEL ) );
  453. break;
  454. }
  455. //Schrodinger cube
  456. case CUBE_SCHRODINGER:
  457. {
  458. SetModelName( MAKE_STRING( CUBE_SCHRODINGER_MODEL ) );
  459. m_pController = CCubeRotationController::CreateRotationController( this );
  460. AddSpawnFlags( SF_PHYSPROP_ENABLE_ON_PHYSCANNON );
  461. if ( m_hSchrodingerDangling.Get() == NULL )
  462. {
  463. m_hSchrodingerDangling = this;
  464. }
  465. else
  466. {
  467. m_hSchrodingerDangling->m_hSchrodingerTwin = this;
  468. m_hSchrodingerTwin = m_hSchrodingerDangling;
  469. m_hSchrodingerDangling = NULL;
  470. }
  471. break;
  472. }
  473. }
  474. SetCubeSkin();
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. void CPropWeightedCube::SetActivated( bool bActivate )
  480. {
  481. m_bActivated = bActivate;
  482. SetCubeSkin();
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. //-----------------------------------------------------------------------------
  487. void CPropWeightedCube::SetCubeSkin( void )
  488. {
  489. switch( m_nCubeType )
  490. {
  491. //Standard cube
  492. case CUBE_STANDARD:
  493. {
  494. //Rusted cubes don't show paint
  495. if( m_bRusted )
  496. {
  497. if( m_bActivated )
  498. {
  499. SetSkin( CUBE_STANDARD_RUSTED_ACTIVATED_SKIN );
  500. }
  501. else
  502. {
  503. SetSkin( CUBE_STANDARD_RUSTED_SKIN );
  504. }
  505. }
  506. else
  507. {
  508. switch( GetPaintedPower() )
  509. {
  510. //Bounce painted
  511. case BOUNCE_POWER:
  512. {
  513. if( m_bActivated )
  514. {
  515. RANDOM_CEG_TEST_SECRET_PERIOD( 98, 106 );
  516. SetSkin( CUBE_STANDARD_BOUNCE_ACTIVATED_SKIN );
  517. }
  518. else
  519. {
  520. SetSkin( CUBE_STANDARD_BOUNCE_SKIN );
  521. }
  522. }
  523. break;
  524. //Speed painted
  525. case SPEED_POWER:
  526. {
  527. if( m_bActivated )
  528. {
  529. SetSkin( CUBE_STANDARD_SPEED_ACTIVATED_SKIN );
  530. }
  531. else
  532. {
  533. SetSkin( CUBE_STANDARD_SPEED_SKIN );
  534. }
  535. }
  536. break;
  537. //Not painted
  538. default:
  539. {
  540. if( m_bActivated )
  541. {
  542. SetSkin( CUBE_STANDARD_CLEAN_ACTIVATED_SKIN );
  543. }
  544. else
  545. {
  546. SetSkin( CUBE_STANDARD_CLEAN_SKIN );
  547. }
  548. }
  549. break;
  550. }
  551. }
  552. }
  553. break;
  554. //Companion cube
  555. case CUBE_COMPANION:
  556. {
  557. switch( GetPaintedPower() )
  558. {
  559. //Bounce painted
  560. case BOUNCE_POWER:
  561. {
  562. if( m_bActivated )
  563. {
  564. SetSkin( CUBE_COMPANION_BOUNCE_ACTIVATED_SKIN );
  565. }
  566. else
  567. {
  568. SetSkin( CUBE_COMPANION_BOUNCE_SKIN );
  569. }
  570. }
  571. break;
  572. //Speed painted
  573. case SPEED_POWER:
  574. {
  575. if( m_bActivated )
  576. {
  577. SetSkin( CUBE_COMPANION_SPEED_ACTIVATED_SKIN );
  578. }
  579. else
  580. {
  581. SetSkin( CUBE_COMPANION_SPEED_SKIN );
  582. }
  583. }
  584. break;
  585. //Not painted
  586. default:
  587. {
  588. if( m_bActivated )
  589. {
  590. SetSkin( CUBE_COMPANION_CLEAN_ACTIVATED_SKIN );
  591. }
  592. else
  593. {
  594. SetSkin( CUBE_COMPANION_CLEAN_SKIN );
  595. }
  596. }
  597. break;
  598. }
  599. }
  600. break;
  601. //Reflective cube
  602. case CUBE_REFLECTIVE:
  603. {
  604. switch( GetPaintedPower() )
  605. {
  606. //Bounce painted
  607. case BOUNCE_POWER:
  608. {
  609. if( m_bRusted )
  610. {
  611. // FIXME
  612. SetSkin( CUBE_REFLECTIVE_BOUNCE_SKIN );
  613. }
  614. else
  615. {
  616. SetSkin( CUBE_REFLECTIVE_BOUNCE_SKIN );
  617. }
  618. }
  619. break;
  620. //Speed painted
  621. case SPEED_POWER:
  622. {
  623. if( m_bRusted )
  624. {
  625. // FIXME
  626. SetSkin( CUBE_REFLECTIVE_SPEED_SKIN );
  627. }
  628. else
  629. {
  630. SetSkin( CUBE_REFLECTIVE_SPEED_SKIN );
  631. }
  632. }
  633. break;
  634. //Not painted
  635. default:
  636. {
  637. if( m_bRusted )
  638. {
  639. SetSkin( CUBE_REFLECTIVE_RUSTED_SKIN );
  640. }
  641. else
  642. {
  643. SetSkin( CUBE_REFLECTIVE_CLEAN_SKIN );
  644. }
  645. }
  646. break;
  647. }
  648. }
  649. break;
  650. //Sphere
  651. case CUBE_SPHERE:
  652. {
  653. switch( GetPaintedPower() )
  654. {
  655. //Bounce painted
  656. case BOUNCE_POWER:
  657. {
  658. if( m_bActivated )
  659. {
  660. SetSkin( CUBE_SPHERE_BOUNCE_ACTIVATED_SKIN );
  661. }
  662. else
  663. {
  664. SetSkin( CUBE_SPHERE_BOUNCE_SKIN );
  665. }
  666. }
  667. break;
  668. //Speed painted
  669. case SPEED_POWER:
  670. {
  671. if( m_bActivated )
  672. {
  673. SetSkin( CUBE_SPHERE_SPEED_ACTIVATED_SKIN );
  674. }
  675. else
  676. {
  677. SetSkin( CUBE_SPHERE_SPEED_SKIN );
  678. }
  679. }
  680. break;
  681. //Not painted
  682. default:
  683. {
  684. if( m_bActivated )
  685. {
  686. SetSkin( CUBE_SPHERE_CLEAN_ACTIVATED_SKIN );
  687. }
  688. else
  689. {
  690. SetSkin( CUBE_SPHERE_CLEAN_SKIN );
  691. }
  692. }
  693. break;
  694. }
  695. }
  696. break;
  697. //Antique cube
  698. case CUBE_ANTIQUE:
  699. {
  700. switch( GetPaintedPower() )
  701. {
  702. //Bounce painted
  703. case BOUNCE_POWER:
  704. {
  705. SetSkin( CUBE_ANTIQUE_BOUNCE_SKIN );
  706. }
  707. break;
  708. //Speed painted
  709. case SPEED_POWER:
  710. {
  711. SetSkin( CUBE_ANTIQUE_SPEED_SKIN );
  712. }
  713. break;
  714. //Not painted
  715. default:
  716. {
  717. SetSkin( CUBE_ANTIQUE_CLEAN_SKIN );
  718. }
  719. break;
  720. }
  721. }
  722. break;
  723. //Antique cube
  724. case CUBE_SCHRODINGER:
  725. {
  726. switch( GetPaintedPower() )
  727. {
  728. //Bounce painted
  729. case BOUNCE_POWER:
  730. {
  731. SetSkin( CUBE_SCHRODINGER_BOUNCE_SKIN );
  732. }
  733. break;
  734. //Speed painted
  735. case SPEED_POWER:
  736. {
  737. SetSkin( CUBE_SCHRODINGER_SPEED_SKIN );
  738. }
  739. break;
  740. //Not painted
  741. default:
  742. {
  743. SetSkin( CUBE_SCHRODINGER_CLEAN_SKIN );
  744. }
  745. break;
  746. }
  747. }
  748. break;
  749. }
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Purpose:
  753. //-----------------------------------------------------------------------------
  754. void CPropWeightedCube::SetSkin( int skinNum )
  755. {
  756. m_nSkin = skinNum;
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Purpose:
  760. //-----------------------------------------------------------------------------
  761. void CPropWeightedCube::InputDissolve( inputdata_t &in )
  762. {
  763. CTriggerPortalCleanser::FizzleBaseAnimating( NULL, this );
  764. }
  765. //-----------------------------------------------------------------------------
  766. // Purpose:
  767. //-----------------------------------------------------------------------------
  768. void CPropWeightedCube::InputSilentDissolve( inputdata_t &in )
  769. {
  770. OnFizzled();
  771. UTIL_Remove( this );
  772. }
  773. //-----------------------------------------------------------------------------
  774. // Purpose:
  775. //-----------------------------------------------------------------------------
  776. void CPropWeightedCube::InputPreDissolveJoke( inputdata_t &in )
  777. {
  778. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, "@glados" );
  779. if ( pEntity )
  780. {
  781. pEntity->RunScript( "CoopCubeFizzle()", "PreDissolveJoke" );
  782. }
  783. }
  784. //-----------------------------------------------------------------------------
  785. // Purpose:
  786. //-----------------------------------------------------------------------------
  787. void CPropWeightedCube::InputDisablePortalFunnel( inputdata_t &in )
  788. {
  789. m_bAllowPortalFunnel = false;
  790. }
  791. //-----------------------------------------------------------------------------
  792. // Purpose:
  793. //-----------------------------------------------------------------------------
  794. void CPropWeightedCube::InputEnablePortalFunnel( inputdata_t &in )
  795. {
  796. m_bAllowPortalFunnel = true;
  797. }
  798. //-----------------------------------------------------------------------------
  799. // Purpose:
  800. //-----------------------------------------------------------------------------
  801. QAngle CPropWeightedCube::CalculatePreferredAngles( CBasePlayer *pPlayer )
  802. {
  803. return QAngle(0,0,0);
  804. }
  805. void CPropWeightedCube::UpdatePreferredAngles( CBasePlayer *pPlayer )
  806. {
  807. m_vecCarryAngles = CalculatePreferredAngles( pPlayer );
  808. if( HasPreferredCarryAnglesForPlayer( pPlayer ) )
  809. {
  810. m_qPreferredPlayerCarryAngles = m_vecCarryAngles;
  811. }
  812. else
  813. {
  814. if( m_qPreferredPlayerCarryAngles.Get().x < FLT_MAX )
  815. {
  816. m_qPreferredPlayerCarryAngles.GetForModify().Init( FLT_MAX, FLT_MAX, FLT_MAX );
  817. }
  818. }
  819. }
  820. extern void ComputePlayerMatrix( CBasePlayer *pPlayer, matrix3x4_t &out );
  821. //-----------------------------------------------------------------------------
  822. // Purpose:
  823. //-----------------------------------------------------------------------------
  824. QAngle CPropWeightedCube::PreferredCarryAngles( void )
  825. {
  826. static QAngle s_prefAngles;
  827. s_prefAngles = m_vecCarryAngles;
  828. CBasePlayer *pPlayer = GetPlayerHoldingEntity( this );
  829. if ( pPlayer )
  830. {
  831. Vector vecRight;
  832. pPlayer->GetVectors( NULL, &vecRight, NULL );
  833. Quaternion qRotation;
  834. AxisAngleQuaternion( vecRight, pPlayer->EyeAngles().x, qRotation );
  835. matrix3x4_t tmp;
  836. ComputePlayerMatrix( pPlayer, tmp );
  837. QAngle qTemp = TransformAnglesToWorldSpace( s_prefAngles, tmp );
  838. Quaternion qExisting;
  839. AngleQuaternion( qTemp, qExisting );
  840. Quaternion qFinal;
  841. QuaternionMult( qRotation, qExisting, qFinal );
  842. QuaternionAngles( qFinal, qTemp );
  843. s_prefAngles = TransformAnglesToLocalSpace( qTemp, tmp );
  844. }
  845. return s_prefAngles;
  846. }
  847. //-----------------------------------------------------------------------------
  848. // Purpose:
  849. //-----------------------------------------------------------------------------
  850. void CPropWeightedCube::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
  851. {
  852. BaseClass::OnPhysGunPickup( pPhysGunUser, reason );
  853. m_bMovementDisabled = false;
  854. m_bTouchedByPlayer = true;
  855. // Calculate our preferred angles on the first pickup
  856. if ( reason == PICKED_UP_BY_CANNON || reason == PICKED_UP_BY_PLAYER )
  857. {
  858. UpdatePreferredAngles( pPhysGunUser );
  859. if ( m_pController )
  860. {
  861. m_pController->Enable( false );
  862. }
  863. CPortal_Player *pPlayer = ToPortalPlayer( pPhysGunUser );
  864. if ( pPlayer )
  865. {
  866. // Force a cool-down on the +USE key after a successful grab
  867. pPlayer->SetUseKeyCooldownTime( 0.5f );
  868. }
  869. }
  870. if ( pPhysGunUser )
  871. {
  872. if ( pPhysGunUser->GetTeamNumber() == TEAM_RED )
  873. {
  874. m_OnOrangePickUp.FireOutput( pPhysGunUser, this );
  875. }
  876. else if ( pPhysGunUser->GetTeamNumber() == TEAM_BLUE )
  877. {
  878. m_OnBluePickUp.FireOutput( pPhysGunUser, this );
  879. }
  880. }
  881. }
  882. //-----------------------------------------------------------------------------
  883. // Purpose: Turn on our rotation controller when we're dropped nicely
  884. //-----------------------------------------------------------------------------
  885. ConVar sv_box_physgundrop_angle_threshold("sv_box_physgundrop_angle_threshold", "70.f");
  886. void CPropWeightedCube::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason )
  887. {
  888. BaseClass::OnPhysGunDrop( pPhysGunUser, reason );
  889. // Only care about this if we're dropped, as opposed to launched or thrown
  890. if ( reason != DROPPED_BY_PLAYER && reason != DROPPED_BY_CANNON )
  891. return;
  892. // Enable the controller for a short time
  893. if ( m_pController )
  894. {
  895. m_pController->Activate();
  896. Vector vecForward;
  897. AngleVectors( GetAbsAngles(), &vecForward );
  898. m_pController->SetAlignmentVector( vecForward );
  899. m_pController->SuspendAfter( gpGlobals->curtime + 0.5f );
  900. }
  901. // When player drop the box and player's up is not world up, try to throw the box in the local down direction
  902. bool bThrowBoxLocalDown = false;
  903. CPortal_Player *pPortalPlayer = ToPortalPlayer( pPhysGunUser );
  904. if ( pPortalPlayer && !AlmostEqual( DotProduct( pPortalPlayer->GetPortalPlayerLocalData().m_Up, Vector( 0, 0, 1 ) ), 1.f ) )
  905. {
  906. // check if player looks too far off the ground, then just drop the box with gravity
  907. Vector vForward;
  908. pPortalPlayer->GetVectors( &vForward, NULL, NULL );
  909. float flLookAngle = RAD2DEG( acosf( DotProduct( vForward, pPortalPlayer->GetPortalPlayerLocalData().m_StickNormal ) ) );
  910. bThrowBoxLocalDown = flLookAngle >= sv_box_physgundrop_angle_threshold.GetFloat();
  911. if( bThrowBoxLocalDown )
  912. {
  913. float flDropSpeed = 400.f;
  914. Vector vecDownVelocity = -( flDropSpeed * pPortalPlayer->GetPortalPlayerLocalData().m_Up );
  915. IPhysicsObject *pPhysics = VPhysicsGetObject();
  916. if ( pPhysics )
  917. {
  918. pPhysics->SetVelocityInstantaneous( &vecDownVelocity, NULL );
  919. }
  920. }
  921. }
  922. }
  923. //-----------------------------------------------------------------------------
  924. // Purpose: Only bother with preferred carry angles if we're a reflective cube
  925. //-----------------------------------------------------------------------------
  926. bool CPropWeightedCube::HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer )
  927. {
  928. return ( m_nCubeType == CUBE_REFLECTIVE ) || ( /*FIXME: Bring back for DLC2 !sv_schrodinger_laser_world_aligned.GetBool() && */ m_nCubeType == CUBE_SCHRODINGER && m_hLaser.Get() );
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Purpose:
  932. //-----------------------------------------------------------------------------
  933. void CPropWeightedCube::NotifySystemEvent(CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
  934. {
  935. // On teleport, we record a pointer to the portal we are arriving at
  936. if ( eventType == NOTIFY_EVENT_TELEPORT )
  937. {
  938. CPortal_Base2D *pEnteredPortal = dynamic_cast<CPortal_Base2D*>( pNotify );
  939. if ( pEnteredPortal && m_pController )
  940. {
  941. Vector vecWorldAign = pEnteredPortal->m_matrixThisToLinked.ApplyRotation( m_pController->GetAlignmentVector() );
  942. vecWorldAign.NormalizeInPlace();
  943. m_pController->SetAlignmentVector( vecWorldAign );
  944. }
  945. }
  946. BaseClass::NotifySystemEvent( pNotify, eventType, params );
  947. }
  948. //-----------------------------------------------------------------------------
  949. // Purpose:
  950. //-----------------------------------------------------------------------------
  951. void CPropWeightedCube::Paint( PaintPowerType paintType, const Vector &worldContactPt )
  952. {
  953. BaseClass::Paint( paintType, worldContactPt );
  954. SetPaintedMaterial( paintType );
  955. SetCubeSkin();
  956. CPropWeightedCube *pTwin = m_hSchrodingerTwin.Get();
  957. if ( pTwin && pTwin->GetPaintedPower() != paintType )
  958. {
  959. pTwin->Paint( paintType, worldContactPt );
  960. }
  961. }
  962. void CPropWeightedCube::SetPaintedMaterial( PaintPowerType paintType )
  963. {
  964. if ( m_nCurrentPaintedType != paintType && paintType != NO_POWER )
  965. {
  966. m_OnPainted.FireOutput( this, this );
  967. }
  968. m_nCurrentPaintedType = paintType;
  969. switch( paintType )
  970. {
  971. case BOUNCE_POWER:
  972. {
  973. //Set the box to be bouncy
  974. IPhysicsObject* pPhysObject = VPhysicsGetObject();
  975. if( pPhysObject )
  976. {
  977. pPhysObject->SetMaterialIndex( m_nBouncyMaterialIndex );
  978. }
  979. ExitDisabledState();
  980. break;
  981. }
  982. case SPEED_POWER:
  983. {
  984. IPhysicsObject* pPhysObject = VPhysicsGetObject();
  985. if( pPhysObject )
  986. {
  987. pPhysObject->SetMaterialIndex( BaseClass::GetSpeedMaterialIndex() );
  988. }
  989. break;
  990. }
  991. case PORTAL_POWER:
  992. case REFLECT_POWER:
  993. case NO_POWER:
  994. default:
  995. {
  996. // Store our material index
  997. IPhysicsObject* pPhysObject = VPhysicsGetObject();
  998. if( pPhysObject )
  999. {
  1000. pPhysObject->SetMaterialIndex( m_nOriginalMaterialIndex );
  1001. }
  1002. break;
  1003. }
  1004. }
  1005. }
  1006. CPropWeightedCube* CPropWeightedCube::GetSchrodingerTwin( void )
  1007. {
  1008. return m_hSchrodingerTwin;
  1009. }
  1010. void CPropWeightedCube::UpdateSchrodingerSound( void )
  1011. {
  1012. if ( !m_hSchrodingerTwin.Get() )
  1013. return;
  1014. float fDist = m_hSchrodingerTwin->GetDistanceToEntity( this );
  1015. if ( m_pSchrodingerSound )
  1016. {
  1017. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
  1018. controller.SoundChangeVolume( m_pSchrodingerSound, RemapValClamped( fDist, 350.0f, 0.0f, 0.0f, 1.0f ), 0.1 );
  1019. }
  1020. }
  1021. void CPropWeightedCube::SetLaser( CBaseEntity *pLaser )
  1022. {
  1023. m_hLaser = pLaser;
  1024. if ( pLaser )
  1025. {
  1026. CBasePlayer *pPlayer = GetPlayerHoldingEntity( this );
  1027. if ( pPlayer )
  1028. {
  1029. UpdatePreferredAngles( pPlayer );
  1030. }
  1031. if ( GetCubeType() == CUBE_SCHRODINGER )
  1032. {
  1033. // FIXME: Need a better sound for this
  1034. //EmitSound( "prop_laser_catcher.poweron" );
  1035. }
  1036. }
  1037. else
  1038. {
  1039. if ( GetCubeType() == CUBE_SCHRODINGER )
  1040. {
  1041. // FIXME: Need a better sound for this
  1042. //EmitSound( "prop_laser_catcher.poweroff" );
  1043. }
  1044. }
  1045. // need to update transmitstate to prevent laser going through box when box goes outside PVS
  1046. UpdateTransmitState();
  1047. }
  1048. bool CPropWeightedCube::ShouldEnterDisabledState( void )
  1049. {
  1050. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  1051. if( pPhysicsObject )
  1052. {
  1053. if( !( pPhysicsObject->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) && pPhysicsObject->IsAsleep() )
  1054. {
  1055. return true;
  1056. }
  1057. }
  1058. return false;
  1059. }
  1060. void CPropWeightedCube::EnterDisabledState( void )
  1061. {
  1062. if ( !m_bMovementDisabled )
  1063. {
  1064. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  1065. if( pPhysicsObject )
  1066. {
  1067. pPhysicsObject->EnableMotion( false );
  1068. }
  1069. m_bMovementDisabled = true;
  1070. SetThink( &CPropWeightedCube::DisabledThink );
  1071. SetNextThink( gpGlobals->curtime + reflector_cube_disabled_think_rate.GetFloat() );
  1072. }
  1073. }
  1074. void CPropWeightedCube::ExitDisabledState( void )
  1075. {
  1076. if ( m_bMovementDisabled )
  1077. {
  1078. m_bMovementDisabled = false;
  1079. EnableMotion();
  1080. }
  1081. }
  1082. void CPropWeightedCube::InputExitDisabledState( inputdata_t &in )
  1083. {
  1084. ExitDisabledState();
  1085. }
  1086. void CPropWeightedCube::OnEnteredTractorBeam( void )
  1087. {
  1088. SetThink( &CPropWeightedCube::TractorBeamThink );
  1089. SetNextThink( gpGlobals->curtime );
  1090. }
  1091. void CPropWeightedCube::OnExitedTractorBeam( void )
  1092. {
  1093. SetThink( &CPropWeightedCube::ExitTractorBeamThink );
  1094. SetNextThink( gpGlobals->curtime );
  1095. }
  1096. void CPropWeightedCube::TractorBeamThink( void )
  1097. {
  1098. if ( m_bMovementDisabled )
  1099. return;
  1100. // Stop colliding with player and freeze any rotational speed
  1101. SetCollisionGroup( COLLISION_GROUP_PLAYER_HELD );
  1102. IPhysicsObject *pPhys = VPhysicsGetObject();
  1103. if ( pPhys )
  1104. {
  1105. AngularImpulse vZeroRotation( vec3_origin );
  1106. pPhys->SetVelocity( NULL, &vZeroRotation );
  1107. }
  1108. // Give players 2 seconds to get out of the way
  1109. SetThink( &CPropWeightedCube::ExitTractorBeamThink );
  1110. SetNextThink( gpGlobals->curtime + 2.0f );
  1111. }
  1112. void CPropWeightedCube::ExitTractorBeamThink( void )
  1113. {
  1114. bool bIntersectingPlayer = false;
  1115. for( int i = 1; i <= gpGlobals->maxClients; ++i )
  1116. {
  1117. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  1118. if ( pPlayer )
  1119. {
  1120. if ( Intersects( pPlayer ) )
  1121. {
  1122. bIntersectingPlayer = true;
  1123. break;
  1124. }
  1125. }
  1126. }
  1127. if ( bIntersectingPlayer )
  1128. {
  1129. SetThink( &CPropWeightedCube::ExitTractorBeamThink );
  1130. SetNextThink( gpGlobals->curtime + 0.2f );
  1131. }
  1132. else
  1133. {
  1134. // Start colliding with player
  1135. SetCollisionGroup( COLLISION_GROUP_WEIGHTED_CUBE );
  1136. }
  1137. }
  1138. void CPropWeightedCube::InputSetPaint( inputdata_t &in )
  1139. {
  1140. Paint( static_cast< PaintPowerType >( in.value.Int() ), Vector( 0.0f, 0.0f, 0.0f ) );
  1141. }
  1142. void CPropWeightedCube::StartTouch( CBaseEntity *pOther )
  1143. {
  1144. if( m_bMovementDisabled )
  1145. {
  1146. if( pOther->IsPlayer() )
  1147. {
  1148. Vector vecPlayerForward;
  1149. AngleVectors( pOther->EyeAngles(), &vecPlayerForward );
  1150. vecPlayerForward.NormalizeInPlace();
  1151. Vector vecCubeToPlayer = (GetAbsOrigin() - pOther->EyePosition()).Normalized();
  1152. float flPlayerLookDot = DotProduct( vecCubeToPlayer, vecPlayerForward );
  1153. float flCubeDirDot = DotProduct( Forward().Normalized(), vecPlayerForward );
  1154. //DevMsg( "Dot:%f, CubeDot:%f\n", flPlayerLookDot, flCubeDirDot );
  1155. //If the cube is in front of the player
  1156. if( ( flPlayerLookDot > 0.8f && flCubeDirDot > 0.8f ) || ( flPlayerLookDot > 0.85f ) )
  1157. {
  1158. ExitDisabledState();
  1159. }
  1160. }
  1161. }
  1162. if( pOther->IsPlayer() )
  1163. {
  1164. m_bTouchedByPlayer = true;
  1165. }
  1166. BaseClass::StartTouch( pOther );
  1167. }
  1168. void CPropWeightedCube::SchrodingerThink( void )
  1169. {
  1170. UpdateSchrodingerSound();
  1171. //Keep thinking
  1172. SetContextThink( &CPropWeightedCube::SchrodingerThink, gpGlobals->curtime + reflector_cube_disabled_think_rate.GetFloat(), SCHRODINGER_THINK_CONTEXT );
  1173. }
  1174. void CPropWeightedCube::DisabledThink( void )
  1175. {
  1176. bool hasPaintPower = false;
  1177. if( engine->HasPaintmap() )
  1178. {
  1179. if( GetPaintedPower() != NO_POWER )
  1180. {
  1181. hasPaintPower = true;
  1182. }
  1183. else
  1184. {
  1185. for( int i = 0; i < PAINT_POWER_TYPE_COUNT; ++i )
  1186. {
  1187. if( !IsInactivePower( GetPaintPower(i) ) )
  1188. {
  1189. hasPaintPower = true;
  1190. break;
  1191. }
  1192. }
  1193. }
  1194. }
  1195. //If the cube no longer has a laser attached to it or has a paint power
  1196. if( !HasLaser() || hasPaintPower )
  1197. {
  1198. ExitDisabledState();
  1199. return;
  1200. }
  1201. //Keep thinking
  1202. SetNextThink( gpGlobals->curtime + reflector_cube_disabled_think_rate.GetFloat() );
  1203. }
  1204. void CPropWeightedCube::InputDisablePickup( inputdata_t &in )
  1205. {
  1206. m_bPickupDisabled = true;
  1207. }
  1208. void CPropWeightedCube::InputEnablePickup( inputdata_t &in )
  1209. {
  1210. m_bPickupDisabled = false;
  1211. }
  1212. void CPropWeightedCube::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1213. {
  1214. if( m_bPickupDisabled == false )
  1215. {
  1216. BaseClass::Use( pActivator, pCaller, useType, value );
  1217. }
  1218. }
  1219. //-----------------------------------------------------------------------------
  1220. // Purpose:
  1221. //-----------------------------------------------------------------------------
  1222. bool UTIL_IsWeightedCube( CBaseEntity *pEntity )
  1223. {
  1224. if ( pEntity == NULL )
  1225. return false;
  1226. return ( FClassnameIs( pEntity, "prop_weighted_cube" ) );
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Purpose:
  1230. //-----------------------------------------------------------------------------
  1231. bool UTIL_IsReflectiveCube( CBaseEntity *pEntity )
  1232. {
  1233. if ( UTIL_IsWeightedCube( pEntity ) == false )
  1234. return false;
  1235. CPropWeightedCube *pCube = assert_cast<CPropWeightedCube*>( pEntity );
  1236. return ( pCube && pCube->GetCubeType() == CUBE_REFLECTIVE );
  1237. }
  1238. #ifndef CLIENT_DLL
  1239. bool UTIL_IsSchrodinger( CBaseEntity *pEntity )
  1240. {
  1241. if ( !UTIL_IsWeightedCube( pEntity ) )
  1242. return false;
  1243. CPropWeightedCube *pCube = assert_cast<CPropWeightedCube*>( pEntity );
  1244. if ( !pCube )
  1245. return false;
  1246. return pCube->GetCubeType() == CUBE_SCHRODINGER;
  1247. }
  1248. CPropWeightedCube* UTIL_GetSchrodingerTwin( CBaseEntity *pEntity )
  1249. {
  1250. if ( !UTIL_IsSchrodinger( pEntity ) )
  1251. return NULL;
  1252. CPropWeightedCube *pCube = assert_cast<CPropWeightedCube*>( pEntity );
  1253. if ( !pCube )
  1254. return NULL;
  1255. return pCube->GetSchrodingerTwin();
  1256. }
  1257. #endif
  1258. #define PORTAL_REFLECTOR_CUBE_MODEL_NAME "models/props/reflectocube.mdl"
  1259. #define PORTAL_WEIGHT_BOX_MODEL_NAME "models/props/metal_box.mdl"
  1260. #ifndef CLIENT_DLL
  1261. //-----------------------------------------------------------------------------
  1262. // Creates a weighted cube of a specific type
  1263. //-----------------------------------------------------------------------------
  1264. void CPropWeightedCube::CreatePortalWeightedCube( WeightedCubeType_e objectType, bool bAtCursorPosition, const Vector &position )
  1265. {
  1266. MDLCACHE_CRITICAL_SECTION();
  1267. bool allowPrecache = CBaseEntity::IsPrecacheAllowed();
  1268. CBaseEntity::SetAllowPrecache( true );
  1269. // Try to create entity
  1270. CPropWeightedCube *entity = ( CPropWeightedCube* )CreateEntityByName("prop_weighted_cube");
  1271. if (entity)
  1272. {
  1273. //entity->PrecacheModel( PORTAL_REFLECTOR_CUBE_MODEL_NAME );
  1274. //entity->SetModel( PORTAL_REFLECTOR_CUBE_MODEL_NAME );
  1275. entity->SetName( MAKE_STRING("cube") );
  1276. entity->AddSpawnFlags( SF_PHYSPROP_ENABLE_PICKUP_OUTPUT );
  1277. entity->m_nCubeType = objectType;
  1278. entity->m_bNewSkins = true;
  1279. entity->Precache();
  1280. if ( !bAtCursorPosition )
  1281. {
  1282. entity->SetAbsOrigin( position );
  1283. }
  1284. DispatchSpawn(entity);
  1285. if ( bAtCursorPosition )
  1286. {
  1287. // Now attempt to drop into the world
  1288. CBasePlayer* pPlayer = UTIL_GetCommandClient();
  1289. trace_t tr;
  1290. Vector forward;
  1291. pPlayer->EyeVectors( &forward );
  1292. UTIL_TraceLine(pPlayer->EyePosition(),
  1293. pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_SOLID,
  1294. pPlayer, COLLISION_GROUP_WEIGHTED_CUBE, &tr );
  1295. if ( tr.fraction != 1.0 )
  1296. {
  1297. tr.endpos.z += 12;
  1298. entity->Teleport( &tr.endpos, NULL, NULL );
  1299. UTIL_DropToFloor( entity, MASK_SOLID );
  1300. }
  1301. }
  1302. // This entity should send its object caps to the client
  1303. entity->UpdateObjectCapsCache();
  1304. }
  1305. CBaseEntity::SetAllowPrecache( allowPrecache );
  1306. }
  1307. // Console command functions
  1308. void CC_Create_PortalWeightedCube()
  1309. {
  1310. CPropWeightedCube::CreatePortalWeightedCube( CUBE_STANDARD );
  1311. }
  1312. void CC_Create_PortalCompanionCube()
  1313. {
  1314. CPropWeightedCube::CreatePortalWeightedCube( CUBE_COMPANION );
  1315. }
  1316. void CC_Create_PortalReflectorCube()
  1317. {
  1318. CPropWeightedCube::CreatePortalWeightedCube( CUBE_REFLECTIVE );
  1319. }
  1320. void CC_Create_PortalWeightedSphere()
  1321. {
  1322. CPropWeightedCube::CreatePortalWeightedCube( CUBE_SPHERE );
  1323. }
  1324. void CC_Create_PortalWeightedAntique()
  1325. {
  1326. CPropWeightedCube::CreatePortalWeightedCube( CUBE_ANTIQUE );
  1327. }
  1328. void CC_Create_PortalWeightedSchrodinger()
  1329. {
  1330. CPropWeightedCube::CreatePortalWeightedCube( CUBE_SCHRODINGER );
  1331. }
  1332. // Console commands for creating cubes
  1333. static ConCommand ent_create_portal_reflector_cube("ent_create_portal_reflector_cube", CC_Create_PortalReflectorCube, "Creates a laser reflector cube cube where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1334. static ConCommand ent_create_portal_companion_cube("ent_create_portal_companion_cube", CC_Create_PortalCompanionCube, "Creates a companion cube where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1335. static ConCommand ent_create_portal_weighted_cube("ent_create_portal_weighted_cube", CC_Create_PortalWeightedCube, "Creates a standard cube where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1336. static ConCommand ent_create_portal_weighted_sphere("ent_create_portal_weighted_sphere", CC_Create_PortalWeightedSphere, "Creates a weighted sphere where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1337. static ConCommand ent_create_portal_weighted_antique("ent_create_portal_weighted_antique", CC_Create_PortalWeightedAntique, "Creates an antique cube where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1338. // FIXME: Bring this back for DLC2
  1339. //static ConCommand ent_create_portal_weighted_schrodinger("ent_create_portal_weighted_schrodinger", CC_Create_PortalWeightedSchrodinger, "Creates an Schrodinger cube where the player is looking.", FCVAR_GAMEDLL | FCVAR_CHEAT);
  1340. #endif // CLIENT_DLL