Physics_Monster.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../../idlib/precompiled.h"
  22. #include "../Game_local.h"
  23. CLASS_DECLARATION( idPhysics_Actor, idPhysics_Monster )
  24. END_CLASS
  25. const float OVERCLIP = 1.001f;
  26. /*
  27. =====================
  28. idPhysics_Monster::CheckGround
  29. =====================
  30. */
  31. void idPhysics_Monster::CheckGround( monsterPState_t &state ) {
  32. trace_t groundTrace;
  33. idVec3 down;
  34. if ( gravityNormal == vec3_zero ) {
  35. state.onGround = false;
  36. groundEntityPtr = NULL;
  37. return;
  38. }
  39. down = state.origin + gravityNormal * CONTACT_EPSILON;
  40. gameLocal.clip.Translation( groundTrace, state.origin, down, clipModel, clipModel->GetAxis(), clipMask, self );
  41. if ( groundTrace.fraction == 1.0f ) {
  42. state.onGround = false;
  43. groundEntityPtr = NULL;
  44. return;
  45. }
  46. groundEntityPtr = gameLocal.entities[ groundTrace.c.entityNum ];
  47. if ( ( groundTrace.c.normal * -gravityNormal ) < minFloorCosine ) {
  48. state.onGround = false;
  49. return;
  50. }
  51. state.onGround = true;
  52. // let the entity know about the collision
  53. self->Collide( groundTrace, state.velocity );
  54. // apply impact to a non world floor entity
  55. if ( groundTrace.c.entityNum != ENTITYNUM_WORLD && groundEntityPtr.GetEntity() ) {
  56. impactInfo_t info;
  57. groundEntityPtr.GetEntity()->GetImpactInfo( self, groundTrace.c.id, groundTrace.c.point, &info );
  58. if ( info.invMass != 0.0f ) {
  59. groundEntityPtr.GetEntity()->ApplyImpulse( self, 0, groundTrace.c.point, state.velocity / ( info.invMass * 10.0f ) );
  60. }
  61. }
  62. }
  63. /*
  64. =====================
  65. idPhysics_Monster::SlideMove
  66. =====================
  67. */
  68. monsterMoveResult_t idPhysics_Monster::SlideMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) {
  69. int i;
  70. trace_t tr;
  71. idVec3 move;
  72. blockingEntity = NULL;
  73. move = delta;
  74. for( i = 0; i < 3; i++ ) {
  75. gameLocal.clip.Translation( tr, start, start + move, clipModel, clipModel->GetAxis(), clipMask, self );
  76. start = tr.endpos;
  77. if ( tr.fraction == 1.0f ) {
  78. if ( i > 0 ) {
  79. return MM_SLIDING;
  80. }
  81. return MM_OK;
  82. }
  83. if ( tr.c.entityNum != ENTITYNUM_NONE ) {
  84. assert( tr.c.entityNum < MAX_GENTITIES );
  85. blockingEntity = gameLocal.entities[ tr.c.entityNum ];
  86. }
  87. // clip the movement delta and velocity
  88. move.ProjectOntoPlane( tr.c.normal, OVERCLIP );
  89. velocity.ProjectOntoPlane( tr.c.normal, OVERCLIP );
  90. }
  91. return MM_BLOCKED;
  92. }
  93. /*
  94. =====================
  95. idPhysics_Monster::StepMove
  96. move start into the delta direction
  97. the velocity is clipped conform any collisions
  98. =====================
  99. */
  100. monsterMoveResult_t idPhysics_Monster::StepMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) {
  101. trace_t tr;
  102. idVec3 up, down, noStepPos, noStepVel, stepPos, stepVel;
  103. monsterMoveResult_t result1, result2;
  104. float stepdist;
  105. float nostepdist;
  106. if ( delta == vec3_origin ) {
  107. return MM_OK;
  108. }
  109. // try to move without stepping up
  110. noStepPos = start;
  111. noStepVel = velocity;
  112. result1 = SlideMove( noStepPos, noStepVel, delta );
  113. if ( result1 == MM_OK ) {
  114. velocity = noStepVel;
  115. if ( gravityNormal == vec3_zero ) {
  116. start = noStepPos;
  117. return MM_OK;
  118. }
  119. // try to step down so that we walk down slopes and stairs at a normal rate
  120. down = noStepPos + gravityNormal * maxStepHeight;
  121. gameLocal.clip.Translation( tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
  122. if ( tr.fraction < 1.0f ) {
  123. start = tr.endpos;
  124. return MM_STEPPED;
  125. } else {
  126. start = noStepPos;
  127. return MM_OK;
  128. }
  129. }
  130. if ( blockingEntity && blockingEntity->IsType( idActor::Type ) ) {
  131. // try to step down in case walking into an actor while going down steps
  132. down = noStepPos + gravityNormal * maxStepHeight;
  133. gameLocal.clip.Translation( tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
  134. start = tr.endpos;
  135. velocity = noStepVel;
  136. return MM_BLOCKED;
  137. }
  138. if ( gravityNormal == vec3_zero ) {
  139. return result1;
  140. }
  141. // try to step up
  142. up = start - gravityNormal * maxStepHeight;
  143. gameLocal.clip.Translation( tr, start, up, clipModel, clipModel->GetAxis(), clipMask, self );
  144. if ( tr.fraction == 0.0f ) {
  145. start = noStepPos;
  146. velocity = noStepVel;
  147. return result1;
  148. }
  149. // try to move at the stepped up position
  150. stepPos = tr.endpos;
  151. stepVel = velocity;
  152. result2 = SlideMove( stepPos, stepVel, delta );
  153. if ( result2 == MM_BLOCKED ) {
  154. start = noStepPos;
  155. velocity = noStepVel;
  156. return result1;
  157. }
  158. // step down again
  159. down = stepPos + gravityNormal * maxStepHeight;
  160. gameLocal.clip.Translation( tr, stepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
  161. stepPos = tr.endpos;
  162. // if the move is further without stepping up, or the slope is too steap, don't step up
  163. nostepdist = ( noStepPos - start ).LengthSqr();
  164. stepdist = ( stepPos - start ).LengthSqr();
  165. if ( ( nostepdist >= stepdist ) || ( ( tr.c.normal * -gravityNormal ) < minFloorCosine ) ) {
  166. start = noStepPos;
  167. velocity = noStepVel;
  168. return MM_SLIDING;
  169. }
  170. start = stepPos;
  171. velocity = stepVel;
  172. return MM_STEPPED;
  173. }
  174. /*
  175. ================
  176. idPhysics_Monster::Activate
  177. ================
  178. */
  179. void idPhysics_Monster::Activate() {
  180. current.atRest = -1;
  181. self->BecomeActive( TH_PHYSICS );
  182. }
  183. /*
  184. ================
  185. idPhysics_Monster::Rest
  186. ================
  187. */
  188. void idPhysics_Monster::Rest() {
  189. current.atRest = gameLocal.time;
  190. current.velocity.Zero();
  191. self->BecomeInactive( TH_PHYSICS );
  192. }
  193. /*
  194. ================
  195. idPhysics_Monster::PutToRest
  196. ================
  197. */
  198. void idPhysics_Monster::PutToRest() {
  199. Rest();
  200. }
  201. /*
  202. ================
  203. idPhysics_Monster::idPhysics_Monster
  204. ================
  205. */
  206. idPhysics_Monster::idPhysics_Monster() {
  207. memset( &current, 0, sizeof( current ) );
  208. current.atRest = -1;
  209. saved = current;
  210. delta.Zero();
  211. maxStepHeight = 18.0f;
  212. minFloorCosine = 0.7f;
  213. moveResult = MM_OK;
  214. forceDeltaMove = false;
  215. fly = false;
  216. useVelocityMove = false;
  217. noImpact = false;
  218. blockingEntity = NULL;
  219. }
  220. /*
  221. ================
  222. idPhysics_Monster_SavePState
  223. ================
  224. */
  225. void idPhysics_Monster_SavePState( idSaveGame *savefile, const monsterPState_t &state ) {
  226. savefile->WriteVec3( state.origin );
  227. savefile->WriteVec3( state.velocity );
  228. savefile->WriteVec3( state.localOrigin );
  229. savefile->WriteVec3( state.pushVelocity );
  230. savefile->WriteBool( state.onGround );
  231. savefile->WriteInt( state.atRest );
  232. }
  233. /*
  234. ================
  235. idPhysics_Monster_RestorePState
  236. ================
  237. */
  238. void idPhysics_Monster_RestorePState( idRestoreGame *savefile, monsterPState_t &state ) {
  239. savefile->ReadVec3( state.origin );
  240. savefile->ReadVec3( state.velocity );
  241. savefile->ReadVec3( state.localOrigin );
  242. savefile->ReadVec3( state.pushVelocity );
  243. savefile->ReadBool( state.onGround );
  244. savefile->ReadInt( state.atRest );
  245. }
  246. /*
  247. ================
  248. idPhysics_Monster::Save
  249. ================
  250. */
  251. void idPhysics_Monster::Save( idSaveGame *savefile ) const {
  252. idPhysics_Monster_SavePState( savefile, current );
  253. idPhysics_Monster_SavePState( savefile, saved );
  254. savefile->WriteFloat( maxStepHeight );
  255. savefile->WriteFloat( minFloorCosine );
  256. savefile->WriteVec3( delta );
  257. savefile->WriteBool( forceDeltaMove );
  258. savefile->WriteBool( fly );
  259. savefile->WriteBool( useVelocityMove );
  260. savefile->WriteBool( noImpact );
  261. savefile->WriteInt( (int)moveResult );
  262. savefile->WriteObject( blockingEntity );
  263. }
  264. /*
  265. ================
  266. idPhysics_Monster::Restore
  267. ================
  268. */
  269. void idPhysics_Monster::Restore( idRestoreGame *savefile ) {
  270. idPhysics_Monster_RestorePState( savefile, current );
  271. idPhysics_Monster_RestorePState( savefile, saved );
  272. savefile->ReadFloat( maxStepHeight );
  273. savefile->ReadFloat( minFloorCosine );
  274. savefile->ReadVec3( delta );
  275. savefile->ReadBool( forceDeltaMove );
  276. savefile->ReadBool( fly );
  277. savefile->ReadBool( useVelocityMove );
  278. savefile->ReadBool( noImpact );
  279. savefile->ReadInt( (int &)moveResult );
  280. savefile->ReadObject( reinterpret_cast<idClass *&>( blockingEntity ) );
  281. }
  282. /*
  283. ================
  284. idPhysics_Monster::SetDelta
  285. ================
  286. */
  287. void idPhysics_Monster::SetDelta( const idVec3 &d ) {
  288. delta = d;
  289. if ( delta != vec3_origin ) {
  290. Activate();
  291. }
  292. }
  293. /*
  294. ================
  295. idPhysics_Monster::SetMaxStepHeight
  296. ================
  297. */
  298. void idPhysics_Monster::SetMaxStepHeight( const float newMaxStepHeight ) {
  299. maxStepHeight = newMaxStepHeight;
  300. }
  301. /*
  302. ================
  303. idPhysics_Monster::GetMaxStepHeight
  304. ================
  305. */
  306. float idPhysics_Monster::GetMaxStepHeight() const {
  307. return maxStepHeight;
  308. }
  309. /*
  310. ================
  311. idPhysics_Monster::OnGround
  312. ================
  313. */
  314. bool idPhysics_Monster::OnGround() const {
  315. return current.onGround;
  316. }
  317. /*
  318. ================
  319. idPhysics_Monster::GetSlideMoveEntity
  320. ================
  321. */
  322. idEntity *idPhysics_Monster::GetSlideMoveEntity() const {
  323. return blockingEntity;
  324. }
  325. /*
  326. ================
  327. idPhysics_Monster::GetMoveResult
  328. ================
  329. */
  330. monsterMoveResult_t idPhysics_Monster::GetMoveResult() const {
  331. return moveResult;
  332. }
  333. /*
  334. ================
  335. idPhysics_Monster::ForceDeltaMove
  336. ================
  337. */
  338. void idPhysics_Monster::ForceDeltaMove( bool force ) {
  339. forceDeltaMove = force;
  340. }
  341. /*
  342. ================
  343. idPhysics_Monster::UseFlyMove
  344. ================
  345. */
  346. void idPhysics_Monster::UseFlyMove( bool force ) {
  347. fly = force;
  348. }
  349. /*
  350. ================
  351. idPhysics_Monster::UseVelocityMove
  352. ================
  353. */
  354. void idPhysics_Monster::UseVelocityMove( bool force ) {
  355. useVelocityMove = force;
  356. }
  357. /*
  358. ================
  359. idPhysics_Monster::EnableImpact
  360. ================
  361. */
  362. void idPhysics_Monster::EnableImpact() {
  363. noImpact = false;
  364. }
  365. /*
  366. ================
  367. idPhysics_Monster::DisableImpact
  368. ================
  369. */
  370. void idPhysics_Monster::DisableImpact() {
  371. noImpact = true;
  372. }
  373. /*
  374. ================
  375. idPhysics_Monster::Evaluate
  376. ================
  377. */
  378. bool idPhysics_Monster::Evaluate( int timeStepMSec, int endTimeMSec ) {
  379. idVec3 masterOrigin, oldOrigin;
  380. idMat3 masterAxis;
  381. float timeStep;
  382. timeStep = MS2SEC( timeStepMSec );
  383. moveResult = MM_OK;
  384. blockingEntity = NULL;
  385. oldOrigin = current.origin;
  386. // if bound to a master
  387. if ( masterEntity ) {
  388. self->GetMasterPosition( masterOrigin, masterAxis );
  389. current.origin = masterOrigin + current.localOrigin * masterAxis;
  390. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  391. current.velocity = ( current.origin - oldOrigin ) / timeStep;
  392. masterDeltaYaw = masterYaw;
  393. masterYaw = masterAxis[0].ToYaw();
  394. masterDeltaYaw = masterYaw - masterDeltaYaw;
  395. return true;
  396. }
  397. // if the monster is at rest
  398. if ( current.atRest >= 0 ) {
  399. return false;
  400. }
  401. ActivateContactEntities();
  402. // move the monster velocity into the frame of a pusher
  403. current.velocity -= current.pushVelocity;
  404. clipModel->Unlink();
  405. // check if on the ground
  406. idPhysics_Monster::CheckGround( current );
  407. // if not on the ground or moving upwards
  408. float upspeed;
  409. if ( gravityNormal != vec3_zero ) {
  410. upspeed = -( current.velocity * gravityNormal );
  411. } else {
  412. upspeed = current.velocity.z;
  413. }
  414. if ( fly || ( !forceDeltaMove && ( !current.onGround || upspeed > 1.0f ) ) ) {
  415. if ( upspeed < 0.0f ) {
  416. moveResult = MM_FALLING;
  417. }
  418. else {
  419. current.onGround = false;
  420. moveResult = MM_OK;
  421. }
  422. delta = current.velocity * timeStep;
  423. if ( delta != vec3_origin ) {
  424. moveResult = idPhysics_Monster::SlideMove( current.origin, current.velocity, delta );
  425. delta.Zero();
  426. }
  427. if ( !fly ) {
  428. current.velocity += gravityVector * timeStep;
  429. }
  430. } else {
  431. if ( useVelocityMove ) {
  432. delta = current.velocity * timeStep;
  433. } else {
  434. current.velocity = delta / timeStep;
  435. }
  436. current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal;
  437. if ( delta == vec3_origin ) {
  438. Rest();
  439. } else {
  440. // try moving into the desired direction
  441. moveResult = idPhysics_Monster::StepMove( current.origin, current.velocity, delta );
  442. delta.Zero();
  443. }
  444. }
  445. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  446. // get all the ground contacts
  447. EvaluateContacts();
  448. // move the monster velocity back into the world frame
  449. current.velocity += current.pushVelocity;
  450. current.pushVelocity.Zero();
  451. if ( IsOutsideWorld() ) {
  452. gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
  453. Rest();
  454. }
  455. return ( current.origin != oldOrigin );
  456. }
  457. /*
  458. ================
  459. idPhysics_Monster::UpdateTime
  460. ================
  461. */
  462. void idPhysics_Monster::UpdateTime( int endTimeMSec ) {
  463. }
  464. /*
  465. ================
  466. idPhysics_Monster::GetTime
  467. ================
  468. */
  469. int idPhysics_Monster::GetTime() const {
  470. return gameLocal.time;
  471. }
  472. /*
  473. ================
  474. idPhysics_Monster::GetImpactInfo
  475. ================
  476. */
  477. void idPhysics_Monster::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
  478. info->invMass = invMass;
  479. info->invInertiaTensor.Zero();
  480. info->position.Zero();
  481. info->velocity = current.velocity;
  482. }
  483. /*
  484. ================
  485. idPhysics_Monster::ApplyImpulse
  486. ================
  487. */
  488. void idPhysics_Monster::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
  489. if ( noImpact ) {
  490. return;
  491. }
  492. current.velocity += impulse * invMass;
  493. Activate();
  494. }
  495. /*
  496. ================
  497. idPhysics_Monster::IsAtRest
  498. ================
  499. */
  500. bool idPhysics_Monster::IsAtRest() const {
  501. return current.atRest >= 0;
  502. }
  503. /*
  504. ================
  505. idPhysics_Monster::GetRestStartTime
  506. ================
  507. */
  508. int idPhysics_Monster::GetRestStartTime() const {
  509. return current.atRest;
  510. }
  511. /*
  512. ================
  513. idPhysics_Monster::SaveState
  514. ================
  515. */
  516. void idPhysics_Monster::SaveState() {
  517. saved = current;
  518. }
  519. /*
  520. ================
  521. idPhysics_Monster::RestoreState
  522. ================
  523. */
  524. void idPhysics_Monster::RestoreState() {
  525. current = saved;
  526. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  527. EvaluateContacts();
  528. }
  529. /*
  530. ================
  531. idPhysics_Player::SetOrigin
  532. ================
  533. */
  534. void idPhysics_Monster::SetOrigin( const idVec3 &newOrigin, int id ) {
  535. idVec3 masterOrigin;
  536. idMat3 masterAxis;
  537. current.localOrigin = newOrigin;
  538. if ( masterEntity ) {
  539. self->GetMasterPosition( masterOrigin, masterAxis );
  540. current.origin = masterOrigin + newOrigin * masterAxis;
  541. }
  542. else {
  543. current.origin = newOrigin;
  544. }
  545. clipModel->Link( gameLocal.clip, self, 0, newOrigin, clipModel->GetAxis() );
  546. Activate();
  547. }
  548. /*
  549. ================
  550. idPhysics_Player::SetAxis
  551. ================
  552. */
  553. void idPhysics_Monster::SetAxis( const idMat3 &newAxis, int id ) {
  554. clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), newAxis );
  555. Activate();
  556. }
  557. /*
  558. ================
  559. idPhysics_Monster::Translate
  560. ================
  561. */
  562. void idPhysics_Monster::Translate( const idVec3 &translation, int id ) {
  563. current.localOrigin += translation;
  564. current.origin += translation;
  565. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  566. Activate();
  567. }
  568. /*
  569. ================
  570. idPhysics_Monster::Rotate
  571. ================
  572. */
  573. void idPhysics_Monster::Rotate( const idRotation &rotation, int id ) {
  574. idVec3 masterOrigin;
  575. idMat3 masterAxis;
  576. current.origin *= rotation;
  577. if ( masterEntity ) {
  578. self->GetMasterPosition( masterOrigin, masterAxis );
  579. current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
  580. }
  581. else {
  582. current.localOrigin = current.origin;
  583. }
  584. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
  585. Activate();
  586. }
  587. /*
  588. ================
  589. idPhysics_Monster::SetLinearVelocity
  590. ================
  591. */
  592. void idPhysics_Monster::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
  593. current.velocity = newLinearVelocity;
  594. Activate();
  595. }
  596. /*
  597. ================
  598. idPhysics_Monster::GetLinearVelocity
  599. ================
  600. */
  601. const idVec3 &idPhysics_Monster::GetLinearVelocity( int id ) const {
  602. return current.velocity;
  603. }
  604. /*
  605. ================
  606. idPhysics_Monster::SetPushed
  607. ================
  608. */
  609. void idPhysics_Monster::SetPushed( int deltaTime ) {
  610. // velocity with which the monster is pushed
  611. current.pushVelocity += ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC );
  612. }
  613. /*
  614. ================
  615. idPhysics_Monster::GetPushedLinearVelocity
  616. ================
  617. */
  618. const idVec3 &idPhysics_Monster::GetPushedLinearVelocity( const int id ) const {
  619. return current.pushVelocity;
  620. }
  621. /*
  622. ================
  623. idPhysics_Monster::SetMaster
  624. the binding is never orientated
  625. ================
  626. */
  627. void idPhysics_Monster::SetMaster( idEntity *master, const bool orientated ) {
  628. idVec3 masterOrigin;
  629. idMat3 masterAxis;
  630. if ( master ) {
  631. if ( !masterEntity ) {
  632. // transform from world space to master space
  633. self->GetMasterPosition( masterOrigin, masterAxis );
  634. current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
  635. masterEntity = master;
  636. masterYaw = masterAxis[0].ToYaw();
  637. }
  638. ClearContacts();
  639. }
  640. else {
  641. if ( masterEntity ) {
  642. masterEntity = NULL;
  643. Activate();
  644. }
  645. }
  646. }
  647. const float MONSTER_VELOCITY_MAX = 4000;
  648. const int MONSTER_VELOCITY_TOTAL_BITS = 16;
  649. const int MONSTER_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( MONSTER_VELOCITY_MAX ) ) + 1;
  650. const int MONSTER_VELOCITY_MANTISSA_BITS = MONSTER_VELOCITY_TOTAL_BITS - 1 - MONSTER_VELOCITY_EXPONENT_BITS;
  651. /*
  652. ================
  653. idPhysics_Monster::WriteToSnapshot
  654. ================
  655. */
  656. void idPhysics_Monster::WriteToSnapshot( idBitMsg &msg ) const {
  657. msg.WriteFloat( current.origin[0] );
  658. msg.WriteFloat( current.origin[1] );
  659. msg.WriteFloat( current.origin[2] );
  660. msg.WriteFloat( current.velocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  661. msg.WriteFloat( current.velocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  662. msg.WriteFloat( current.velocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  663. msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] );
  664. msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] );
  665. msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] );
  666. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  667. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  668. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  669. msg.WriteLong( current.atRest );
  670. msg.WriteBits( current.onGround, 1 );
  671. }
  672. /*
  673. ================
  674. idPhysics_Monster::ReadFromSnapshot
  675. ================
  676. */
  677. void idPhysics_Monster::ReadFromSnapshot( const idBitMsg &msg ) {
  678. current.origin[0] = msg.ReadFloat();
  679. current.origin[1] = msg.ReadFloat();
  680. current.origin[2] = msg.ReadFloat();
  681. current.velocity[0] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  682. current.velocity[1] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  683. current.velocity[2] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  684. current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] );
  685. current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] );
  686. current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] );
  687. current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  688. current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  689. current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
  690. current.atRest = msg.ReadLong();
  691. current.onGround = msg.ReadBits( 1 ) != 0;
  692. }