sentry.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. #include "../idlib/precompiled.h"
  2. #pragma hdrstop
  3. #include "Game_local.h"
  4. #define TURN_TIME 300
  5. #define SHOT_DELAY 350
  6. const idEventDef EV_sentry_activate( "sentryactivate", "d" );
  7. const idEventDef EV_sentry_issentryactive( "issentryactive", NULL, 'd' );
  8. const idEventDef EV_sentry_turn( "sentryturn", "f" );
  9. const idEventDef EV_sentry_pitch( "sentrypitch", "f" );
  10. const idEventDef EV_sentry_face( "sentryface", "fff" );
  11. const idEventDef EV_sentry_stand( "sentrystand" );
  12. const idEventDef EV_sentry_fire( "sentryfire" );
  13. const idEventDef EV_sentry_getlaser( "sentrygetlaser", NULL, 'v' );
  14. const idEventDef EV_sentry_sentrykill( "sentrykill" );
  15. CLASS_DECLARATION( idMoveableItem, idSentry )
  16. EVENT( EV_sentry_activate, idSentry::Event_activate)
  17. EVENT( EV_sentry_issentryactive, idSentry::Event_issentryactive)
  18. EVENT( EV_sentry_turn, idSentry::Event_sentryturn)
  19. EVENT( EV_sentry_pitch, idSentry::Event_sentrypitch)
  20. EVENT( EV_sentry_face, idSentry::Event_sentryface)
  21. EVENT( EV_sentry_fire, idSentry::Event_sentryfire)
  22. EVENT( EV_sentry_stand, idSentry::Event_sentrystand)
  23. EVENT( EV_sentry_getlaser, idSentry::Event_sentrygetlaser)
  24. EVENT( EV_sentry_sentrykill, idSentry::Event_sentrykill)
  25. END_CLASS
  26. void idSentry::Spawn( void )
  27. {
  28. idDict args;
  29. jointHandle_t muzzleJoint;
  30. idVec3 muzzlePos;
  31. idMat3 muzzleAxis;
  32. idVec3 forward, right, up;
  33. pitch = 0;
  34. yaw = 0;
  35. state = OFF;
  36. BecomeActive( TH_THINK );
  37. args.Clear();
  38. args.SetVector( "origin", this->GetPhysics()->GetOrigin() );
  39. args.Set( "model", "env_sentry" );
  40. model = ( idAnimatedEntity * )gameLocal.SpawnEntityType( idAnimatedEntity::Type, &args );
  41. model->Bind(this, true);
  42. model->Event_PlayAnim( "closed", 4 );
  43. //spawn beam end.
  44. args.SetVector( "origin", vec3_origin );
  45. beamEnd = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
  46. muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
  47. model->GetAnimator()->GetJointTransform( muzzleJoint, gameLocal.time, muzzlePos, muzzleAxis );
  48. //spawn beam start.
  49. args.Clear();
  50. args.Set( "target", beamEnd->name.c_str() );
  51. args.SetVector( "origin", muzzlePos + this->GetPhysics()->GetOrigin() );
  52. args.SetBool( "start_off", true );
  53. args.Set( "skin", spawnArgs.GetString("beamskin", "skins/beam_turret") );
  54. args.SetInt( "width", spawnArgs.GetInt("beamwidth", "3") );
  55. beamStart = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
  56. beamStart->BindToJoint( model, muzzleJoint, false );
  57. beamStart->BecomeActive(TH_PHYSICS);
  58. beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_RED ] = 0;
  59. beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_GREEN ] = 1;
  60. beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_BLUE ] = 0;
  61. //laser sight dot.
  62. args.Clear();
  63. args.SetVector( "origin", vec3_origin );
  64. args.Set( "model", spawnArgs.GetString("lasermodel", "models/lasersight/tris.ase") );
  65. args.SetInt( "solid", 0 );
  66. laserdot = gameLocal.SpawnEntityType( idStaticEntity::Type, &args );
  67. laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_RED ] = 0;
  68. laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_GREEN ] = 1;
  69. laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_BLUE ] = 0;
  70. laserdot->Hide();
  71. yawActive = false;
  72. yawTimeEnd = 0;
  73. yawTimeStart = 0;
  74. yawStart = 0;
  75. yawEnd = 0;
  76. pitchActive = false;
  77. pitchTimeEnd = 0;
  78. pitchTimeStart = 0;
  79. pitchStart = 0;
  80. pitchEnd = 0;
  81. //nose camera.
  82. this->GetPhysics()->GetAxis().ToAngles().ToVectors(&forward, &right, &up);
  83. args.Clear();
  84. args.SetVector( "origin", muzzlePos + this->GetPhysics()->GetOrigin() + (up * 2.6f) );
  85. args.Set( "classname", "func_cameraview" );
  86. gameLocal.SpawnEntityDef( args, &nosecam );
  87. nosecam->BindToJoint( model, muzzleJoint, true );
  88. nosecam->BecomeActive(TH_PHYSICS);
  89. this->spawnArgs.Set("nosecamera_name", nosecam->GetName());
  90. nextShotTime = 0;
  91. queuedShots = 0;
  92. }
  93. void idSentry::Save( idSaveGame *savefile ) const {
  94. savefile->WriteInt(state);
  95. savefile->WriteFloat(yaw);
  96. savefile->WriteFloat(pitch);
  97. savefile->WriteObject(beamStart);
  98. savefile->WriteObject(beamEnd);
  99. savefile->WriteObject(model);
  100. savefile->WriteObject(laserdot);
  101. savefile->WriteObject(nosecam);
  102. savefile->WriteInt(laserActivateTime);
  103. savefile->WriteFloat(yawStart);
  104. savefile->WriteFloat(yawEnd);
  105. savefile->WriteInt(yawTimeStart);
  106. savefile->WriteInt(yawTimeEnd);
  107. savefile->WriteBool(yawActive);
  108. savefile->WriteFloat(pitchStart);
  109. savefile->WriteFloat(pitchEnd);
  110. savefile->WriteInt(pitchTimeStart);
  111. savefile->WriteInt(pitchTimeEnd);
  112. savefile->WriteBool(pitchActive);
  113. savefile->WriteInt(queuedShots);
  114. savefile->WriteInt(nextShotTime);
  115. }
  116. void idSentry::Restore( idRestoreGame *savefile ) {
  117. savefile->ReadInt(state);
  118. savefile->ReadFloat(yaw);
  119. savefile->ReadFloat(pitch);
  120. savefile->ReadObject(reinterpret_cast<idClass *&>(beamStart));
  121. savefile->ReadObject(reinterpret_cast<idClass *&>(beamEnd));
  122. savefile->ReadObject(reinterpret_cast<idClass *&>(model));
  123. savefile->ReadObject(reinterpret_cast<idClass *&>(laserdot));
  124. savefile->ReadObject(reinterpret_cast<idClass *&>(nosecam));
  125. savefile->ReadInt(laserActivateTime);
  126. savefile->ReadFloat(yawStart);
  127. savefile->ReadFloat(yawEnd);
  128. savefile->ReadInt(yawTimeStart);
  129. savefile->ReadInt(yawTimeEnd);
  130. savefile->ReadBool(yawActive);
  131. savefile->ReadFloat(pitchStart);
  132. savefile->ReadFloat(pitchEnd);
  133. savefile->ReadInt(pitchTimeStart);
  134. savefile->ReadInt(pitchTimeEnd);
  135. savefile->ReadBool(pitchActive);
  136. savefile->ReadInt(queuedShots);
  137. savefile->ReadInt(nextShotTime);
  138. }
  139. void idSentry::Event_sentrygetlaser()
  140. {
  141. idThread::ReturnVector(this->beamEnd->GetPhysics()->GetOrigin());
  142. }
  143. void idSentry::Event_sentrystand()
  144. {
  145. idAngles ang = this->GetPhysics()->GetAxis().ToAngles();
  146. ang.pitch = 0;
  147. ang.roll = 0;
  148. this->GetPhysics()->SetAxis( ang.ToMat3() );
  149. this->SetOrigin(this->GetPhysics()->GetOrigin() + idVec3(0,0,0.1f));
  150. }
  151. void idSentry::Event_sentryfire()
  152. {
  153. if (gameLocal.time > nextShotTime)
  154. {
  155. fireShot();
  156. nextShotTime = gameLocal.time + SHOT_DELAY;
  157. }
  158. else
  159. {
  160. queuedShots++;
  161. }
  162. }
  163. void idSentry::fireShot()
  164. {
  165. jointHandle_t muzzleJoint, muzzleBackJoint;
  166. idVec3 offset1, offset2;
  167. idMat3 axis;
  168. muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
  169. muzzleBackJoint = model->GetAnimator()->GetJointHandle( "muzzle_back" );
  170. if ( model->GetJointWorldTransform( muzzleJoint, gameLocal.time, offset1, axis )
  171. && model->GetJointWorldTransform( muzzleBackJoint, gameLocal.time, offset2, axis ))
  172. {
  173. //trace_t tr;
  174. const idDict * projectileDef;
  175. idEntity * ent;
  176. idVec3 forward;
  177. idDict args;
  178. idEntity * particles;
  179. idAngles particlesAngles;
  180. idVec3 bulletspeed;
  181. StartSound( "snd_fire", SND_CHANNEL_ANY, 0, false, NULL );
  182. forward = offset1 - offset2;
  183. forward.Normalize();
  184. //fire the projectile.
  185. //FIRE.
  186. idProjectile *bullet;
  187. projectileDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("projectile", "projectile_sentrybullet"), false );
  188. bulletspeed = projectileDef->GetVector("velocity", "256 0 0");
  189. gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
  190. bullet = ( idProjectile * )ent;
  191. bullet->Create( this, offset1, forward );
  192. bullet->Launch( offset1, forward, forward * bulletspeed.x );
  193. args.Clear();
  194. args.SetVector( "origin", offset1);
  195. args.Set( "model", spawnArgs.GetString("smoke_fire", "gunsmoke.prt") );
  196. args.SetBool( "start_off", false );
  197. particles = gameLocal.SpawnEntityType( idExplodable::Type, &args );
  198. particlesAngles = forward.ToAngles();
  199. particlesAngles.pitch += 90;
  200. particles->SetAngles(particlesAngles);
  201. //BC shell casing.
  202. idVec3 gunPos;
  203. jointHandle_t gunJoint;
  204. idMat3 gunAxis;
  205. gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
  206. model->GetAnimator()->GetJointTransform( gunJoint, gameLocal.time, gunPos, gunAxis);
  207. gunPos = this->GetPhysics()->GetOrigin() + gunPos * this->GetPhysics()->GetAxis();
  208. idEntity *shellEnt;
  209. const idDict * shellDef = gameLocal.FindEntityDefDict( spawnArgs.GetString( "shell", "moveable_shell"), false );
  210. gameLocal.SpawnEntityDef( *shellDef, &shellEnt, false );
  211. shellEnt->GetPhysics()->SetOrigin(gunPos);
  212. shellEnt->GetPhysics()->SetAxis(this->GetPhysics()->GetAxis());
  213. idVec3 right;
  214. forward.ToAngles().ToVectors( NULL, &right, NULL);
  215. idVec3 shellVelocity = (right * (16 + gameLocal.random.CRandomFloat() * 8) ) + idVec3(0,0,80+gameLocal.random.CRandomFloat() * 12) + (forward * (gameLocal.random.CRandomFloat() * 8) );
  216. shellEnt->GetPhysics()->SetLinearVelocity(shellVelocity);
  217. }
  218. }
  219. void idSentry::Event_sentryface( float x, float y, float z )
  220. {
  221. idVec3 dirToTarget;
  222. jointHandle_t pivotJoint;
  223. idVec3 offset;
  224. idMat3 axis;
  225. pivotJoint = model->GetAnimator()->GetJointHandle( "pivot" );
  226. model->GetJointWorldTransform(pivotJoint, gameLocal.time, offset, axis);
  227. dirToTarget = idVec3(x,y,z) - offset;
  228. idAngles ang1 = dirToTarget.ToAngles();
  229. ang1.yaw -= this->GetPhysics()->GetAxis().ToAngles().yaw;
  230. ang1.pitch -= this->GetPhysics()->GetAxis().ToAngles().pitch;
  231. dirToTarget = ang1.ToForward();
  232. dirToTarget.Normalize();
  233. model->GetAnimator()->SetJointAxis(pivotJoint, JOINTMOD_WORLD, dirToTarget.ToMat3());
  234. }
  235. void idSentry::Event_sentryturn( float yawValue )
  236. {
  237. yawTimeStart = gameLocal.time;
  238. yawTimeEnd = gameLocal.time + TURN_TIME;
  239. yawStart = yaw;
  240. yawEnd = yaw - yawValue;
  241. yawActive = true;
  242. }
  243. void idSentry::Event_sentrypitch( float pitchValue )
  244. {
  245. pitchTimeStart = gameLocal.time;
  246. pitchTimeEnd = gameLocal.time + TURN_TIME;
  247. pitchStart = pitch;
  248. pitchEnd = pitch - pitchValue;
  249. pitchActive = true;
  250. /*
  251. jointHandle_t gunJoint;
  252. this->pitch -= pitchValue;
  253. idAngles ang(pitch, yaw,0);
  254. gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
  255. model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());*/
  256. }
  257. void idSentry::Event_activate( int value )
  258. {
  259. if (value >= 1)
  260. {
  261. //turn on. Deploy.
  262. model->Event_PlayAnim( "deploy", 4 );
  263. state = DEPLOYING;
  264. laserActivateTime = gameLocal.time + 1300;
  265. }
  266. else
  267. {
  268. //turn off. Pack up.
  269. model->Event_PlayAnim( "close", 4 );
  270. state = CLOSING;
  271. pitchTimeStart = gameLocal.time;
  272. pitchTimeEnd = gameLocal.time + 400;
  273. pitchStart = pitch;
  274. pitchEnd = 0;
  275. pitchActive = true;
  276. yawTimeStart = gameLocal.time;
  277. yawTimeEnd = gameLocal.time + 400;
  278. yawStart = yaw;
  279. yawEnd = 0;
  280. yawActive = true;
  281. laserdot->Hide();
  282. beamStart->Hide();
  283. queuedShots = 0;
  284. }
  285. }
  286. void idSentry::Event_issentryactive()
  287. {
  288. if (state == ON || state == DEPLOYING)
  289. {
  290. idThread::ReturnInt( 1 );
  291. return;
  292. }
  293. else
  294. {
  295. idThread::ReturnInt( 0 );
  296. return;
  297. }
  298. }
  299. void idSentry::Think( void )
  300. {
  301. trace_t tr;
  302. idVec3 offset1, offset2;
  303. idMat3 axis;
  304. jointHandle_t muzzleJoint, muzzleBackJoint;
  305. //RunPhysics();
  306. muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
  307. muzzleBackJoint = model->GetAnimator()->GetJointHandle( "muzzle_back" );
  308. if ( model->GetJointWorldTransform( muzzleJoint, gameLocal.time, offset1, axis )
  309. && model->GetJointWorldTransform( muzzleBackJoint, gameLocal.time, offset2, axis ))
  310. {
  311. trace_t tr;
  312. idVec3 forward;
  313. forward = offset1 - offset2;
  314. forward.Normalize();
  315. //beam end goes through glass.
  316. int i;
  317. int maxGlassPanes = 32;
  318. idVec3 beamTempStartPos = offset1;
  319. for (i = 0; i < maxGlassPanes; i++)
  320. {
  321. trace_t beamTr;
  322. gameLocal.clip.TracePoint( beamTr, beamTempStartPos, beamTempStartPos + (forward * 4096), MASK_SOLID | MASK_SHOT_RENDERMODEL, this );
  323. if (!gameLocal.entities[ beamTr.c.entityNum ])
  324. continue;
  325. if (gameLocal.entities[ beamTr.c.entityNum ]->IsType( idBrittleFracture::Type ) || gameLocal.entities[ beamTr.c.entityNum ]->IsType( idQGlass::Type ))
  326. {
  327. //glass. continue the beam.
  328. //gameRenderWorld->DebugLine(idVec4(1,1,0,1), beamTempStartPos, beamTr.endpos, 1, false);
  329. beamTempStartPos = beamTr.endpos + (forward * 0.1f);
  330. continue;
  331. }
  332. beamEnd->SetOrigin( beamTr.endpos );
  333. break;
  334. }
  335. //gameLocal.clip.TracePoint( tr, offset1, offset1 + (forward * 4096), MASK_OPAQUE, this );
  336. //beamEnd->SetOrigin( tr.endpos );
  337. //beam dot stops at any solid surface.
  338. gameLocal.clip.TracePoint( tr, offset1, offset1 + (forward * 4096), MASK_SOLID | MASK_SHOT_RENDERMODEL, this );
  339. laserdot->SetOrigin( tr.endpos);
  340. }
  341. //yaw think.
  342. if (yawActive)
  343. {
  344. jointHandle_t gunJoint;
  345. float lerp;
  346. float currentTime = gameLocal.time;
  347. float lookTimeMax = yawTimeEnd - yawTimeStart;
  348. float lookTimeMin = yawTimeStart;
  349. currentTime -= yawTimeStart;
  350. lerp = currentTime / lookTimeMax;
  351. if (lerp > 1)
  352. lerp = 1;
  353. yaw = idMath::Lerp(yawStart, yawEnd, lerp);
  354. idAngles ang(pitch, yaw,0);
  355. gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
  356. model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());
  357. if (lerp >= 1)
  358. {
  359. yawActive = false;
  360. }
  361. }
  362. //yaw think.
  363. if (pitchActive)
  364. {
  365. jointHandle_t gunJoint;
  366. float lerp;
  367. float currentTime = gameLocal.time;
  368. float lookTimeMax = pitchTimeEnd - pitchTimeStart;
  369. float lookTimeMin = pitchTimeStart;
  370. currentTime -= pitchTimeStart;
  371. lerp = currentTime / lookTimeMax;
  372. if (lerp > 1)
  373. lerp = 1;
  374. pitch = idMath::Lerp(pitchStart, pitchEnd, lerp);
  375. idAngles ang(pitch, yaw,0);
  376. gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
  377. model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());
  378. if (lerp >= 1)
  379. {
  380. pitchActive = false;
  381. }
  382. }
  383. if (gameLocal.time > laserActivateTime && (laserdot->IsHidden() || beamStart->IsHidden())
  384. && (state == DEPLOYING || state == ON) )
  385. {
  386. laserdot->Show();
  387. beamStart->Show();
  388. }
  389. //BC 10-2-2015 so that the camera can see the laserline. ugh! hack.
  390. if (!beamStart->IsHidden())
  391. gameRenderWorld->DebugLine(idVec4(0,1,0,1), beamStart->GetPhysics()->GetOrigin(), beamEnd->GetPhysics()->GetOrigin(),1, true);
  392. if (gameLocal.time > nextShotTime && queuedShots > 0 && state != OFF)
  393. {
  394. fireShot();
  395. nextShotTime = gameLocal.time + SHOT_DELAY;
  396. queuedShots--;
  397. }
  398. //Present();
  399. idMoveableItem::Think();
  400. }
  401. void idSentry::OnGet( void )
  402. {
  403. //BC 6-28-2016 crash fix
  404. gameLocal.KillCCTVs();
  405. gameLocal.GetLocalPlayer()->StartSound( "snd_get", SND_CHANNEL_ANY, 0, false, NULL );
  406. this->PostEventMS( &EV_Remove, 0 );
  407. gameLocal.GetLocalPlayer()->GiveInventoryItem("weapon_sentry");
  408. }
  409. void idSentry::Event_sentrykill( void )
  410. {
  411. gameLocal.KillCCTVs();
  412. laserdot->PostEventMS( &EV_Remove, 0 );
  413. beamStart->PostEventMS( &EV_Remove, 0 );
  414. beamEnd->PostEventMS( &EV_Remove, 0 );
  415. }