g_rail.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. ////////////////////////////////////////////////////////////////////////////////////////
  2. // RAVEN SOFTWARE - STAR WARS: JK II
  3. // (c) 2002 Activision
  4. //
  5. // Rail System
  6. //
  7. // The rail system is intended to provide a means for generating moving entities along
  8. // tracks of varying speed and direction. The entities are pulled from the map based
  9. // upon their targets and recycled in random positions and order
  10. //
  11. ////////////////////////////////////////////////////////////////////////////////////////
  12. #include "g_headers.h"
  13. ////////////////////////////////////////////////////////////////////////////////////////
  14. // Externs & Fwd Decl.
  15. ////////////////////////////////////////////////////////////////////////////////////////
  16. //extern cvar_t* g_nav1;
  17. extern void G_SoundAtSpot( vec3_t org, int soundIndex, qboolean broadcast );
  18. class CRailTrack;
  19. class CRailLane;
  20. class CRailMover;
  21. ////////////////////////////////////////////////////////////////////////////////////////
  22. // Includes
  23. ////////////////////////////////////////////////////////////////////////////////////////
  24. #include "b_local.h"
  25. #if !defined(RATL_ARRAY_VS_INC)
  26. #include "..\Ratl\array_vs.h"
  27. #endif
  28. #if !defined(RATL_VECTOR_VS_INC)
  29. #include "..\Ratl\vector_vs.h"
  30. #endif
  31. #if !defined(RAVL_VEC_INC)
  32. #include "..\Ravl\CVec.h"
  33. #endif
  34. #if !defined(RUFL_HSTRING_INC)
  35. #include "..\Rufl\hstring.h"
  36. #endif
  37. #if !defined(RATL_GRID_VS_INC)
  38. #include "..\Ratl\grid_vs.h"
  39. #endif
  40. #if !defined(RATL_POOL_VS_INC)
  41. #include "..\Ratl\pool_vs.h"
  42. #endif
  43. #ifdef _XBOX
  44. using dllNamespace::hstring;
  45. #endif
  46. ////////////////////////////////////////////////////////////////////////////////////////
  47. // Constants
  48. ////////////////////////////////////////////////////////////////////////////////////////
  49. #define MAX_TRACKS 4
  50. #define MAX_LANES 8
  51. #define MAX_MOVERS 150
  52. #define MAX_MOVER_ENTS 10
  53. #define MAX_MOVERS_TRACK 80
  54. #define MAX_COLS 32
  55. #define MAX_ROWS 96
  56. #define MAX_ROW_HISTORY 10
  57. #define WOOSH_DEBUG 0
  58. #define WOOSH_ALL_RANGE 1500.0f
  59. #define WOOSH_SUPPORT_RANGE 2500.0f
  60. #define WOOSH_TUNNEL_RANGE 3000.0f
  61. bool mRailSystemActive = false;
  62. ////////////////////////////////////////////////////////////////////////////////////////
  63. // The Rail Track
  64. //
  65. // Tracks are the central component to the rails system. They provide the master
  66. // repositry of all movers and maintain the list of available movers as well as
  67. //
  68. ////////////////////////////////////////////////////////////////////////////////////////
  69. class CRailTrack
  70. {
  71. public:
  72. void Setup(gentity_t *ent)
  73. {
  74. mName = ent->targetname;
  75. mSpeedGridCellsPerSecond = ent->speed;
  76. mNumMoversPerRow = ent->count;
  77. mMins = ent->mins;
  78. mMaxs = ent->maxs;
  79. mStartTime = ent->delay + level.time;
  80. mGridCellSize = (ent->radius!=0.0f)?(ent->radius):(1.0f);
  81. mVertical = (ent->s.angles[1]==90.0f || ent->s.angles[1]==270.0f);
  82. mNegative = (ent->s.angles[1]==180.0f || ent->s.angles[1]==270.0f); // From Maxs To Mins
  83. mWAxis = (mVertical)?(0):(1);
  84. mHAxis = (mVertical)?(1):(0);
  85. mTravelDistanceUnits = ent->maxs[mHAxis] - ent->mins[mHAxis];
  86. mRow = 0;
  87. mNextUpdateTime = 0;
  88. mCenterLocked = false;
  89. SnapVectorToGrid(mMins);
  90. SnapVectorToGrid(mMaxs);
  91. // Calculate Number Of Rows And Columns
  92. //--------------------------------------
  93. mRows = ((mMaxs[mHAxis] - mMins[mHAxis]) / mGridCellSize);
  94. mCols = ((mMaxs[mWAxis] - mMins[mWAxis]) / mGridCellSize);
  95. // Calculate Grid Center
  96. //-----------------------
  97. mGridCenter = ((mMins+mMaxs)*0.5f);
  98. SnapVectorToGrid(mGridCenter);
  99. // Calculate Speed & Velocity
  100. //----------------------------
  101. mSpeedUnitsPerMillisecond = mSpeedGridCellsPerSecond * mGridCellSize / 1000.0f;
  102. mTravelTimeMilliseconds = mTravelDistanceUnits / mSpeedUnitsPerMillisecond;
  103. AngleVectors(ent->s.angles, mDirection.v, 0, 0);
  104. mDirection.SafeNorm();
  105. mVelocity = mDirection;
  106. mVelocity *= (mSpeedGridCellsPerSecond * mGridCellSize);
  107. mNextUpdateDelay = 1000.0f / (float)(mSpeedGridCellsPerSecond);
  108. // Calculate Bottom Left Corner
  109. //------------------------------
  110. mGridBottomLeftCorner = ent->mins;
  111. if (ent->s.angles[1]==180.0f)
  112. {
  113. mGridBottomLeftCorner[0] = mMaxs[0];
  114. }
  115. else if (ent->s.angles[1]==270.0f)
  116. {
  117. mGridBottomLeftCorner[1] = mMaxs[1];
  118. }
  119. SnapVectorToGrid(mGridBottomLeftCorner);
  120. mCells.set_size(mCols/*xSize*/, mRows/*ySize*/);
  121. mCells.init(0);
  122. mMovers.clear();
  123. if (!mNumMoversPerRow)
  124. {
  125. mNumMoversPerRow = 3;
  126. }
  127. // Safe Clamp Number Of Rows & Cols
  128. //----------------------------------
  129. if (mRows>(MAX_ROWS-1))
  130. {
  131. mRows = (MAX_ROWS-1);
  132. assert(0);
  133. }
  134. if (mCols>(MAX_COLS-1))
  135. {
  136. mCols = (MAX_COLS-1);
  137. assert(0);
  138. }
  139. }
  140. void SnapVectorToGrid(CVec3& Vec)
  141. {
  142. SnapFloatToGrid(Vec[0]);
  143. SnapFloatToGrid(Vec[1]);
  144. }
  145. void SnapFloatToGrid(float& f)
  146. {
  147. f = (int)(f);
  148. bool fNeg = (f<0);
  149. if (fNeg)
  150. {
  151. f *= -1; // Temporarly make it positive
  152. }
  153. int Offset = ((int)(f) % (int)(mGridCellSize));
  154. int OffsetAbs = abs(Offset);
  155. if (OffsetAbs>(mGridCellSize/2))
  156. {
  157. Offset = (mGridCellSize - OffsetAbs) * -1;
  158. }
  159. f -= Offset;
  160. if (fNeg)
  161. {
  162. f *= -1; // Put It Back To Negative
  163. }
  164. f = (int)(f);
  165. assert(((int)(f)%(int)(mGridCellSize)) == 0);
  166. }
  167. void Update();
  168. bool TestMoverInCells(CRailMover* mover, int atCol);
  169. void InsertMoverInCells(CRailMover* mover, int atCol);
  170. void RandomizeTestCols(int startCol, int stopCol);
  171. public:
  172. hstring mName;
  173. int mRow;
  174. int mNumMoversPerRow;
  175. int mNextUpdateTime;
  176. int mNextUpdateDelay;
  177. int mStartTime;
  178. int mRows;
  179. int mCols;
  180. bool mVertical;
  181. bool mNegative;
  182. int mHAxis;
  183. int mWAxis;
  184. int mSpeedGridCellsPerSecond;
  185. float mSpeedUnitsPerMillisecond;
  186. int mTravelTimeMilliseconds;
  187. float mTravelDistanceUnits;
  188. CVec3 mDirection;
  189. CVec3 mVelocity;
  190. CVec3 mMins;
  191. CVec3 mMaxs;
  192. CVec3 mGridBottomLeftCorner;
  193. CVec3 mGridCenter;
  194. float mGridCellSize;
  195. bool mCenterLocked;
  196. ratl::grid2_vs<CRailMover*, MAX_COLS, MAX_ROWS> mCells;
  197. ratl::vector_vs<CRailMover*, MAX_MOVERS_TRACK> mMovers;
  198. ratl::vector_vs<int, MAX_ROWS> mTestCols;
  199. };
  200. ratl::vector_vs<CRailTrack, MAX_TRACKS> mRailTracks;
  201. ////////////////////////////////////////////////////////////////////////////////////////
  202. /*QUAKED rail_track (0 .5 .8) ? x x x x x x x x
  203. A rail track determines what location and direction rail_mover entities go. Don't bother with any origin brushes. Make sure to set:
  204. "radius" Number of units to break down into grid size
  205. "speed" Number of grid sized units per second rail_movers will go at
  206. "angle" The direction rail_movers will go
  207. "count" The number of mover ents the track will try to add per row
  208. "delay" How long the ent will wait from the start of the level before placing movers
  209. */
  210. ////////////////////////////////////////////////////////////////////////////////////////
  211. void SP_rail_track(gentity_t *ent)
  212. {
  213. gi.SetBrushModel(ent, ent->model);
  214. G_SpawnInt("delay", "0", &ent->delay);
  215. mRailTracks.push_back().Setup(ent);
  216. G_FreeEntity(ent);
  217. mRailSystemActive = true;
  218. }
  219. ////////////////////////////////////////////////////////////////////////////////////////
  220. // The Rail Lane
  221. //
  222. //
  223. //
  224. ////////////////////////////////////////////////////////////////////////////////////////
  225. class CRailLane
  226. {
  227. public:
  228. ////////////////////////////////////////////////////////////////////////////////////
  229. // From Entity Setup Spawn
  230. ////////////////////////////////////////////////////////////////////////////////////
  231. void Setup(gentity_t* ent)
  232. {
  233. mName = ent->targetname;
  234. mNameTrack = ent->target;
  235. mMins = ent->mins;
  236. mMaxs = ent->maxs;
  237. mStartTime = ent->delay + level.time;
  238. }
  239. hstring mName;
  240. hstring mNameTrack;
  241. CVec3 mMins;
  242. CVec3 mMaxs;
  243. int mStartTime;
  244. public:
  245. ////////////////////////////////////////////////////////////////////////////////////
  246. // Initialize
  247. //
  248. // This function scans through the list of tracks and hooks itself up with the
  249. // track
  250. ////////////////////////////////////////////////////////////////////////////////////
  251. void Initialize()
  252. {
  253. mTrack = 0;
  254. mMinCol = 0;
  255. mMaxCol = 0;
  256. // int dummy;
  257. for (int i=0; i<mRailTracks.size(); i++)
  258. {
  259. if (mRailTracks[i].mName==mNameTrack)
  260. {
  261. mTrack = &(mRailTracks[i]);
  262. mTrack->SnapVectorToGrid(mMins);
  263. mTrack->SnapVectorToGrid(mMaxs);
  264. mMinCol = (int)((mMins[mTrack->mWAxis] - mTrack->mMins[mTrack->mWAxis])/mTrack->mGridCellSize);
  265. mMaxCol = (int)((mMaxs[mTrack->mWAxis] - mTrack->mMins[mTrack->mWAxis] - (mTrack->mGridCellSize/2.0f))/mTrack->mGridCellSize);
  266. //if (mTrack->mNegative)
  267. //{
  268. // mMinCol = (mTrack->mCols - mMinCol - 1);
  269. // mMaxCol = (mTrack->mCols - mMaxCol - 1);
  270. //}
  271. // mTrack->mCells.get_cell_coords(mMins[mTrack->mWAxis], 0, mMinCol, dummy);
  272. // mTrack->mCells.get_cell_coords((mMaxs[mTrack->mWAxis]-10.0f), 0, mMaxCol, dummy);
  273. break;
  274. }
  275. }
  276. assert(mTrack!=0);
  277. }
  278. CRailTrack* mTrack;
  279. int mMinCol;
  280. int mMaxCol;
  281. };
  282. ratl::vector_vs<CRailLane, MAX_LANES> mRailLanes;
  283. ////////////////////////////////////////////////////////////////////////////////////////
  284. /*QUAKED rail_lane (0 .5 .8) ? x x x x x x x x
  285. Use rail lanes to split up tracks. Just target it to a track that you want to break up into pieces
  286. "delay" How long the ent will wait from the start of the level before placing movers
  287. */
  288. ////////////////////////////////////////////////////////////////////////////////////////
  289. void SP_rail_lane(gentity_t *ent)
  290. {
  291. gi.SetBrushModel(ent, ent->model);
  292. G_SpawnInt("delay", "0", &ent->delay);
  293. mRailLanes.push_back().Setup(ent);
  294. G_FreeEntity(ent);
  295. }
  296. ////////////////////////////////////////////////////////////////////////////////////////
  297. //
  298. ////////////////////////////////////////////////////////////////////////////////////////
  299. class CRailMover
  300. {
  301. public:
  302. ////////////////////////////////////////////////////////////////////////////////////
  303. // From Entity Setup Spawn
  304. ////////////////////////////////////////////////////////////////////////////////////
  305. void Setup(gentity_t* ent)
  306. {
  307. mEnt = ent;
  308. mCenter = (ent->spawnflags&1);
  309. mSoundPlayed = false;
  310. mOriginOffset = ent->mins;
  311. mOriginOffset += ent->maxs;
  312. mOriginOffset *= 0.5f;
  313. mOriginOffset[2] = 0;//((ent->maxs[2] - ent->mins[2]) * 0.5);
  314. ent->e_ReachedFunc = reachedF_NULL;
  315. ent->moverState = MOVER_POS1;
  316. ent->svFlags = SVF_USE_CURRENT_ORIGIN;
  317. ent->s.eType = ET_MOVER;
  318. ent->s.eFlags |= EF_NODRAW;
  319. ent->contents = 0;
  320. ent->clipmask = 0;
  321. ent->s.pos.trType = TR_STATIONARY;
  322. ent->s.pos.trDuration = 0;
  323. ent->s.pos.trTime = 0;
  324. VectorCopy( ent->pos1, ent->currentOrigin );
  325. VectorCopy( ent->pos1, ent->s.pos.trBase );
  326. gi.linkentity(ent);
  327. }
  328. gentity_t* mEnt;
  329. bool mCenter;
  330. CVec3 mOriginOffset;
  331. bool mSoundPlayed;
  332. bool Active()
  333. {
  334. assert(mEnt!=0);
  335. return (level.time<(mEnt->s.pos.trDuration + mEnt->s.pos.trTime));
  336. }
  337. public:
  338. ////////////////////////////////////////////////////////////////////////////////////
  339. // Initialize
  340. //
  341. // This function scans through the list of tracks and hooks itself up with the
  342. // track (and possibly lane)
  343. ////////////////////////////////////////////////////////////////////////////////////
  344. void Initialize()
  345. {
  346. mTrack = 0;
  347. mLane = 0;
  348. mCols = 0;
  349. mRows = 0;
  350. hstring target = mEnt->target;
  351. for (int track=0; track<mRailTracks.size(); track++)
  352. {
  353. if (mRailTracks[track].mName==target)
  354. {
  355. mTrack = &(mRailTracks[track]);
  356. break;
  357. }
  358. }
  359. if (mTrack==0)
  360. {
  361. for (int lane=0; lane<mRailLanes.size(); lane++)
  362. {
  363. if (mRailLanes[lane].mName==target)
  364. {
  365. mLane = &(mRailLanes[lane]);
  366. mTrack = mLane->mTrack;
  367. break;
  368. }
  369. }
  370. }
  371. assert(mTrack!=0);
  372. if (mTrack)
  373. {
  374. mTrack->mMovers.push_back(this);
  375. mCols = (int)((mEnt->maxs[mTrack->mWAxis] - mEnt->mins[mTrack->mWAxis]) / mTrack->mGridCellSize) + 1;
  376. mRows = (int)((mEnt->maxs[mTrack->mHAxis] - mEnt->mins[mTrack->mHAxis]) / mTrack->mGridCellSize) + 1;
  377. // Make Sure The Mover Fits In The Track And Lane
  378. //------------------------------------------------
  379. if (mRows>mTrack->mRows)
  380. {
  381. // assert(0);
  382. mRows = mTrack->mRows;
  383. }
  384. if (mCols>mTrack->mCols)
  385. {
  386. // assert(0);
  387. mCols = mTrack->mCols;
  388. }
  389. if (mLane && mCols>(mLane->mMaxCol - mLane->mMinCol + 1))
  390. {
  391. // assert(0);
  392. mCols = (mLane->mMaxCol - mLane->mMinCol + 1);
  393. }
  394. }
  395. }
  396. CRailTrack* mTrack;
  397. CRailLane* mLane;
  398. int mCols;
  399. int mRows;
  400. };
  401. ratl::vector_vs<CRailMover, MAX_MOVERS> mRailMovers;
  402. ////////////////////////////////////////////////////////////////////////////////////////
  403. /*QUAKED rail_mover (0 .5 .8) ? CENTER x x x x x x x
  404. Rail Mover will go along the track and lane of your choice. Just target it to either a track or a lane. Don't bother with any origin brushes.
  405. CENTER Will force this mover to attempt to center in the track or lane
  406. "target" The track or lane you want this entity to move through
  407. "model" A model you wish to use, not necessary - can be just a brush
  408. "angle" Random angle rotation allowable on this thing
  409. */
  410. ////////////////////////////////////////////////////////////////////////////////////////
  411. void SP_rail_mover(gentity_t *ent)
  412. {
  413. gi.SetBrushModel(ent, ent->model);
  414. mRailMovers.push_back().Setup(ent);
  415. }
  416. ratl::vector_vs<int, 20> mWooshSml; // Small Building
  417. ratl::vector_vs<int, 20> mWooshMed; // Medium Building
  418. ratl::vector_vs<int, 10> mWooshLar; // Large Building
  419. ratl::vector_vs<int, 10> mWooshSup; // Track Support
  420. ratl::vector_vs<int, 3> mWooshTun; // Tunnel
  421. ////////////////////////////////////////////////////////////////////////////////////////
  422. //
  423. ////////////////////////////////////////////////////////////////////////////////////////
  424. void Rail_Reset()
  425. {
  426. mRailSystemActive = false;
  427. mRailTracks.clear();
  428. mRailLanes.clear();
  429. mRailMovers.clear();
  430. mWooshSml.clear();
  431. mWooshMed.clear();
  432. mWooshLar.clear();
  433. mWooshSup.clear();
  434. mWooshTun.clear();
  435. }
  436. ////////////////////////////////////////////////////////////////////////////////////////
  437. //
  438. ////////////////////////////////////////////////////////////////////////////////////////
  439. void Rail_Initialize()
  440. {
  441. for (int lane=0; lane<mRailLanes.size(); lane++)
  442. {
  443. mRailLanes[lane].Initialize();
  444. }
  445. for (int mover=0; mover<mRailMovers.size(); mover++)
  446. {
  447. mRailMovers[mover].Initialize();
  448. }
  449. // Precache All The Woosh Sounds
  450. //-------------------------------
  451. if (!mRailMovers.empty())
  452. {
  453. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh1"));
  454. mWooshSml.push_back(G_SoundIndex("sound/effects/woosh2"));
  455. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh3"));
  456. mWooshSml.push_back(G_SoundIndex("sound/effects/woosh4"));
  457. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh5"));
  458. mWooshSml.push_back(G_SoundIndex("sound/effects/woosh6"));
  459. mWooshSup.push_back(G_SoundIndex("sound/effects/woosh7"));
  460. mWooshSup.push_back(G_SoundIndex("sound/effects/woosh8"));
  461. mWooshSup.push_back(G_SoundIndex("sound/effects/woosh9"));
  462. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh10"));
  463. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh11"));
  464. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh12"));
  465. mWooshSml.push_back(G_SoundIndex("sound/effects/woosh13"));
  466. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh14"));
  467. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh15"));
  468. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh16"));
  469. mWooshSml.push_back(G_SoundIndex("sound/effects/woosh17"));
  470. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh18"));
  471. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh19"));
  472. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh20"));
  473. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh21"));
  474. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh22"));
  475. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh23"));
  476. mWooshSup.push_back(G_SoundIndex("sound/effects/woosh24"));
  477. mWooshSup.push_back(G_SoundIndex("sound/effects/woosh25"));
  478. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh26"));
  479. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh27"));
  480. mWooshMed.push_back(G_SoundIndex("sound/effects/woosh28"));
  481. mWooshLar.push_back(G_SoundIndex("sound/effects/woosh29"));
  482. mWooshTun.push_back(G_SoundIndex("sound/effects/whoosh_tunnel"));
  483. }
  484. }
  485. ////////////////////////////////////////////////////////////////////////////////////////
  486. //
  487. ////////////////////////////////////////////////////////////////////////////////////////
  488. void Rail_Update()
  489. {
  490. if (mRailSystemActive)// && false)
  491. {
  492. for (int track=0; track<mRailTracks.size(); track++)
  493. {
  494. if (level.time>mRailTracks[track].mNextUpdateTime && !mRailTracks[track].mMovers.empty())
  495. {
  496. mRailTracks[track].Update();
  497. }
  498. }
  499. // Is The Player Outside?
  500. //------------------------
  501. if (player && gi.WE_IsOutside(player->currentOrigin))
  502. {
  503. int wooshSound;
  504. vec3_t wooshSoundPos;
  505. vec3_t moverOrigin;
  506. vec3_t playerToMover;
  507. float playerToMoverDistance;
  508. float playerToMoverDistanceFraction;
  509. // Iterate Over All The Movers
  510. //-----------------------------
  511. for (int moverIndex=0; moverIndex<mRailMovers.size(); moverIndex++)
  512. {
  513. CRailMover& mover = mRailMovers[moverIndex];
  514. // Is It Active, And Has The Sound Already Played On It?
  515. //--------------------------------------------------------
  516. if (mover.Active() && !mover.mSoundPlayed)
  517. {
  518. VectorAdd(mover.mEnt->currentOrigin, mover.mOriginOffset.v, moverOrigin);
  519. VectorSubtract(moverOrigin, player->currentOrigin, playerToMover);
  520. playerToMover[2] = 0.0f;
  521. playerToMoverDistance = VectorNormalize(playerToMover);
  522. // Is It Close Enough?
  523. //---------------------
  524. if ((( mover.mLane || !mover.mCenter) && // Not Center Track
  525. (playerToMoverDistance<WOOSH_ALL_RANGE) && // And Close Enough
  526. (DotProduct(playerToMover, mover.mTrack->mDirection.v)>-0.45f)) // And On The Side
  527. || //OR
  528. ((!mover.mLane && mover.mCenter) && // Is Center Track
  529. (playerToMoverDistance<WOOSH_SUPPORT_RANGE || // And Close Enough for Support
  530. (playerToMoverDistance<WOOSH_TUNNEL_RANGE && mover.mRows>10)) // Or Close Enough For Tunnel
  531. ))
  532. {
  533. mover.mSoundPlayed = true;
  534. wooshSound = 0;
  535. // The Centered Entities Play Right On The Player's Head For Full Volume
  536. //-----------------------------------------------------------------------
  537. if (mover.mCenter && !mover.mLane)
  538. {
  539. VectorCopy(player->currentOrigin, wooshSoundPos);
  540. wooshSoundPos[2] += 50;
  541. // If It Is Very Long, Play The Tunnel Sound
  542. //-------------------------------------------
  543. if (mover.mRows>10)
  544. {
  545. wooshSound = mWooshTun[Q_irand(0, mWooshTun.size()-1)];
  546. }
  547. // Otherwise It Is A Support
  548. //---------------------------
  549. else
  550. {
  551. wooshSound = mWooshSup[Q_irand(0, mWooshSup.size()-1)];
  552. }
  553. }
  554. // All Other Entities Play At A Fraction Of Their Normal Range
  555. //-------------------------------------------------------------
  556. else
  557. {
  558. // Scale The Play Pos By The Square Of The Distance
  559. //--------------------------------------------------
  560. playerToMoverDistanceFraction = playerToMoverDistance/WOOSH_ALL_RANGE;
  561. playerToMoverDistanceFraction *= playerToMoverDistanceFraction;
  562. playerToMoverDistanceFraction *= 0.6f;
  563. playerToMoverDistance *= playerToMoverDistanceFraction;
  564. VectorMA(player->currentOrigin, playerToMoverDistance, playerToMover, wooshSoundPos);
  565. // Large Building
  566. //----------------
  567. if (mover.mRows>4)
  568. {
  569. wooshSound = mWooshLar[Q_irand(0, mWooshLar.size()-1)];
  570. }
  571. // Medium Building
  572. //-----------------
  573. else if (mover.mRows>2)
  574. {
  575. wooshSound = mWooshMed[Q_irand(0, mWooshMed.size()-1)];
  576. }
  577. // Small Building
  578. //----------------
  579. else
  580. {
  581. wooshSound = mWooshSml[Q_irand(0, mWooshSml.size()-1)];
  582. }
  583. }
  584. // If A Woosh Sound Was Selected, Play It Now
  585. //--------------------------------------------
  586. if (wooshSound)
  587. {
  588. G_SoundAtSpot(wooshSoundPos, wooshSound, qfalse);
  589. if (WOOSH_DEBUG)
  590. {
  591. CG_DrawEdge(player->currentOrigin, wooshSoundPos, EDGE_WHITE_TWOSECOND);
  592. }
  593. }
  594. }
  595. }
  596. }
  597. }
  598. }
  599. }
  600. ////////////////////////////////////////////////////////////////////////////////////////
  601. //
  602. ////////////////////////////////////////////////////////////////////////////////////////
  603. void Rail_LockCenterOfTrack(const char* trackName)
  604. {
  605. hstring name = trackName;
  606. for (int track=0; track<mRailTracks.size(); track++)
  607. {
  608. if (mRailTracks[track].mName==name)
  609. {
  610. mRailTracks[track].mCenterLocked = true;
  611. return;
  612. }
  613. }
  614. assert(0);
  615. }
  616. ////////////////////////////////////////////////////////////////////////////////////////
  617. //
  618. ////////////////////////////////////////////////////////////////////////////////////////
  619. void Rail_UnLockCenterOfTrack(const char* trackName)
  620. {
  621. hstring name = trackName;
  622. for (int track=0; track<mRailTracks.size(); track++)
  623. {
  624. if (mRailTracks[track].mName==name)
  625. {
  626. mRailTracks[track].mCenterLocked = false;
  627. return;
  628. }
  629. }
  630. assert(0);
  631. }
  632. ////////////////////////////////////////////////////////////////////////////////////////
  633. //
  634. ////////////////////////////////////////////////////////////////////////////////////////
  635. void CRailTrack::Update()
  636. {
  637. mNextUpdateTime = level.time + mNextUpdateDelay;
  638. // Now, Attempt To Add A Number Of Movers To The Track
  639. //-----------------------------------------------------
  640. int attempt;
  641. int startCol;
  642. int stopCol;
  643. int atCol;
  644. int testColIndex;
  645. for (attempt=0; attempt<mNumMoversPerRow; attempt++)
  646. {
  647. // Randomly Select A Mover And Test To See If It Is Active
  648. //---------------------------------------------------------
  649. CRailMover* mover = mMovers[Q_irand(0, mMovers.size()-1)];
  650. if (mover->Active())
  651. {
  652. continue;
  653. }
  654. // Don't Spawn Until Start Time Has Expired
  655. //------------------------------------------
  656. if (level.time < ((mover->mLane)?(mover->mLane->mStartTime):(mStartTime)))
  657. {
  658. continue;
  659. }
  660. // If Center Locked, Stop Spawning Center Track Movers
  661. //-----------------------------------------------------
  662. if (mover->mCenter && mCenterLocked)
  663. {
  664. continue;
  665. }
  666. // Restrict It To A Lane
  667. //-----------------------
  668. if (mover->mLane)
  669. {
  670. startCol = mover->mLane->mMinCol;
  671. stopCol = mover->mLane->mMaxCol+1;
  672. }
  673. // Or Let It Go Anywhere On The Track
  674. //------------------------------------
  675. else
  676. {
  677. startCol = 0;
  678. stopCol = mCols;
  679. }
  680. stopCol -= (mover->mCols-1);
  681. // If The Mover Is Too Big To Fit In The Lane, Go On To Next Attempt
  682. //-------------------------------------------------------------------
  683. if (stopCol<=startCol)
  684. {
  685. assert(0); // Should Not Happen
  686. continue;
  687. }
  688. // Force It To Center
  689. //--------------------
  690. if (mover->mCenter && stopCol!=(startCol+1))
  691. {
  692. startCol = ((mCols/2) - (mover->mCols/2));
  693. stopCol = startCol+1;
  694. }
  695. // Construct A List Of Columns To Test For Insertion
  696. //---------------------------------------------------
  697. mTestCols.clear();
  698. for (int i=startCol; i<stopCol; i++)
  699. {
  700. mTestCols.push_back(i);
  701. }
  702. // Now Try All The Cols To See If The Building Can Fit
  703. //-----------------------------------------------------
  704. while (!mTestCols.empty())
  705. {
  706. // Randomly Pick A Column, Then Remove It From The Vector
  707. //--------------------------------------------------------
  708. testColIndex = Q_irand(0, mTestCols.size()-1);
  709. atCol = mTestCols[testColIndex];
  710. mTestCols.erase_swap(testColIndex);
  711. if (TestMoverInCells(mover, atCol))
  712. {
  713. // Ok, We've Found A Safe Column To Insert This Mover
  714. //----------------------------------------------------
  715. InsertMoverInCells(mover, atCol);
  716. // Now Transport The Actual Mover Entity Into Position, Link It & Send It Off
  717. //----------------------------------------------------------------------------
  718. CVec3 StartPos(mGridBottomLeftCorner);
  719. StartPos[mWAxis] += ((atCol * mGridCellSize) + ((mover->mCols/2.0f) * mGridCellSize));
  720. StartPos[mHAxis] += (((mover->mRows/2.0f) * mGridCellSize) * ((mNegative)?(1):(-1)));
  721. StartPos[2] = 0;
  722. // If Centered, Actually Put It At EXACTLY The Right Position On The Width Axis
  723. //------------------------------------------------------------------------------
  724. if (mover->mCenter)
  725. {
  726. StartPos[mWAxis] = mGridCenter[mWAxis];
  727. float deltaOffset = mGridCenter[mWAxis] - mover->mOriginOffset[mWAxis];
  728. if (deltaOffset<(mGridCellSize*0.5f) )
  729. {
  730. StartPos[mWAxis] -= deltaOffset;
  731. }
  732. }
  733. StartPos -= mover->mOriginOffset;
  734. G_SetOrigin(mover->mEnt, StartPos.v);
  735. // Start It Moving
  736. //-----------------
  737. VectorCopy(StartPos.v, mover->mEnt->s.pos.trBase);
  738. VectorCopy(mVelocity.v, mover->mEnt->s.pos.trDelta);
  739. mover->mEnt->s.pos.trTime = level.time;
  740. mover->mEnt->s.pos.trDuration = mTravelTimeMilliseconds + (mNextUpdateDelay*mover->mRows);
  741. mover->mEnt->s.pos.trType = TR_LINEAR_STOP;
  742. mover->mEnt->s.eFlags &= ~EF_NODRAW;
  743. mover->mSoundPlayed = false;
  744. // Successfully Inserted This Mover. Now Move On To The Next Mover
  745. //------------------------------------------------------------------
  746. break;
  747. }
  748. }
  749. }
  750. // Incriment The Current Row
  751. //---------------------------
  752. mRow++;
  753. if (mRow>=mRows)
  754. {
  755. mRow = 0;
  756. }
  757. // Erase The Erase Row
  758. //---------------------
  759. int EraseRow = mRow - MAX_ROW_HISTORY;
  760. if (EraseRow<0)
  761. {
  762. EraseRow += mRows;
  763. }
  764. for (int col=0; col<mCols; col++)
  765. {
  766. mCells.get(col, EraseRow) = 0;
  767. }
  768. }
  769. ////////////////////////////////////////////////////////////////////////////////////////
  770. //
  771. ////////////////////////////////////////////////////////////////////////////////////////
  772. void CRailTrack::RandomizeTestCols(int startCol, int stopCol)
  773. {
  774. int numCols = (stopCol - startCol);
  775. int swapA;
  776. int swapB;
  777. for (int swapNum=0; swapNum<numCols; swapNum++)
  778. {
  779. swapA = Q_irand(0, numCols-1);
  780. swapB = Q_irand(0, numCols-1);
  781. if (swapA!=swapB)
  782. {
  783. mTestCols.swap(swapA, swapB);
  784. }
  785. }
  786. }
  787. ////////////////////////////////////////////////////////////////////////////////////////
  788. //
  789. ////////////////////////////////////////////////////////////////////////////////////////
  790. bool CRailTrack::TestMoverInCells(CRailMover* mover, int atCol)
  791. {
  792. //for (int moverRow=0; (moverRow<mover->mRows); moverRow++)
  793. //{
  794. for (int moverCol=0; (moverCol<mover->mCols); moverCol++)
  795. {
  796. if (mCells.get(atCol+moverCol, mRow/*+moverRow*/)!=0)
  797. {
  798. return false;
  799. }
  800. }
  801. //}
  802. return true;
  803. }
  804. ////////////////////////////////////////////////////////////////////////////////////////
  805. //
  806. ////////////////////////////////////////////////////////////////////////////////////////
  807. void CRailTrack::InsertMoverInCells(CRailMover* mover, int atCol)
  808. {
  809. for (int moverCol=0; (moverCol<mover->mCols); moverCol++)
  810. {
  811. int col = atCol+moverCol;
  812. for (int moverRow=0; (moverRow<mover->mRows); moverRow++)
  813. {
  814. int row = mRow+moverRow;
  815. if (row>=mRows)
  816. {
  817. row -= mRows;
  818. }
  819. assert(mCells.get(col, row)==0);
  820. mCells.get(col, row) = mover;
  821. }
  822. }
  823. }