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.

618 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //
  4. //=====================================================================================//
  5. #include "cbase.h" // for pch
  6. #include "props.h"
  7. #include "filters.h"
  8. #include "achievementmgr.h"
  9. extern CAchievementMgr g_AchievementMgrPortal;
  10. #define RADIO_MODEL_NAME "models/props/radio_reference.mdl"
  11. //#define RADIO_DEBUG_SERVER
  12. class CDinosaurSignal : public CBaseEntity
  13. {
  14. public:
  15. DECLARE_DATADESC();
  16. DECLARE_SERVERCLASS();
  17. DECLARE_CLASS( CDinosaurSignal, CBaseEntity );
  18. void Spawn();
  19. int UpdateTransmitState();
  20. #if RADIO_DEBUG_SERVER
  21. int DrawDebugTextOverlays( void );
  22. #endif
  23. CNetworkString( m_szSoundName, 128 );
  24. CNetworkVar( float, m_flInnerRadius );
  25. CNetworkVar( float, m_flOuterRadius );
  26. CNetworkVar( int, m_nSignalID );
  27. };
  28. LINK_ENTITY_TO_CLASS( updateitem1, CDinosaurSignal );
  29. BEGIN_DATADESC( CDinosaurSignal )
  30. DEFINE_AUTO_ARRAY( m_szSoundName, FIELD_CHARACTER ),
  31. DEFINE_FIELD( m_flOuterRadius, FIELD_FLOAT ),
  32. DEFINE_FIELD( m_flInnerRadius, FIELD_FLOAT ),
  33. DEFINE_FIELD( m_nSignalID, FIELD_INTEGER ),
  34. END_DATADESC()
  35. IMPLEMENT_SERVERCLASS_ST( CDinosaurSignal, DT_DinosaurSignal )
  36. SendPropString( SENDINFO(m_szSoundName) ),
  37. SendPropFloat( SENDINFO(m_flOuterRadius) ),
  38. SendPropFloat( SENDINFO(m_flInnerRadius) ),
  39. SendPropInt( SENDINFO(m_nSignalID) ),
  40. END_SEND_TABLE()
  41. void CDinosaurSignal::Spawn()
  42. {
  43. PrecacheScriptSound( m_szSoundName.Get() );
  44. BaseClass::Spawn();
  45. SetTransmitState( FL_EDICT_ALWAYS );
  46. }
  47. int CDinosaurSignal::UpdateTransmitState()
  48. {
  49. // ALWAYS transmit to all clients.
  50. return SetTransmitState( FL_EDICT_ALWAYS );
  51. }
  52. #if RADIO_DEBUG_SERVER
  53. int CDinosaurSignal::DrawDebugTextOverlays( void )
  54. {
  55. int text_offset = BaseClass::DrawDebugTextOverlays();
  56. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  57. {
  58. NDebugOverlay::Sphere( GetAbsOrigin(), GetAbsAngles(), m_flInnerRadius, 255, 0, 0, 64, false, 0.1f );
  59. NDebugOverlay::Sphere( GetAbsOrigin(), GetAbsAngles(), m_flOuterRadius, 0, 255, 0, 64, false, 0.1f );
  60. }
  61. return text_offset;
  62. }
  63. #endif
  64. class CPortal_Dinosaur : public CPhysicsProp
  65. {
  66. public:
  67. DECLARE_CLASS( CPortal_Dinosaur, CPhysicsProp );
  68. DECLARE_DATADESC();
  69. DECLARE_SERVERCLASS();
  70. virtual void Spawn();
  71. virtual void Precache();
  72. virtual QAngle PreferredCarryAngles( void ) { return QAngle( 0, 180, 0 ); }
  73. virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return true; }
  74. virtual void Activate();
  75. CNetworkHandle( CDinosaurSignal, m_hDinosaur_Signal );
  76. CNetworkVar( bool, m_bAlreadyDiscovered );
  77. };
  78. LINK_ENTITY_TO_CLASS( updateitem2, CPortal_Dinosaur );
  79. BEGIN_DATADESC( CPortal_Dinosaur )
  80. DEFINE_FIELD( m_hDinosaur_Signal, FIELD_EHANDLE ),
  81. DEFINE_FIELD( m_bAlreadyDiscovered, FIELD_BOOLEAN ),
  82. END_DATADESC()
  83. IMPLEMENT_SERVERCLASS_ST( CPortal_Dinosaur, DT_PropDinosaur )
  84. SendPropEHandle( SENDINFO( m_hDinosaur_Signal ) ),
  85. SendPropBool( SENDINFO( m_bAlreadyDiscovered ) ),
  86. END_SEND_TABLE()
  87. void CPortal_Dinosaur::Precache()
  88. {
  89. PrecacheModel( RADIO_MODEL_NAME );
  90. PrecacheScriptSound( "Portal.room1_radio" );
  91. PrecacheScriptSound( "UpdateItem.Static" );
  92. PrecacheScriptSound( "UpdateItem.Dinosaur01" );
  93. PrecacheScriptSound( "UpdateItem.Dinosaur02" );
  94. PrecacheScriptSound( "UpdateItem.Dinosaur03" );
  95. PrecacheScriptSound( "UpdateItem.Dinosaur04" );
  96. PrecacheScriptSound( "UpdateItem.Dinosaur05" );
  97. PrecacheScriptSound( "UpdateItem.Dinosaur06" );
  98. PrecacheScriptSound( "UpdateItem.Dinosaur07" );
  99. PrecacheScriptSound( "UpdateItem.Dinosaur08" );
  100. PrecacheScriptSound( "UpdateItem.Dinosaur09" );
  101. PrecacheScriptSound( "UpdateItem.Dinosaur10" );
  102. PrecacheScriptSound( "UpdateItem.Dinosaur11" );
  103. PrecacheScriptSound( "UpdateItem.Dinosaur12" );
  104. PrecacheScriptSound( "UpdateItem.Dinosaur13" );
  105. PrecacheScriptSound( "UpdateItem.Dinosaur14" );
  106. PrecacheScriptSound( "UpdateItem.Dinosaur15" );
  107. PrecacheScriptSound( "UpdateItem.Dinosaur16" );
  108. PrecacheScriptSound( "UpdateItem.Dinosaur17" );
  109. PrecacheScriptSound( "UpdateItem.Dinosaur18" );
  110. PrecacheScriptSound( "UpdateItem.Dinosaur19" );
  111. PrecacheScriptSound( "UpdateItem.Dinosaur20" );
  112. PrecacheScriptSound( "UpdateItem.Dinosaur21" );
  113. PrecacheScriptSound( "UpdateItem.Dinosaur22" );
  114. PrecacheScriptSound( "UpdateItem.Dinosaur23" );
  115. PrecacheScriptSound( "UpdateItem.Dinosaur24" );
  116. PrecacheScriptSound( "UpdateItem.Dinosaur25" );
  117. PrecacheScriptSound( "UpdateItem.Dinosaur26" );
  118. PrecacheScriptSound( "UpdateItem.Fizzle" );
  119. }
  120. void CPortal_Dinosaur::Spawn()
  121. {
  122. Precache();
  123. KeyValue( "model", RADIO_MODEL_NAME );
  124. m_spawnflags |= SF_PHYSPROP_START_ASLEEP;
  125. BaseClass::Spawn();
  126. }
  127. void CPortal_Dinosaur::Activate( void )
  128. {
  129. // Find the current completion status of the dinosaurs
  130. uint64 fStateFlags = 0;
  131. CBaseAchievement *pTransmissionRecvd = dynamic_cast<CBaseAchievement *>(g_AchievementMgrPortal.GetAchievementByName("PORTAL_TRANSMISSION_RECEIVED"));
  132. if ( pTransmissionRecvd )
  133. {
  134. fStateFlags = pTransmissionRecvd->GetComponentBits();
  135. }
  136. if ( m_hDinosaur_Signal != NULL )
  137. {
  138. uint64 nId = m_hDinosaur_Signal.Get()->m_nSignalID;
  139. // See if we're already tripped
  140. if ( fStateFlags & ((uint64)1<<nId) )
  141. {
  142. m_bAlreadyDiscovered = true;
  143. }
  144. }
  145. BaseClass::Activate();
  146. }
  147. struct radiolocs
  148. {
  149. const char *mapname;
  150. const char *soundname;
  151. int id;
  152. float radiopos[3];
  153. float radioang[3];
  154. float soundpos[3];
  155. float soundouterrad;
  156. float soundinnerrad;
  157. };
  158. static const radiolocs s_radiolocs[] =
  159. {
  160. {
  161. "testchmb_a_00",
  162. "UpdateItem.Dinosaur01",
  163. 0,
  164. { 0, 0, 0 },
  165. { 0, 0, 0 },
  166. { -506, -924, 161 },
  167. 200,
  168. 64
  169. },
  170. {
  171. "testchmb_a_00",
  172. "UpdateItem.Dinosaur02",
  173. 1,
  174. { -960, -634, 783 },
  175. { 0, 90, 0 },
  176. { -926.435, -256.323, 583 },
  177. 200,
  178. 64,
  179. },
  180. {
  181. "testchmb_a_01",
  182. "UpdateItem.Dinosaur03",
  183. 2,
  184. { 233, 393, 130 },
  185. { 0, 225, 0 },
  186. { 96, 160, -108 },
  187. 224,
  188. 128,
  189. },
  190. {
  191. "testchmb_a_01",
  192. "UpdateItem.Dinosaur04",
  193. 3,
  194. { -1439.89, 1076.04, 779.102 },
  195. { 0, 270, 0 },
  196. { -731, 735, 888 },
  197. 400,
  198. 64,
  199. },
  200. {
  201. // new entry
  202. "testchmb_a_02",
  203. "UpdateItem.Dinosaur05",
  204. 4,
  205. { 2, 65, 390 },
  206. { 0, 270, 0 },
  207. { -864, 192, 64},
  208. 192,
  209. 96,
  210. },
  211. {
  212. "testchmb_a_02",
  213. "UpdateItem.Dinosaur06",
  214. 21,
  215. { 111, 832, 577 },
  216. { 0, 0, 0 },
  217. { 918, 831, 512},
  218. 192,
  219. 96,
  220. },
  221. {
  222. "testchmb_a_03",
  223. "UpdateItem.Dinosaur07",
  224. 5,
  225. { -53.2337, 78.181, 236 },
  226. { 0, 225, 0 },
  227. { 304, 0, -96 },
  228. 256,
  229. 128
  230. },
  231. // new entry
  232. {
  233. "testchmb_a_03",
  234. "UpdateItem.Dinosaur08",
  235. 6,
  236. { 428.112, 0.22326, 1201 },
  237. { 0, 180, 0 },
  238. { -581.096, 193.694, 1351 },
  239. 165,
  240. 128
  241. },
  242. {
  243. "testchmb_a_04",
  244. "UpdateItem.Dinosaur09",
  245. 7,
  246. { 118, -56.6, -38.8 },
  247. { 0, 180, 0 },
  248. { -640, 256, 8 },
  249. 512,
  250. 128
  251. },
  252. // new entry
  253. {
  254. "testchmb_a_05",
  255. "UpdateItem.Dinosaur10",
  256. 8,
  257. { 64, 144, 160 },
  258. { 0, 270, 0 },
  259. { 64, 740, 7 },
  260. 350,
  261. 128
  262. },
  263. {
  264. "testchmb_a_06",
  265. "UpdateItem.Dinosaur11",
  266. 9,
  267. { 529, 315, 320 },
  268. { 0, 270, 0 },
  269. { 608, 128, -184 },
  270. 384,
  271. 160
  272. },
  273. {
  274. "testchmb_a_07",
  275. "UpdateItem.Dinosaur12",
  276. 10,
  277. { 192, -1546, 1425 },
  278. { 0, 113, 0 },
  279. { 272, -496, 1328 },
  280. 432,
  281. 88
  282. },
  283. // new entry
  284. {
  285. "testchmb_a_07",
  286. "UpdateItem.Dinosaur13",
  287. 11,
  288. { -144, -768, 256 },
  289. { 0, 90, 0 },
  290. { -192, -384, 176 },
  291. 256,
  292. 128
  293. },
  294. {
  295. "testchmb_a_08",
  296. "UpdateItem.Dinosaur14",
  297. 12,
  298. { 267, -378, 256 },
  299. { 0, 90, 0 },
  300. { -560, 96, 320 },
  301. 288,
  302. 128,
  303. },
  304. {
  305. "testchmb_a_09",
  306. "UpdateItem.Dinosaur15",
  307. 13,
  308. { 634, 1308, 256 },
  309. { 0, 180, 0 },
  310. { 386.699, 1792.43, 7},
  311. 548,
  312. 64
  313. },
  314. {
  315. "testchmb_a_10",
  316. "UpdateItem.Dinosaur16",
  317. 14,
  318. { -1420, -2752, 76 },
  319. { 0, 0, 0 },
  320. { -1968, -2880, -334 },
  321. 448,
  322. 196,
  323. },
  324. // new entry
  325. {
  326. "testchmb_a_10",
  327. "UpdateItem.Dinosaur17",
  328. 15,
  329. { 112, 1392, -63 },
  330. { 0, 260, 0 },
  331. { -189, 1220, 65 },
  332. 192,
  333. 128,
  334. },
  335. {
  336. "testchmb_a_11",
  337. "UpdateItem.Dinosaur18",
  338. 16,
  339. {0,0,0},
  340. {0,0,0},
  341. {-512,644,64},
  342. 192,
  343. 96,
  344. },
  345. {
  346. "testchmb_a_13",
  347. "UpdateItem.Dinosaur19",
  348. 17,
  349. {955,931,-267},
  350. {-90,0,0},
  351. {1472,-191,-12},
  352. 256,
  353. 128,
  354. },
  355. {
  356. "testchmb_a_14",
  357. "UpdateItem.Dinosaur20",
  358. 18,
  359. {0,0,0},
  360. {0,0,0},
  361. {144,192,1288},
  362. 807,
  363. 128,
  364. },
  365. {
  366. "testchmb_a_14",
  367. "UpdateItem.Dinosaur21",
  368. 22,
  369. {1285, 1344, 1412},
  370. {0,0,0},
  371. {2712, 894, 1011},
  372. 200,
  373. 120,
  374. },
  375. {
  376. "testchmb_a_14",
  377. "UpdateItem.Dinosaur22",
  378. 23,
  379. {-952, 336, -256},
  380. {0,0,0},
  381. {-1144, -249, 3336},
  382. 400,
  383. 128,
  384. },
  385. {
  386. "testchmb_a_15",
  387. "UpdateItem.Dinosaur23",
  388. 19,
  389. {-1529,293,-283},
  390. {0,90,0},
  391. {761,443,810},
  392. 256,
  393. 128,
  394. },
  395. {
  396. "escape_00",
  397. "UpdateItem.Dinosaur24",
  398. 24,
  399. {192, -1344, -832},
  400. {0, 135, 0},
  401. {891, 322, -184},
  402. 285,
  403. 150,
  404. },
  405. {
  406. "escape_01",
  407. "UpdateItem.Dinosaur25",
  408. 20,
  409. {0,0,0},
  410. {0,0,0},
  411. {-624, 1440, -464},
  412. 512,
  413. 128,
  414. },
  415. {
  416. "escape_02",
  417. "UpdateItem.Dinosaur26",
  418. 25,
  419. {5504, 131, -1422},
  420. {0, 90, 0},
  421. {4218, 674, 8},
  422. 300,
  423. 100,
  424. },
  425. };
  426. class CSpawnDinosaurHack : CAutoGameSystem
  427. {
  428. public:
  429. virtual void LevelInitPreEntity();
  430. virtual void LevelInitPostEntity();
  431. CPortal_Dinosaur *SpawnDinosaur( radiolocs& loc );
  432. CDinosaurSignal *SpawnSignal( radiolocs& loc );
  433. void ApplyMapSpecificHacks();
  434. };
  435. static CSpawnDinosaurHack g_SpawnRadioHack;
  436. void CSpawnDinosaurHack::LevelInitPreEntity()
  437. {
  438. UTIL_PrecacheOther( "updateitem2", RADIO_MODEL_NAME );
  439. ApplyMapSpecificHacks();
  440. }
  441. // Spawn all the Dinosaurs and sstv images
  442. void CSpawnDinosaurHack::LevelInitPostEntity()
  443. {
  444. if ( gpGlobals->eLoadType == MapLoad_LoadGame )
  445. {
  446. #if defined ( RADIO_DEBUG_SERVER )
  447. Msg( "Not spawning any Dinosaurs: Detected a map load\n" );
  448. #endif
  449. return;
  450. }
  451. IAchievement *pHeartbreaker = g_AchievementMgrPortal.GetAchievementByName("PORTAL_BEAT_GAME");
  452. if ( pHeartbreaker == NULL || pHeartbreaker->IsAchieved() == false )
  453. {
  454. #if defined ( RADIO_DEBUG_SERVER )
  455. Msg( "Not spawning any Dinosaurs: Player has not beat the game, or failed to get heartbreaker achievement from mgr\n" );
  456. #endif
  457. return;
  458. }
  459. for ( int i = 0; i < ARRAYSIZE( s_radiolocs ); ++i )
  460. {
  461. radiolocs loc = s_radiolocs[i];
  462. if ( V_strcmp( STRING(gpGlobals->mapname), loc.mapname ) == 0 )
  463. {
  464. #if defined ( RADIO_DEBUG_SERVER )
  465. Msg( "Found Dinosaur and signal info for %s, spawning.\n", loc.mapname );
  466. Msg( "Dinosaur pos: %f %f %f, ang: %f %f %f\n", loc.radiopos[0], loc.radiopos[1], loc.radiopos[2], loc.radioang[0], loc.radioang[1], loc.radioang[2] );
  467. Msg( "Signal pos: %f %f %f, inner rad: %f, outter rad: %f\n", loc.soundpos[0], loc.soundpos[1], loc.soundpos[2], loc.soundinnerrad, loc.soundouterrad );
  468. #endif
  469. CPortal_Dinosaur *pDinosaur = SpawnDinosaur( loc );
  470. CDinosaurSignal *pSignal = SpawnSignal( loc );
  471. Assert ( pDinosaur && pSignal );
  472. if ( pDinosaur && pSignal )
  473. {
  474. #if defined ( RADIO_DEBUG_SERVER )
  475. Msg( "SUCCESS: Spawned Dinosaur and signal and linked them.\n" );
  476. #endif
  477. // OK, so these really could have been the same class... not worth changing it now though.
  478. pDinosaur->m_hDinosaur_Signal.Set( pSignal );
  479. pDinosaur->Activate();
  480. }
  481. }
  482. }
  483. }
  484. CPortal_Dinosaur *CSpawnDinosaurHack::SpawnDinosaur( radiolocs& loc )
  485. {
  486. Vector vSpawnPos ( loc.radiopos[0], loc.radiopos[1], loc.radiopos[2] );
  487. QAngle vSpawnAng ( loc.radioang[0], loc.radioang[1], loc.radioang[2] );
  488. // origin and angles of zero means skip this Dinosaur creation and look for an existing radio
  489. if ( loc.radiopos[0] == 0 &&
  490. loc.radiopos[1] == 0 &&
  491. loc.radiopos[2] == 0 &&
  492. loc.radioang[0] == 0 &&
  493. loc.radioang[1] == 0 &&
  494. loc.radioang[2] == 0 )
  495. {
  496. #if defined ( RADIO_DEBUG_SERVER )
  497. Msg( "Dinosaur found with zero angles and origin. Replacing existing radio.\n" );
  498. #endif
  499. // Find existing Dinosaur, kill it and spawn at its position
  500. CPhysicsProp *pOldDinosaur = (CPhysicsProp*)gEntList.FindEntityByClassname( NULL, "prop_physics" );
  501. while ( pOldDinosaur )
  502. {
  503. if ( V_strcmp( STRING( pOldDinosaur->GetModelName() ), RADIO_MODEL_NAME ) == 0 )
  504. {
  505. vSpawnPos = pOldDinosaur->GetAbsOrigin();
  506. vSpawnAng = pOldDinosaur->GetAbsAngles();
  507. UTIL_Remove( pOldDinosaur );
  508. #if defined ( RADIO_DEBUG_SERVER )
  509. Msg( "Found Dinosaur exiting in level, replacing with %f, %f %f and %f %f %f.\n", XYZ(vSpawnPos), XYZ(vSpawnAng) );
  510. #endif
  511. break;
  512. }
  513. pOldDinosaur = (CPhysicsProp*)gEntList.FindEntityByClassname( pOldDinosaur, "prop_physics" );
  514. }
  515. }
  516. Assert( vSpawnPos != vec3_origin );
  517. CPortal_Dinosaur *pDinosaur = (CPortal_Dinosaur*)CreateEntityByName( "updateitem2" );
  518. Assert ( pDinosaur );
  519. if ( pDinosaur )
  520. {
  521. pDinosaur->SetAbsOrigin( vSpawnPos );
  522. pDinosaur->SetAbsAngles( vSpawnAng );
  523. DispatchSpawn( pDinosaur );
  524. }
  525. return pDinosaur;
  526. }
  527. CDinosaurSignal *CSpawnDinosaurHack::SpawnSignal( radiolocs& loc )
  528. {
  529. CDinosaurSignal *pSignal = (CDinosaurSignal*)CreateEntityByName( "updateitem1" );
  530. Assert ( pSignal );
  531. if ( pSignal )
  532. {
  533. #if defined ( RADIO_DEBUG_SERVER )
  534. if ( loc.soundinnerrad > loc.soundouterrad )
  535. {
  536. Assert( 0 );
  537. Warning( "Dinosaur BUG: Inner radius is greater than outer radius. Will swap them.\n" );
  538. swap( loc.soundinnerrad, loc.soundouterrad );
  539. }
  540. #endif
  541. pSignal->SetAbsOrigin( Vector( loc.soundpos[0], loc.soundpos[1], loc.soundpos[2] ) );
  542. pSignal->m_flInnerRadius = loc.soundinnerrad;
  543. pSignal->m_flOuterRadius = loc.soundouterrad;
  544. V_strncpy( pSignal->m_szSoundName.GetForModify(), loc.soundname, 128 );
  545. pSignal->m_nSignalID = loc.id;
  546. DispatchSpawn( pSignal );
  547. }
  548. return pSignal;
  549. }
  550. void CSpawnDinosaurHack::ApplyMapSpecificHacks()
  551. {
  552. if ( V_strcmp( STRING(gpGlobals->mapname), "testchmb_a_02" ) == 0 )
  553. {
  554. CBaseEntity *pFilter = CreateEntityByName( "filter_activator_name" );
  555. Assert( pFilter );
  556. if ( pFilter )
  557. {
  558. pFilter->KeyValue( "filtername", "box_2" );
  559. pFilter->KeyValue( "targetname", "filter_weight_box" );
  560. DispatchSpawn( pFilter );
  561. }
  562. }
  563. }