worldmanager.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. #include "../idlib/precompiled.h"
  2. #pragma hdrstop
  3. #include "Game_local.h"
  4. #define RECORDRATE 300 //record every X ms
  5. #define RECORD_LAUNCHAIM 1
  6. #define RECORD_UNSPAWN 2
  7. #define RECORD_SPAWN 3
  8. const idEventDef EV_recordclear( "recordclear", "d" );
  9. const idEventDef EV_recordstart( "recordstart", "dd" );
  10. const idEventDef EV_recordstop( "recordstop" );
  11. const idEventDef EV_recordplay( "recordplay", "d" );
  12. const idEventDef EV_geteventcount( "geteventcount", "d", 'd' );
  13. const idEventDef EV_getlasteventtimestamp( "getlasteventtimestamp", "d", 'd' );
  14. const idEventDef EV_setrecordstarttime( "setrecordstarttime" );
  15. const idEventDef EV_moveplayertoghost( "moveplayertoghost", "d" );
  16. const idEventDef EV_setcomplete( "setcomplete", "dd" );
  17. const idEventDef EV_getcomplete( "getcomplete", "d", 'd' );
  18. const idEventDef EV_recordspawn( "recordspawn", "sdvf" );
  19. const idEventDef EV_recordunspawn( "recordunspawn", "d" );
  20. const idEventDef EV_recordlaunchaim( "recordlaunchaim", "dvf" );
  21. const idEventDef EV_reset( "worldreset" );
  22. CLASS_DECLARATION( idEntity, idWorldManager )
  23. EVENT( EV_recordstart, idWorldManager::Event_recordstart)
  24. EVENT( EV_recordstop, idWorldManager::Event_recordstop)
  25. EVENT( EV_recordplay, idWorldManager::Event_recordplay)
  26. EVENT( EV_reset, idWorldManager::Event_reset)
  27. EVENT( EV_geteventcount, idWorldManager::Event_geteventcount)
  28. EVENT( EV_getlasteventtimestamp, idWorldManager::Event_getlasteventtimestamp)
  29. EVENT( EV_setrecordstarttime, idWorldManager::Event_setrecordstarttime)
  30. EVENT( EV_moveplayertoghost, idWorldManager::Event_moveplayertoghost)
  31. EVENT( EV_recordclear, idWorldManager::Event_recordclear)
  32. EVENT( EV_recordspawn, idWorldManager::RecordSpawn)
  33. EVENT( EV_recordunspawn, idWorldManager::RecordUnspawn)
  34. EVENT( EV_recordlaunchaim, idWorldManager::RecordLaunchAim)
  35. EVENT( EV_setcomplete, idWorldManager::Event_setcomplete)
  36. EVENT( EV_getcomplete, idWorldManager::Event_getcomplete)
  37. END_CLASS
  38. void idWorldManager::Save( idSaveGame *savefile ) const
  39. {
  40. savefile->WriteInt(index);
  41. savefile->WriteInt(state);
  42. savefile->WriteInt(recordStarttime);
  43. savefile->WriteInt(nextRecordtime);
  44. savefile->WriteVec3(lastPosition);
  45. savefile->WriteFloat(lastAngle);
  46. //RECORDS.
  47. for (int i = 0; i < 3; i++)
  48. {
  49. savefile->WriteObject(records[i].ghost);
  50. savefile->WriteInt(records[i].index);
  51. savefile->WriteBool(records[i].playing);
  52. savefile->WriteBool(records[i].completed);
  53. int totalEvents = records[i].events.Num();
  54. savefile->WriteInt(totalEvents); //how many events.
  55. for (int k = 0; k < totalEvents; k++)
  56. {
  57. savefile->WriteInt(records[i].events[k].timestamp);
  58. savefile->WriteVec3(records[i].events[k].position);
  59. savefile->WriteFloat(records[i].events[k].yaw);
  60. savefile->WriteString(records[i].events[k].deckcommand.c_str());
  61. savefile->WriteString(records[i].events[k].frobcommand.c_str());
  62. savefile->WriteString(records[i].events[k].spawncommand.c_str());
  63. savefile->WriteBool(records[i].events[k].done);
  64. savefile->WriteInt(records[i].events[k].entID);
  65. savefile->WriteInt(records[i].events[k].recordtype);
  66. }
  67. }
  68. //RECORDLINES
  69. for (int i = 0; i < 3; i++)
  70. {
  71. int totalLines = recordlines[i].lines.Num();
  72. savefile->WriteInt(totalLines);
  73. for (int k = 0; k < totalLines; k++)
  74. {
  75. savefile->WriteVec3(recordlines[i].lines[k].position1);
  76. savefile->WriteVec3(recordlines[i].lines[k].position2);
  77. }
  78. }
  79. }
  80. void idWorldManager::Restore( idRestoreGame *savefile )
  81. {
  82. savefile->ReadInt(index);
  83. savefile->ReadInt(state);
  84. savefile->ReadInt(recordStarttime);
  85. savefile->ReadInt(nextRecordtime);
  86. savefile->ReadVec3(lastPosition);
  87. savefile->ReadFloat(lastAngle);
  88. //RECORDS.
  89. for (int i = 0; i < 3; i++)
  90. {
  91. savefile->ReadObject(reinterpret_cast<idClass *&>( records[i].ghost ) );
  92. savefile->ReadInt(records[i].index);
  93. savefile->ReadBool(records[i].playing);
  94. savefile->ReadBool(records[i].completed);
  95. int totalEvents;
  96. savefile->ReadInt(totalEvents);
  97. for (int k = 0; k < totalEvents; k++)
  98. {
  99. record_t newEvent;
  100. savefile->ReadInt(newEvent.timestamp);
  101. savefile->ReadVec3(newEvent.position);
  102. savefile->ReadFloat(newEvent.yaw);
  103. savefile->ReadString(newEvent.deckcommand);
  104. savefile->ReadString(newEvent.frobcommand);
  105. savefile->ReadString(newEvent.spawncommand);
  106. savefile->ReadBool(newEvent.done);
  107. savefile->ReadInt(newEvent.entID);
  108. savefile->ReadInt(newEvent.recordtype);
  109. records[i].events.Append(newEvent);
  110. }
  111. }
  112. //RECORDLINES
  113. for (int i = 0; i < 3; i++)
  114. {
  115. recordlines[i].lines.Clear();
  116. int totalLines;
  117. savefile->ReadInt(totalLines);
  118. for (int k = 0; k < totalLines; k++)
  119. {
  120. recordline_t newLine;
  121. savefile->ReadVec3(newLine.position1);
  122. savefile->ReadVec3(newLine.position2);
  123. recordlines[i].lines.Append(newLine);
  124. }
  125. }
  126. }
  127. void idWorldManager::Spawn( void )
  128. {
  129. int i;
  130. for (i = 0; i < 3; i++)
  131. {
  132. idDict args;
  133. records[i].index = 0;
  134. records[i].playing = false;
  135. records[i].completed = false;
  136. args.Clear();
  137. args.Set( "model", "models/monster_npc/tris.ase" );
  138. args.SetInt( "solid", 0 );
  139. args.Set("skin", "skins/npc/ghost2");
  140. records[i].ghost = ( idMover * )gameLocal.SpawnEntityType( idMover::Type, &args );
  141. records[i].ghost->Hide();
  142. recordlines[i].lines.Clear();
  143. }
  144. lastPosition = vec3_zero;
  145. lastAngle = 0;
  146. nextRecordtime = 0;
  147. recordStarttime = 0;
  148. index = 0;
  149. state = OFF;
  150. BecomeActive( TH_THINK );
  151. }
  152. void idWorldManager::Event_getcomplete(int idx)
  153. {
  154. idThread::ReturnInt(records[idx].completed);
  155. }
  156. void idWorldManager::Event_setcomplete(int idx, bool value)
  157. {
  158. records[idx].completed = value;
  159. }
  160. void idWorldManager::Event_moveplayertoghost(int idx)
  161. {
  162. //common->Printf("ghost %f %f %f\n", records[idx].ghost->GetPhysics()->GetOrigin().x, records[idx].ghost->GetPhysics()->GetOrigin().y, records[idx].ghost->GetPhysics()->GetOrigin().z);
  163. gameLocal.GetLocalPlayer()->SetOrigin( records[idx].ghost->GetPhysics()->GetOrigin() + idVec3(0,0,0) );
  164. }
  165. void idWorldManager::Event_recordclear(int idx)
  166. {
  167. if (idx < 0)
  168. {
  169. return;
  170. }
  171. //erase all events.
  172. records[idx].events.Clear();
  173. }
  174. void idWorldManager::Event_setrecordstarttime()
  175. {
  176. recordStarttime = gameLocal.time;
  177. }
  178. void idWorldManager::Event_getlasteventtimestamp(int idx)
  179. {
  180. int indexOfLastEvent = records[idx].events.Num();
  181. if (indexOfLastEvent <= 0)
  182. {
  183. idThread::ReturnInt(0);
  184. return;
  185. }
  186. int time = records[idx].events[indexOfLastEvent - 1].timestamp;
  187. time += gameLocal.time;
  188. idThread::ReturnFloat(time / 1000.0f);
  189. }
  190. void idWorldManager::Event_geteventcount(int idx)
  191. {
  192. idThread::ReturnInt( records[idx].events.Num() );
  193. }
  194. void idWorldManager::Event_reset(void)
  195. {
  196. int i;
  197. for ( i = 0; i < gameLocal.num_entities; i++ )
  198. {
  199. if ( !gameLocal.entities[ i ] )
  200. continue;
  201. if (gameLocal.entities[i]->IsType(idMoveableItem::Type))
  202. {
  203. gameLocal.entities[i]->GetPhysics()->PutToRest();
  204. gameLocal.entities[i]->SetOrigin(static_cast<idMoveableItem *>( gameLocal.entities[i] )->originalPosition);
  205. gameLocal.entities[i]->SetAxis(static_cast<idMoveableItem *>( gameLocal.entities[i] )->originalAngle);
  206. if (static_cast<idMoveableItem *>( gameLocal.entities[i] )->frozen == 2)
  207. {
  208. static_cast<idMoveableItem *>( gameLocal.entities[i] )->frozen = 1;
  209. }
  210. }
  211. else if (gameLocal.entities[i]->IsType(idLever::Type))
  212. {
  213. static_cast<idLever *>( gameLocal.entities[i] )->Reset();
  214. }
  215. else if (gameLocal.entities[i]->IsType(idMoveable::Type))
  216. {
  217. gameLocal.entities[i]->GetPhysics()->PutToRest();
  218. gameLocal.entities[i]->SetOrigin(static_cast<idMoveable *>( gameLocal.entities[i] )->originalPosition);
  219. gameLocal.entities[i]->SetAxis(static_cast<idMoveable *>( gameLocal.entities[i] )->originalAngle);
  220. gameLocal.entities[i]->GetPhysics()->PutToRest();
  221. }
  222. else if (gameLocal.entities[i]->IsType(idMover::Type))
  223. {
  224. //gameLocal.entities[i]->GetPhysics()->PutToRest();
  225. if (gameLocal.entities[i]->spawnArgs.GetInt("resetmover", "0") <= 0)
  226. {
  227. continue;
  228. }
  229. static_cast<idMover *>( gameLocal.entities[i] )->Event_StopMoving();
  230. static_cast<idMover *>( gameLocal.entities[i] )->Event_StopRotating();
  231. if ( gameLocal.entities[i]->GetBindMaster() == NULL )
  232. {
  233. gameLocal.entities[i]->SetOrigin( static_cast<idMover *>(gameLocal.entities[i] )->originalPosition );
  234. }
  235. else
  236. {
  237. if (gameLocal.entities[i]->GetBindMaster()->IsType(idMover::Type))
  238. {
  239. idVec3 masterPos = GetLocalCoordinates( static_cast<idMover *>(gameLocal.entities[i]->GetBindMaster())->originalPosition );
  240. gameLocal.entities[i]->SetOrigin( static_cast<idMover *>(gameLocal.entities[i] )->originalPosition - masterPos);
  241. }
  242. else
  243. {
  244. idVec3 orgPos = GetLocalCoordinates( static_cast<idMover *>(gameLocal.entities[i])->originalPosition );
  245. gameLocal.entities[i]->SetOrigin( orgPos );
  246. }
  247. }
  248. gameLocal.entities[i]->SetAxis(static_cast<idMover *>( gameLocal.entities[i] )->originalAngle);
  249. }
  250. else if (gameLocal.entities[i]->IsType(idTrembler::Type))
  251. {
  252. static_cast<idTrembler *>( gameLocal.entities[i] )->Reset();
  253. }
  254. }
  255. //popcorn reset.
  256. gameLocal.GetLocalPlayer()->popcornPosition = vec3_zero;
  257. }
  258. void idWorldManager::Event_recordstart( int idx, int continuation )
  259. {
  260. lastPosition = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin();
  261. if (!continuation)
  262. {
  263. recordStarttime = gameLocal.time;
  264. //reset the record lines.
  265. if (idx >= 0)
  266. {
  267. recordlines[idx].lines.Clear();
  268. }
  269. }
  270. this->index = idx;
  271. if (idx >= 0)
  272. {
  273. state = RECORDING;
  274. records[index].ghost->Hide();
  275. if (!continuation)
  276. {
  277. records[index].events.Clear();
  278. }
  279. }
  280. //worldmanager_moveable
  281. int i;
  282. for ( i = 0; i < gameLocal.num_entities; i++ )
  283. {
  284. if ( !gameLocal.entities[ i ] )
  285. continue;
  286. if (!gameLocal.entities[i]->IsType(idWorldManager_Moveable::Type))
  287. continue;
  288. int role = gameLocal.entities[i]->spawnArgs.GetInt("role", "-1");
  289. if (role != index)
  290. continue;
  291. static_cast<idWorldManager_Moveable *>( gameLocal.entities[i])->Event_startrecord( continuation );
  292. }
  293. }
  294. void idWorldManager::Event_recordstop( void )
  295. {
  296. int i;
  297. state = OFF;
  298. this->index = 0;
  299. for ( i = 0; i < gameLocal.num_entities; i++ )
  300. {
  301. if ( !gameLocal.entities[ i ] )
  302. continue;
  303. if (!gameLocal.entities[i]->IsType(idWorldManager_Moveable::Type))
  304. continue;
  305. static_cast<idWorldManager_Moveable *>( gameLocal.entities[i])->Event_stop();
  306. }
  307. }
  308. void idWorldManager::Event_recordplay( int idx )
  309. {
  310. int i;
  311. if (records[idx].events.Num() <= 0)
  312. {
  313. return;
  314. }
  315. records[idx].index = 0;
  316. records[idx].playing = true;
  317. records[idx].ghost->Show();
  318. records[idx].ghost->SetSkin(declManager->FindSkin( this->spawnArgs.GetString(va("skin%d", idx), "skins/npc/ghost2") ));
  319. //flag every event as NOT DONE.
  320. for (i = 0; i < records[idx].events.Num(); i++)
  321. {
  322. records[idx].events[i].done = false;
  323. }
  324. //the colored line that the operative poops out.
  325. if (index == -1)
  326. {
  327. recordline_t newLine;
  328. newLine.position1 = records[idx].events[0].position;
  329. newLine.position2 = records[idx].events[0].position;
  330. recordlines[idx].lines.Append(newLine);
  331. }
  332. for ( i = 0; i < gameLocal.num_entities; i++ )
  333. {
  334. if ( !gameLocal.entities[ i ] )
  335. continue;
  336. if (!gameLocal.entities[i]->IsType(idWorldManager_Moveable::Type))
  337. continue;
  338. int role = gameLocal.entities[i]->spawnArgs.GetInt("role", "-1");
  339. if (role == index)
  340. continue;
  341. static_cast<idWorldManager_Moveable *>( gameLocal.entities[i])->Event_startplay();
  342. }
  343. }
  344. void idWorldManager::RecordDeck( const char *deckString )
  345. {
  346. if (state == OFF)
  347. {
  348. return;
  349. }
  350. record_t newEvent;
  351. newEvent.timestamp = gameLocal.time - recordStarttime;
  352. newEvent.deckcommand = deckString;
  353. records[index].events.Append( newEvent );
  354. }
  355. void idWorldManager::RecordFrob( const char *entName )
  356. {
  357. if (state == OFF)
  358. {
  359. return;
  360. }
  361. record_t newEvent;
  362. newEvent.timestamp = gameLocal.time - recordStarttime;
  363. newEvent.frobcommand = entName;
  364. records[index].events.Append( newEvent );
  365. }
  366. void idWorldManager::RecordUnspawn( int id )
  367. {
  368. if (state == OFF)
  369. {
  370. return;
  371. }
  372. record_t newEvent;
  373. newEvent.recordtype = RECORD_UNSPAWN;
  374. newEvent.timestamp = gameLocal.time - recordStarttime;
  375. newEvent.entID = id;
  376. records[index].events.Append( newEvent );
  377. }
  378. void idWorldManager::RecordSpawn( const char *defName, int id, const idVec3 &pos, float yaw )
  379. {
  380. if (state == OFF)
  381. {
  382. return;
  383. }
  384. record_t newEvent;
  385. newEvent.recordtype = RECORD_SPAWN;
  386. newEvent.timestamp = gameLocal.time - recordStarttime;
  387. newEvent.spawncommand = defName;
  388. newEvent.position = pos;
  389. newEvent.yaw = yaw;
  390. newEvent.entID = id;
  391. records[index].events.Append( newEvent );
  392. if (developer.GetBool())
  393. {
  394. common->Printf("worldmanager: recording entity spawn ID %d defname %s \n", id, defName);
  395. }
  396. }
  397. void idWorldManager::RecordLaunchAim( int id, const idVec3 &dir, float force )
  398. {
  399. if (state == OFF)
  400. {
  401. return;
  402. }
  403. if (id < 0)
  404. return;
  405. record_t newEvent;
  406. newEvent.timestamp = gameLocal.time - recordStarttime;
  407. newEvent.recordtype = RECORD_LAUNCHAIM;
  408. newEvent.entID = id; //id #
  409. newEvent.position = dir; //direction.
  410. newEvent.yaw = force; //force.
  411. records[index].events.Append( newEvent );
  412. if (developer.GetBool())
  413. {
  414. common->Printf("worldmanager: recording launcher aim ID %d \n", id);
  415. }
  416. }
  417. void idWorldManager::UpdatePlay( int idx )
  418. {
  419. int currentIndex = records[idx].index;
  420. if (currentIndex > records[idx].events.Num() - 1)
  421. {
  422. return;
  423. }
  424. if (records[idx].events[currentIndex].timestamp < gameLocal.time - recordStarttime)
  425. {
  426. if (!records[idx].events[currentIndex].frobcommand.IsEmpty() && !records[idx].events[currentIndex].done)
  427. {
  428. //FROB EVENT.
  429. idEntity *frobEnt;
  430. frobEnt = gameLocal.FindEntity( records[idx].events[currentIndex].frobcommand );
  431. if (frobEnt)
  432. {
  433. if (frobEnt->IsType(idTrigger_Multi::Type))
  434. {
  435. static_cast<idTrigger_Multi *>( frobEnt )->TriggerAction(NULL);
  436. }
  437. else
  438. {
  439. gameLocal.GetLocalPlayer()->DoFrob(frobEnt);
  440. //common->Printf("frobbing! %d\n", gameLocal.time);
  441. }
  442. }
  443. else
  444. {
  445. gameLocal.Warning("WorldManager couldn't find frob ent: %s\n", gameLocal.FindEntity( records[idx].events[currentIndex].frobcommand.c_str()));
  446. }
  447. records[idx].events[currentIndex].done = true;
  448. }
  449. else if (records[idx].events[currentIndex].recordtype == RECORD_LAUNCHAIM && !records[idx].events[currentIndex].done)
  450. {
  451. //event: change launcher aim.
  452. //find the launcher with this id.
  453. int i;
  454. int targetEnt = -1;
  455. for ( i = 0; i < gameLocal.num_entities; i++ )
  456. {
  457. if ( !gameLocal.entities[ i ] )
  458. continue;
  459. int kk = records[idx].events[currentIndex].entID;
  460. if (gameLocal.entities[i]->spawnArgs.GetInt("id") != records[idx].events[currentIndex].entID)
  461. {
  462. continue;
  463. }
  464. targetEnt = i;
  465. break;
  466. }
  467. if (developer.GetBool())
  468. {
  469. common->Printf("worldmanager: aiming launcher entity ID %d \n", records[idx].events[currentIndex].entID);
  470. }
  471. if (targetEnt >= 0)
  472. {
  473. //legacy.
  474. gameLocal.entities[targetEnt]->spawnArgs.SetVector("new_launchdir", records[idx].events[currentIndex].position);
  475. gameLocal.entities[targetEnt]->spawnArgs.SetInt("new_force", records[idx].events[currentIndex].yaw);
  476. gameLocal.entities[targetEnt]->spawnArgs.SetInt("new_update", 1);
  477. static_cast<idLauncher *>( gameLocal.entities[i] )->SetLaunchDir(records[idx].events[currentIndex].position, records[idx].events[currentIndex].yaw);
  478. }
  479. records[idx].events[currentIndex].done = true;
  480. }
  481. else if (!records[idx].events[currentIndex].deckcommand.IsEmpty() && !records[idx].events[currentIndex].done)
  482. {
  483. //DECK EVENT.
  484. gameLocal.RunDeckCommand(records[idx].events[currentIndex].deckcommand.c_str());
  485. records[idx].events[currentIndex].done = true;
  486. }
  487. else if (records[idx].events[currentIndex].recordtype == RECORD_UNSPAWN && !records[idx].events[currentIndex].done)
  488. {
  489. //UNSPAWN EVENT.
  490. //find the ent with this id.
  491. int i;
  492. int targetEnt = -1;
  493. for ( i = 0; i < gameLocal.num_entities; i++ )
  494. {
  495. if ( !gameLocal.entities[ i ] )
  496. continue;
  497. int kk = records[idx].events[currentIndex].entID;
  498. if (gameLocal.entities[i]->spawnArgs.GetInt("id") != records[idx].events[currentIndex].entID)
  499. {
  500. continue;
  501. }
  502. targetEnt = i;
  503. break;
  504. }
  505. if (targetEnt >= 0)
  506. {
  507. gameLocal.entities[targetEnt]->PostEventMS( &EV_Remove, 0 );
  508. //gameLocal.entities[targetEnt]->Event_CallFunction("onPick");
  509. }
  510. records[idx].events[currentIndex].done = true;
  511. }
  512. else if (records[idx].events[currentIndex].recordtype == RECORD_SPAWN && !records[idx].events[currentIndex].done)
  513. {
  514. //SPAWN EVENT.
  515. idEntity *ent;
  516. idDict args;
  517. idAngles ang;
  518. int id = gameLocal.time - recordStarttime;
  519. if (developer.GetBool())
  520. {
  521. common->Printf("worldmanager: spawning entity ID %d classname %s \n", records[idx].events[currentIndex].entID,
  522. records[idx].events[currentIndex].spawncommand.c_str());
  523. }
  524. args.Set( "classname", records[idx].events[currentIndex].spawncommand );
  525. args.SetVector( "origin", records[idx].events[currentIndex].position );
  526. args.SetInt( "id", records[idx].events[currentIndex].entID);
  527. bool bSpawn = gameLocal.SpawnEntityDef( args, &ent );
  528. if (ent)
  529. {
  530. ent->spawnArgs.SetInt("id", records[idx].events[currentIndex].entID); //BC 7-21-2016 was crashing here.
  531. ang.pitch = 0;
  532. ang.yaw = records[idx].events[currentIndex].yaw;
  533. ang.roll = 0;
  534. ent->SetAngles( ang );
  535. }
  536. if (developer.GetBool())
  537. {
  538. common->Printf("worldmanager: spawning success:%d\n", bSpawn);
  539. }
  540. records[idx].events[currentIndex].done = true;
  541. }
  542. else
  543. {
  544. //MOVE EVENT.
  545. float moveTime = (float)RECORDRATE / 1000;
  546. records[idx].ghost->Event_SetMoveTime(moveTime);
  547. records[idx].ghost->Event_MoveToPos(records[idx].events[currentIndex].position);
  548. idAngles newAng = idAngles(0, records[idx].events[currentIndex].yaw, 0);
  549. records[idx].ghost->SetAxis(newAng.ToMat3());
  550. if (index == -1)
  551. {
  552. int lastLineIndex = recordlines[idx].lines.Num() - 1;
  553. recordline_t newLine;
  554. newLine.position1 = recordlines[idx].lines[lastLineIndex].position2;
  555. newLine.position2 = records[idx].events[currentIndex].position;
  556. recordlines[idx].lines.Append(newLine);
  557. }
  558. records[idx].events[currentIndex].done = true;
  559. }
  560. records[idx].index++;
  561. }
  562. }
  563. void idWorldManager::UpdateRecord( void )
  564. {
  565. if (state == OFF)
  566. {
  567. return;
  568. }
  569. if (gameLocal.time < nextRecordtime)
  570. {
  571. return;
  572. }
  573. nextRecordtime = gameLocal.time + RECORDRATE;
  574. idVec3 currentPosition = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin();
  575. int currentAngle = (int)gameLocal.GetLocalPlayer()->viewAngles.yaw;
  576. if ((int)lastPosition.x == (int)currentPosition.x && (int)lastPosition.y == (int)currentPosition.y && (int)lastPosition.z == (int)currentPosition.z && (int)lastAngle == (int)currentAngle)
  577. {
  578. return;
  579. }
  580. lastPosition = currentPosition;
  581. lastAngle = gameLocal.GetLocalPlayer()->viewAngles.yaw;
  582. record_t newEvent;
  583. newEvent.timestamp = gameLocal.time - recordStarttime;
  584. newEvent.position = currentPosition;
  585. newEvent.yaw = currentAngle;
  586. newEvent.deckcommand = NULL;
  587. newEvent.frobcommand = NULL;
  588. records[index].events.Append( newEvent );
  589. }
  590. void idWorldManager::Think( void )
  591. {
  592. int i;
  593. UpdateRecord();
  594. for (i = 0; i < 3; i++)
  595. {
  596. idVec4 markerColor;
  597. idVec3 markerPos;
  598. int markerRadius = 24;
  599. if (records[i].playing)
  600. {
  601. UpdatePlay(i);
  602. }
  603. else
  604. {
  605. continue;
  606. }
  607. if (state == OFF && index != -1 /*caser*/)
  608. {
  609. continue;
  610. }
  611. if (this->index == i)
  612. {
  613. continue;
  614. }
  615. if (!records[i].ghost->IsHidden())
  616. {
  617. if ((int)(gameLocal.time * 0.004) % 3 == 0)
  618. {
  619. markerRadius = 12;
  620. }
  621. switch (i)
  622. {
  623. case 0: markerColor = idVec4(.25, .75, 1, 1); break; //blue.
  624. case 1: markerColor = idVec4(.74, .9, .26, 1); break; //green.
  625. default: markerColor = idVec4(1, .6, 0, 1); break; //orange.
  626. }
  627. //blue .25, .75, 1
  628. //yellow 1, .8, 0, 1
  629. //red .9, .25, .25
  630. markerPos = records[i].ghost->GetPhysics()->GetOrigin() + idVec3(0,0,85);
  631. gameRenderWorld->DebugLine( markerColor, markerPos + idVec3(0,0,-markerRadius), markerPos + idVec3(0,0,markerRadius) );
  632. gameRenderWorld->DebugLine( markerColor, markerPos + idVec3(0,-markerRadius,0), markerPos + idVec3(0,markerRadius,0) );
  633. gameRenderWorld->DebugLine( markerColor, markerPos + idVec3(-markerRadius,0,0), markerPos + idVec3(markerRadius,0,0) );
  634. if (index == -1)
  635. {
  636. //draw lines.
  637. int k;
  638. if (recordlines[i].lines.Num() >= 3)
  639. {
  640. for (k = 0; k < recordlines[i].lines.Num() - 1; k++)
  641. {
  642. if (k > 2) //BC hack. The initial lines are garbage data. So, just skip them.
  643. {
  644. gameRenderWorld->DebugLine( markerColor,
  645. recordlines[i].lines[k].position1, recordlines[i].lines[k].position2 );
  646. }
  647. }
  648. //This is the dangly bit that connects the last recordline position to the character model's feet.
  649. if (records[i].index < recordlines[i].lines.Num() && i > 1)
  650. {
  651. gameRenderWorld->DebugLine( markerColor,
  652. recordlines[i].lines[records[i].index].position1,
  653. records[i].ghost->GetPhysics()->GetOrigin() );
  654. }
  655. }
  656. }
  657. }
  658. }
  659. }