Physics_Player.cpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "../Game_local.h"
  23. CLASS_DECLARATION( idPhysics_Actor, idPhysics_Player )
  24. END_CLASS
  25. // movement parameters
  26. const float PM_STOPSPEED = 100.0f;
  27. const float PM_SWIMSCALE = 0.5f;
  28. const float PM_LADDERSPEED = 100.0f;
  29. const float PM_STEPSCALE = 1.0f;
  30. const float PM_ACCELERATE = 10.0f;
  31. const float PM_AIRACCELERATE = 1.0f;
  32. const float PM_WATERACCELERATE = 4.0f;
  33. const float PM_FLYACCELERATE = 8.0f;
  34. const float PM_FRICTION = 6.0f;
  35. const float PM_AIRFRICTION = 0.0f;
  36. const float PM_WATERFRICTION = 1.0f;
  37. const float PM_FLYFRICTION = 3.0f;
  38. const float PM_NOCLIPFRICTION = 12.0f;
  39. const float MIN_WALK_NORMAL = 0.7f; // can't walk on very steep slopes
  40. const float OVERCLIP = 1.001f;
  41. // movementFlags
  42. const int PMF_DUCKED = 1; // set when ducking
  43. const int PMF_JUMPED = 2; // set when the player jumped this frame
  44. const int PMF_STEPPED_UP = 4; // set when the player stepped up this frame
  45. const int PMF_STEPPED_DOWN = 8; // set when the player stepped down this frame
  46. const int PMF_JUMP_HELD = 16; // set when jump button is held down
  47. const int PMF_TIME_LAND = 32; // movementTime is time before rejump
  48. const int PMF_TIME_KNOCKBACK = 64; // movementTime is an air-accelerate only time
  49. const int PMF_TIME_WATERJUMP = 128; // movementTime is waterjump
  50. const int PMF_ALL_TIMES = (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK);
  51. int c_pmove = 0;
  52. /*
  53. ============
  54. idPhysics_Player::CmdScale
  55. Returns the scale factor to apply to cmd movements
  56. This allows the clients to use axial -127 to 127 values for all directions
  57. without getting a sqrt(2) distortion in speed.
  58. ============
  59. */
  60. float idPhysics_Player::CmdScale( const usercmd_t &cmd ) const {
  61. int max;
  62. float total;
  63. float scale;
  64. int forwardmove;
  65. int rightmove;
  66. int upmove;
  67. forwardmove = cmd.forwardmove;
  68. rightmove = cmd.rightmove;
  69. // since the crouch key doubles as downward movement, ignore downward movement when we're on the ground
  70. // otherwise crouch speed will be lower than specified
  71. if ( walking ) {
  72. upmove = 0;
  73. } else {
  74. upmove = cmd.upmove;
  75. }
  76. max = abs( forwardmove );
  77. if ( abs( rightmove ) > max ) {
  78. max = abs( rightmove );
  79. }
  80. if ( abs( upmove ) > max ) {
  81. max = abs( upmove );
  82. }
  83. if ( !max ) {
  84. return 0.0f;
  85. }
  86. total = idMath::Sqrt( (float) forwardmove * forwardmove + rightmove * rightmove + upmove * upmove );
  87. scale = (float) playerSpeed * max / ( 127.0f * total );
  88. return scale;
  89. }
  90. /*
  91. ==============
  92. idPhysics_Player::Accelerate
  93. Handles user intended acceleration
  94. ==============
  95. */
  96. void idPhysics_Player::Accelerate( const idVec3 &wishdir, const float wishspeed, const float accel ) {
  97. #if 1
  98. // q2 style
  99. float addspeed, accelspeed, currentspeed;
  100. currentspeed = current.velocity * wishdir;
  101. addspeed = wishspeed - currentspeed;
  102. if (addspeed <= 0) {
  103. return;
  104. }
  105. accelspeed = accel * frametime * wishspeed;
  106. if (accelspeed > addspeed) {
  107. accelspeed = addspeed;
  108. }
  109. current.velocity += accelspeed * wishdir;
  110. #else
  111. // proper way (avoids strafe jump maxspeed bug), but feels bad
  112. idVec3 wishVelocity;
  113. idVec3 pushDir;
  114. float pushLen;
  115. float canPush;
  116. wishVelocity = wishdir * wishspeed;
  117. pushDir = wishVelocity - current.velocity;
  118. pushLen = pushDir.Normalize();
  119. canPush = accel * frametime * wishspeed;
  120. if (canPush > pushLen) {
  121. canPush = pushLen;
  122. }
  123. current.velocity += canPush * pushDir;
  124. #endif
  125. }
  126. /*
  127. ==================
  128. idPhysics_Player::SlideMove
  129. Returns true if the velocity was clipped in some way
  130. ==================
  131. */
  132. #define MAX_CLIP_PLANES 5
  133. bool idPhysics_Player::SlideMove( bool gravity, bool stepUp, bool stepDown, bool push ) {
  134. int i, j, k, pushFlags;
  135. int bumpcount, numbumps, numplanes;
  136. float d, time_left, into, totalMass;
  137. idVec3 dir, planes[MAX_CLIP_PLANES];
  138. idVec3 end, stepEnd, primal_velocity, endVelocity, endClipVelocity, clipVelocity;
  139. trace_t trace, stepTrace, downTrace;
  140. bool nearGround, stepped, pushed;
  141. numbumps = 4;
  142. primal_velocity = current.velocity;
  143. if ( gravity ) {
  144. endVelocity = current.velocity + gravityVector * frametime;
  145. current.velocity = ( current.velocity + endVelocity ) * 0.5f;
  146. primal_velocity = endVelocity;
  147. if ( groundPlane ) {
  148. // slide along the ground plane
  149. current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  150. }
  151. }
  152. else {
  153. endVelocity = current.velocity;
  154. }
  155. time_left = frametime;
  156. // never turn against the ground plane
  157. if ( groundPlane ) {
  158. numplanes = 1;
  159. planes[0] = groundTrace.c.normal;
  160. } else {
  161. numplanes = 0;
  162. }
  163. // never turn against original velocity
  164. planes[numplanes] = current.velocity;
  165. planes[numplanes].Normalize();
  166. numplanes++;
  167. for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) {
  168. // calculate position we are trying to move to
  169. end = current.origin + time_left * current.velocity;
  170. // see if we can make it there
  171. gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self );
  172. time_left -= time_left * trace.fraction;
  173. current.origin = trace.endpos;
  174. // if moved the entire distance
  175. if ( trace.fraction >= 1.0f ) {
  176. break;
  177. }
  178. stepped = pushed = false;
  179. // if we are allowed to step up
  180. if ( stepUp ) {
  181. nearGround = groundPlane | ladder;
  182. if ( !nearGround ) {
  183. // trace down to see if the player is near the ground
  184. // step checking when near the ground allows the player to move up stairs smoothly while jumping
  185. stepEnd = current.origin + maxStepHeight * gravityNormal;
  186. gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
  187. nearGround = ( downTrace.fraction < 1.0f && (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL );
  188. }
  189. // may only step up if near the ground or on a ladder
  190. if ( nearGround ) {
  191. // step up
  192. stepEnd = current.origin - maxStepHeight * gravityNormal;
  193. gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
  194. // trace along velocity
  195. stepEnd = downTrace.endpos + time_left * current.velocity;
  196. gameLocal.clip.Translation( stepTrace, downTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
  197. // step down
  198. stepEnd = stepTrace.endpos + maxStepHeight * gravityNormal;
  199. gameLocal.clip.Translation( downTrace, stepTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
  200. if ( downTrace.fraction >= 1.0f || (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL ) {
  201. // if moved the entire distance
  202. if ( stepTrace.fraction >= 1.0f ) {
  203. time_left = 0;
  204. current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
  205. current.origin = downTrace.endpos;
  206. current.movementFlags |= PMF_STEPPED_UP;
  207. current.velocity *= PM_STEPSCALE;
  208. break;
  209. }
  210. // if the move is further when stepping up
  211. if ( stepTrace.fraction > trace.fraction ) {
  212. time_left -= time_left * stepTrace.fraction;
  213. current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
  214. current.origin = downTrace.endpos;
  215. current.movementFlags |= PMF_STEPPED_UP;
  216. current.velocity *= PM_STEPSCALE;
  217. trace = stepTrace;
  218. stepped = true;
  219. }
  220. }
  221. }
  222. }
  223. // if we can push other entities and not blocked by the world
  224. if ( push && trace.c.entityNum != ENTITYNUM_WORLD ) {
  225. clipModel->SetPosition( current.origin, clipModel->GetAxis() );
  226. // clip movement, only push idMoveables, don't push entities the player is standing on
  227. // apply impact to pushed objects
  228. pushFlags = PUSHFL_CLIP|PUSHFL_ONLYMOVEABLE|PUSHFL_NOGROUNDENTITIES|PUSHFL_APPLYIMPULSE;
  229. // clip & push
  230. totalMass = gameLocal.push.ClipTranslationalPush( trace, self, pushFlags, end, end - current.origin );
  231. if ( totalMass > 0.0f ) {
  232. // decrease velocity based on the total mass of the objects being pushed ?
  233. current.velocity *= 1.0f - idMath::ClampFloat( 0.0f, 1000.0f, totalMass - 20.0f ) * ( 1.0f / 950.0f );
  234. pushed = true;
  235. }
  236. current.origin = trace.endpos;
  237. time_left -= time_left * trace.fraction;
  238. // if moved the entire distance
  239. if ( trace.fraction >= 1.0f ) {
  240. break;
  241. }
  242. }
  243. if ( !stepped ) {
  244. // let the entity know about the collision
  245. self->Collide( trace, current.velocity );
  246. }
  247. if ( numplanes >= MAX_CLIP_PLANES ) {
  248. // MrElusive: I think we have some relatively high poly LWO models with a lot of slanted tris
  249. // where it may hit the max clip planes
  250. current.velocity = vec3_origin;
  251. return true;
  252. }
  253. //
  254. // if this is the same plane we hit before, nudge velocity
  255. // out along it, which fixes some epsilon issues with
  256. // non-axial planes
  257. //
  258. for ( i = 0; i < numplanes; i++ ) {
  259. if ( ( trace.c.normal * planes[i] ) > 0.999f ) {
  260. current.velocity += trace.c.normal;
  261. break;
  262. }
  263. }
  264. if ( i < numplanes ) {
  265. continue;
  266. }
  267. planes[numplanes] = trace.c.normal;
  268. numplanes++;
  269. //
  270. // modify velocity so it parallels all of the clip planes
  271. //
  272. // find a plane that it enters
  273. for ( i = 0; i < numplanes; i++ ) {
  274. into = current.velocity * planes[i];
  275. if ( into >= 0.1f ) {
  276. continue; // move doesn't interact with the plane
  277. }
  278. // slide along the plane
  279. clipVelocity = current.velocity;
  280. clipVelocity.ProjectOntoPlane( planes[i], OVERCLIP );
  281. // slide along the plane
  282. endClipVelocity = endVelocity;
  283. endClipVelocity.ProjectOntoPlane( planes[i], OVERCLIP );
  284. // see if there is a second plane that the new move enters
  285. for ( j = 0; j < numplanes; j++ ) {
  286. if ( j == i ) {
  287. continue;
  288. }
  289. if ( ( clipVelocity * planes[j] ) >= 0.1f ) {
  290. continue; // move doesn't interact with the plane
  291. }
  292. // try clipping the move to the plane
  293. clipVelocity.ProjectOntoPlane( planes[j], OVERCLIP );
  294. endClipVelocity.ProjectOntoPlane( planes[j], OVERCLIP );
  295. // see if it goes back into the first clip plane
  296. if ( ( clipVelocity * planes[i] ) >= 0 ) {
  297. continue;
  298. }
  299. // slide the original velocity along the crease
  300. dir = planes[i].Cross( planes[j] );
  301. dir.Normalize();
  302. d = dir * current.velocity;
  303. clipVelocity = d * dir;
  304. dir = planes[i].Cross( planes[j] );
  305. dir.Normalize();
  306. d = dir * endVelocity;
  307. endClipVelocity = d * dir;
  308. // see if there is a third plane the the new move enters
  309. for ( k = 0; k < numplanes; k++ ) {
  310. if ( k == i || k == j ) {
  311. continue;
  312. }
  313. if ( ( clipVelocity * planes[k] ) >= 0.1f ) {
  314. continue; // move doesn't interact with the plane
  315. }
  316. // stop dead at a tripple plane interaction
  317. current.velocity = vec3_origin;
  318. return true;
  319. }
  320. }
  321. // if we have fixed all interactions, try another move
  322. current.velocity = clipVelocity;
  323. endVelocity = endClipVelocity;
  324. break;
  325. }
  326. }
  327. // step down
  328. if ( stepDown && groundPlane ) {
  329. stepEnd = current.origin + gravityNormal * maxStepHeight;
  330. gameLocal.clip.Translation( downTrace, current.origin, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
  331. if ( downTrace.fraction > 1e-4f && downTrace.fraction < 1.0f ) {
  332. current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
  333. current.origin = downTrace.endpos;
  334. current.movementFlags |= PMF_STEPPED_DOWN;
  335. current.velocity *= PM_STEPSCALE;
  336. }
  337. }
  338. if ( gravity ) {
  339. current.velocity = endVelocity;
  340. }
  341. // come to a dead stop when the velocity orthogonal to the gravity flipped
  342. clipVelocity = current.velocity - gravityNormal * current.velocity * gravityNormal;
  343. endClipVelocity = endVelocity - gravityNormal * endVelocity * gravityNormal;
  344. if ( clipVelocity * endClipVelocity < 0.0f ) {
  345. current.velocity = gravityNormal * current.velocity * gravityNormal;
  346. }
  347. return (bool)( bumpcount == 0 );
  348. }
  349. /*
  350. ==================
  351. idPhysics_Player::Friction
  352. Handles both ground friction and water friction
  353. ==================
  354. */
  355. void idPhysics_Player::Friction( void ) {
  356. idVec3 vel;
  357. float speed, newspeed, control;
  358. float drop;
  359. vel = current.velocity;
  360. if ( walking ) {
  361. // ignore slope movement, remove all velocity in gravity direction
  362. vel += (vel * gravityNormal) * gravityNormal;
  363. }
  364. speed = vel.Length();
  365. if ( speed < 1.0f ) {
  366. // remove all movement orthogonal to gravity, allows for sinking underwater
  367. if ( fabs( current.velocity * gravityNormal ) < 1e-5f ) {
  368. current.velocity.Zero();
  369. } else {
  370. current.velocity = (current.velocity * gravityNormal) * gravityNormal;
  371. }
  372. // FIXME: still have z friction underwater?
  373. return;
  374. }
  375. drop = 0;
  376. // spectator friction
  377. if ( current.movementType == PM_SPECTATOR ) {
  378. drop += speed * PM_FLYFRICTION * frametime;
  379. }
  380. // apply ground friction
  381. else if ( walking && waterLevel <= WATERLEVEL_FEET ) {
  382. // no friction on slick surfaces
  383. if ( !(groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK) ) {
  384. // if getting knocked back, no friction
  385. if ( !(current.movementFlags & PMF_TIME_KNOCKBACK) ) {
  386. control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed;
  387. drop += control * PM_FRICTION * frametime;
  388. }
  389. }
  390. }
  391. // apply water friction even if just wading
  392. else if ( waterLevel ) {
  393. drop += speed * PM_WATERFRICTION * waterLevel * frametime;
  394. }
  395. // apply air friction
  396. else {
  397. drop += speed * PM_AIRFRICTION * frametime;
  398. }
  399. // scale the velocity
  400. newspeed = speed - drop;
  401. if (newspeed < 0) {
  402. newspeed = 0;
  403. }
  404. current.velocity *= ( newspeed / speed );
  405. }
  406. /*
  407. ===================
  408. idPhysics_Player::WaterJumpMove
  409. Flying out of the water
  410. ===================
  411. */
  412. void idPhysics_Player::WaterJumpMove( void ) {
  413. // waterjump has no control, but falls
  414. idPhysics_Player::SlideMove( true, true, false, false );
  415. // add gravity
  416. current.velocity += gravityNormal * frametime;
  417. // if falling down
  418. if ( current.velocity * gravityNormal > 0.0f ) {
  419. // cancel as soon as we are falling down again
  420. current.movementFlags &= ~PMF_ALL_TIMES;
  421. current.movementTime = 0;
  422. }
  423. }
  424. /*
  425. ===================
  426. idPhysics_Player::WaterMove
  427. ===================
  428. */
  429. void idPhysics_Player::WaterMove( void ) {
  430. idVec3 wishvel;
  431. float wishspeed;
  432. idVec3 wishdir;
  433. float scale;
  434. float vel;
  435. if ( idPhysics_Player::CheckWaterJump() ) {
  436. idPhysics_Player::WaterJumpMove();
  437. return;
  438. }
  439. idPhysics_Player::Friction();
  440. scale = idPhysics_Player::CmdScale( command );
  441. // user intentions
  442. if ( !scale ) {
  443. wishvel = gravityNormal * 60; // sink towards bottom
  444. } else {
  445. wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
  446. wishvel -= scale * gravityNormal * command.upmove;
  447. }
  448. wishdir = wishvel;
  449. wishspeed = wishdir.Normalize();
  450. if ( wishspeed > playerSpeed * PM_SWIMSCALE ) {
  451. wishspeed = playerSpeed * PM_SWIMSCALE;
  452. }
  453. idPhysics_Player::Accelerate( wishdir, wishspeed, PM_WATERACCELERATE );
  454. // make sure we can go up slopes easily under water
  455. if ( groundPlane && ( current.velocity * groundTrace.c.normal ) < 0.0f ) {
  456. vel = current.velocity.Length();
  457. // slide along the ground plane
  458. current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  459. current.velocity.Normalize();
  460. current.velocity *= vel;
  461. }
  462. idPhysics_Player::SlideMove( false, true, false, false );
  463. }
  464. /*
  465. ===================
  466. idPhysics_Player::FlyMove
  467. ===================
  468. */
  469. void idPhysics_Player::FlyMove( void ) {
  470. idVec3 wishvel;
  471. float wishspeed;
  472. idVec3 wishdir;
  473. float scale;
  474. // normal slowdown
  475. idPhysics_Player::Friction();
  476. scale = idPhysics_Player::CmdScale( command );
  477. if ( !scale ) {
  478. wishvel = vec3_origin;
  479. } else {
  480. wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
  481. wishvel -= scale * gravityNormal * command.upmove;
  482. }
  483. wishdir = wishvel;
  484. wishspeed = wishdir.Normalize();
  485. idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE );
  486. idPhysics_Player::SlideMove( false, false, false, false );
  487. }
  488. /*
  489. ===================
  490. idPhysics_Player::AirMove
  491. ===================
  492. */
  493. void idPhysics_Player::AirMove( void ) {
  494. idVec3 wishvel;
  495. idVec3 wishdir;
  496. float wishspeed;
  497. float scale;
  498. idPhysics_Player::Friction();
  499. scale = idPhysics_Player::CmdScale( command );
  500. // project moves down to flat plane
  501. viewForward -= (viewForward * gravityNormal) * gravityNormal;
  502. viewRight -= (viewRight * gravityNormal) * gravityNormal;
  503. viewForward.Normalize();
  504. viewRight.Normalize();
  505. wishvel = viewForward * command.forwardmove + viewRight * command.rightmove;
  506. wishvel -= (wishvel * gravityNormal) * gravityNormal;
  507. wishdir = wishvel;
  508. wishspeed = wishdir.Normalize();
  509. wishspeed *= scale;
  510. // not on ground, so little effect on velocity
  511. idPhysics_Player::Accelerate( wishdir, wishspeed, PM_AIRACCELERATE );
  512. // we may have a ground plane that is very steep, even
  513. // though we don't have a groundentity
  514. // slide along the steep plane
  515. if ( groundPlane ) {
  516. current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  517. }
  518. idPhysics_Player::SlideMove( true, false, false, false );
  519. }
  520. /*
  521. ===================
  522. idPhysics_Player::WalkMove
  523. ===================
  524. */
  525. void idPhysics_Player::WalkMove( void ) {
  526. idVec3 wishvel;
  527. idVec3 wishdir;
  528. float wishspeed;
  529. float scale;
  530. float accelerate;
  531. idVec3 oldVelocity, vel;
  532. float oldVel, newVel;
  533. if ( waterLevel > WATERLEVEL_WAIST && ( viewForward * groundTrace.c.normal ) > 0.0f ) {
  534. // begin swimming
  535. idPhysics_Player::WaterMove();
  536. return;
  537. }
  538. if ( idPhysics_Player::CheckJump() ) {
  539. // jumped away
  540. if ( waterLevel > WATERLEVEL_FEET ) {
  541. idPhysics_Player::WaterMove();
  542. }
  543. else {
  544. idPhysics_Player::AirMove();
  545. }
  546. return;
  547. }
  548. idPhysics_Player::Friction();
  549. scale = idPhysics_Player::CmdScale( command );
  550. // project moves down to flat plane
  551. viewForward -= (viewForward * gravityNormal) * gravityNormal;
  552. viewRight -= (viewRight * gravityNormal) * gravityNormal;
  553. // project the forward and right directions onto the ground plane
  554. viewForward.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  555. viewRight.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  556. //
  557. viewForward.Normalize();
  558. viewRight.Normalize();
  559. wishvel = viewForward * command.forwardmove + viewRight * command.rightmove;
  560. wishdir = wishvel;
  561. wishspeed = wishdir.Normalize();
  562. wishspeed *= scale;
  563. // clamp the speed lower if wading or walking on the bottom
  564. if ( waterLevel ) {
  565. float waterScale;
  566. waterScale = waterLevel / 3.0f;
  567. waterScale = 1.0f - ( 1.0f - PM_SWIMSCALE ) * waterScale;
  568. if ( wishspeed > playerSpeed * waterScale ) {
  569. wishspeed = playerSpeed * waterScale;
  570. }
  571. }
  572. // when a player gets hit, they temporarily lose full control, which allows them to be moved a bit
  573. if ( ( groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK ) || current.movementFlags & PMF_TIME_KNOCKBACK ) {
  574. accelerate = PM_AIRACCELERATE;
  575. }
  576. else {
  577. accelerate = PM_ACCELERATE;
  578. }
  579. idPhysics_Player::Accelerate( wishdir, wishspeed, accelerate );
  580. if ( ( groundMaterial && groundMaterial->GetSurfaceFlags() & SURF_SLICK ) || current.movementFlags & PMF_TIME_KNOCKBACK ) {
  581. current.velocity += gravityVector * frametime;
  582. }
  583. oldVelocity = current.velocity;
  584. // slide along the ground plane
  585. current.velocity.ProjectOntoPlane( groundTrace.c.normal, OVERCLIP );
  586. // if not clipped into the opposite direction
  587. if ( oldVelocity * current.velocity > 0.0f ) {
  588. newVel = current.velocity.LengthSqr();
  589. if ( newVel > 1.0f ) {
  590. oldVel = oldVelocity.LengthSqr();
  591. if ( oldVel > 1.0f ) {
  592. // don't decrease velocity when going up or down a slope
  593. current.velocity *= idMath::Sqrt( oldVel / newVel );
  594. }
  595. }
  596. }
  597. // don't do anything if standing still
  598. vel = current.velocity - (current.velocity * gravityNormal) * gravityNormal;
  599. if ( !vel.LengthSqr() ) {
  600. return;
  601. }
  602. gameLocal.push.InitSavingPushedEntityPositions();
  603. idPhysics_Player::SlideMove( false, true, true, true );
  604. }
  605. /*
  606. ==============
  607. idPhysics_Player::DeadMove
  608. ==============
  609. */
  610. void idPhysics_Player::DeadMove( void ) {
  611. float forward;
  612. if ( !walking ) {
  613. return;
  614. }
  615. // extra friction
  616. forward = current.velocity.Length();
  617. forward -= 20;
  618. if ( forward <= 0 ) {
  619. current.velocity = vec3_origin;
  620. }
  621. else {
  622. current.velocity.Normalize();
  623. current.velocity *= forward;
  624. }
  625. }
  626. /*
  627. ===============
  628. idPhysics_Player::NoclipMove
  629. ===============
  630. */
  631. void idPhysics_Player::NoclipMove( void ) {
  632. float speed, drop, friction, newspeed, stopspeed;
  633. float scale, wishspeed;
  634. idVec3 wishdir;
  635. // friction
  636. speed = current.velocity.Length();
  637. if ( speed < 20.0f ) {
  638. current.velocity = vec3_origin;
  639. }
  640. else {
  641. stopspeed = playerSpeed * 0.3f;
  642. if ( speed < stopspeed ) {
  643. speed = stopspeed;
  644. }
  645. friction = PM_NOCLIPFRICTION;
  646. drop = speed * friction * frametime;
  647. // scale the velocity
  648. newspeed = speed - drop;
  649. if (newspeed < 0) {
  650. newspeed = 0;
  651. }
  652. current.velocity *= newspeed / speed;
  653. }
  654. // accelerate
  655. scale = idPhysics_Player::CmdScale( command );
  656. wishdir = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
  657. wishdir -= scale * gravityNormal * command.upmove;
  658. wishspeed = wishdir.Normalize();
  659. wishspeed *= scale;
  660. idPhysics_Player::Accelerate( wishdir, wishspeed, PM_ACCELERATE );
  661. // move
  662. current.origin += frametime * current.velocity;
  663. }
  664. /*
  665. ===============
  666. idPhysics_Player::SpectatorMove
  667. ===============
  668. */
  669. void idPhysics_Player::SpectatorMove( void ) {
  670. idVec3 wishvel;
  671. float wishspeed;
  672. idVec3 wishdir;
  673. float scale;
  674. trace_t trace;
  675. idVec3 end;
  676. // fly movement
  677. idPhysics_Player::Friction();
  678. scale = idPhysics_Player::CmdScale( command );
  679. if ( !scale ) {
  680. wishvel = vec3_origin;
  681. } else {
  682. wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
  683. }
  684. wishdir = wishvel;
  685. wishspeed = wishdir.Normalize();
  686. idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE );
  687. idPhysics_Player::SlideMove( false, false, false, false );
  688. }
  689. /*
  690. ============
  691. idPhysics_Player::LadderMove
  692. ============
  693. */
  694. void idPhysics_Player::LadderMove( void ) {
  695. idVec3 wishdir, wishvel, right;
  696. float wishspeed, scale;
  697. float upscale;
  698. // stick to the ladder
  699. wishvel = -100.0f * ladderNormal;
  700. current.velocity = (gravityNormal * current.velocity) * gravityNormal + wishvel;
  701. upscale = (-gravityNormal * viewForward + 0.5f) * 2.5f;
  702. if ( upscale > 1.0f ) {
  703. upscale = 1.0f;
  704. }
  705. else if ( upscale < -1.0f ) {
  706. upscale = -1.0f;
  707. }
  708. scale = idPhysics_Player::CmdScale( command );
  709. wishvel = -0.9f * gravityNormal * upscale * scale * (float)command.forwardmove;
  710. // strafe
  711. if ( command.rightmove ) {
  712. // right vector orthogonal to gravity
  713. right = viewRight - (gravityNormal * viewRight) * gravityNormal;
  714. // project right vector into ladder plane
  715. right = right - (ladderNormal * right) * ladderNormal;
  716. right.Normalize();
  717. // if we are looking away from the ladder, reverse the right vector
  718. if ( ladderNormal * viewForward > 0.0f ) {
  719. right = -right;
  720. }
  721. wishvel += 2.0f * right * scale * (float) command.rightmove;
  722. }
  723. // up down movement
  724. if ( command.upmove ) {
  725. wishvel += -0.5f * gravityNormal * scale * (float) command.upmove;
  726. }
  727. // do strafe friction
  728. idPhysics_Player::Friction();
  729. // accelerate
  730. wishspeed = wishvel.Normalize();
  731. idPhysics_Player::Accelerate( wishvel, wishspeed, PM_ACCELERATE );
  732. // cap the vertical velocity
  733. upscale = current.velocity * -gravityNormal;
  734. if ( upscale < -PM_LADDERSPEED ) {
  735. current.velocity += gravityNormal * (upscale + PM_LADDERSPEED);
  736. }
  737. else if ( upscale > PM_LADDERSPEED ) {
  738. current.velocity += gravityNormal * (upscale - PM_LADDERSPEED);
  739. }
  740. if ( (wishvel * gravityNormal) == 0.0f ) {
  741. if ( current.velocity * gravityNormal < 0.0f ) {
  742. current.velocity += gravityVector * frametime;
  743. if ( current.velocity * gravityNormal > 0.0f ) {
  744. current.velocity -= (gravityNormal * current.velocity) * gravityNormal;
  745. }
  746. }
  747. else {
  748. current.velocity -= gravityVector * frametime;
  749. if ( current.velocity * gravityNormal < 0.0f ) {
  750. current.velocity -= (gravityNormal * current.velocity) * gravityNormal;
  751. }
  752. }
  753. }
  754. idPhysics_Player::SlideMove( false, ( command.forwardmove > 0 ), false, false );
  755. }
  756. /*
  757. =============
  758. idPhysics_Player::CorrectAllSolid
  759. =============
  760. */
  761. void idPhysics_Player::CorrectAllSolid( trace_t &trace, int contents ) {
  762. if ( debugLevel ) {
  763. gameLocal.Printf( "%i:allsolid\n", c_pmove );
  764. }
  765. // FIXME: jitter around to find a free spot ?
  766. if ( trace.fraction >= 1.0f ) {
  767. memset( &trace, 0, sizeof( trace ) );
  768. trace.endpos = current.origin;
  769. trace.endAxis = clipModelAxis;
  770. trace.fraction = 0.0f;
  771. trace.c.dist = current.origin.z;
  772. trace.c.normal.Set( 0, 0, 1 );
  773. trace.c.point = current.origin;
  774. trace.c.entityNum = ENTITYNUM_WORLD;
  775. trace.c.id = 0;
  776. trace.c.type = CONTACT_TRMVERTEX;
  777. trace.c.material = NULL;
  778. trace.c.contents = contents;
  779. }
  780. }
  781. /*
  782. =============
  783. idPhysics_Player::CheckGround
  784. =============
  785. */
  786. void idPhysics_Player::CheckGround( void ) {
  787. int i, contents;
  788. idVec3 point;
  789. bool hadGroundContacts;
  790. hadGroundContacts = HasGroundContacts();
  791. // set the clip model origin before getting the contacts
  792. clipModel->SetPosition( current.origin, clipModel->GetAxis() );
  793. EvaluateContacts();
  794. // setup a ground trace from the contacts
  795. groundTrace.endpos = current.origin;
  796. groundTrace.endAxis = clipModel->GetAxis();
  797. if ( contacts.Num() ) {
  798. groundTrace.fraction = 0.0f;
  799. groundTrace.c = contacts[0];
  800. for ( i = 1; i < contacts.Num(); i++ ) {
  801. groundTrace.c.normal += contacts[i].normal;
  802. }
  803. groundTrace.c.normal.Normalize();
  804. } else {
  805. groundTrace.fraction = 1.0f;
  806. }
  807. contents = gameLocal.clip.Contents( current.origin, clipModel, clipModel->GetAxis(), -1, self );
  808. if ( contents & MASK_SOLID ) {
  809. // do something corrective if stuck in solid
  810. idPhysics_Player::CorrectAllSolid( groundTrace, contents );
  811. }
  812. // if the trace didn't hit anything, we are in free fall
  813. if ( groundTrace.fraction == 1.0f ) {
  814. groundPlane = false;
  815. walking = false;
  816. groundEntityPtr = NULL;
  817. return;
  818. }
  819. groundMaterial = groundTrace.c.material;
  820. groundEntityPtr = gameLocal.entities[ groundTrace.c.entityNum ];
  821. // check if getting thrown off the ground
  822. if ( (current.velocity * -gravityNormal) > 0.0f && ( current.velocity * groundTrace.c.normal ) > 10.0f ) {
  823. if ( debugLevel ) {
  824. gameLocal.Printf( "%i:kickoff\n", c_pmove );
  825. }
  826. groundPlane = false;
  827. walking = false;
  828. return;
  829. }
  830. // slopes that are too steep will not be considered onground
  831. if ( ( groundTrace.c.normal * -gravityNormal ) < MIN_WALK_NORMAL ) {
  832. if ( debugLevel ) {
  833. gameLocal.Printf( "%i:steep\n", c_pmove );
  834. }
  835. // FIXME: if they can't slide down the slope, let them walk (sharp crevices)
  836. // make sure we don't die from sliding down a steep slope
  837. if ( current.velocity * gravityNormal > 150.0f ) {
  838. current.velocity -= ( current.velocity * gravityNormal - 150.0f ) * gravityNormal;
  839. }
  840. groundPlane = true;
  841. walking = false;
  842. return;
  843. }
  844. groundPlane = true;
  845. walking = true;
  846. // hitting solid ground will end a waterjump
  847. if ( current.movementFlags & PMF_TIME_WATERJUMP ) {
  848. current.movementFlags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND );
  849. current.movementTime = 0;
  850. }
  851. // if the player didn't have ground contacts the previous frame
  852. if ( !hadGroundContacts ) {
  853. // don't do landing time if we were just going down a slope
  854. if ( (current.velocity * -gravityNormal) < -200.0f ) {
  855. // don't allow another jump for a little while
  856. current.movementFlags |= PMF_TIME_LAND;
  857. current.movementTime = 250;
  858. }
  859. }
  860. // let the entity know about the collision
  861. self->Collide( groundTrace, current.velocity );
  862. if ( groundEntityPtr.GetEntity() ) {
  863. impactInfo_t info;
  864. groundEntityPtr.GetEntity()->GetImpactInfo( self, groundTrace.c.id, groundTrace.c.point, &info );
  865. if ( info.invMass != 0.0f ) {
  866. groundEntityPtr.GetEntity()->ApplyImpulse( self, groundTrace.c.id, groundTrace.c.point, current.velocity / ( info.invMass * 10.0f ) );
  867. }
  868. }
  869. }
  870. /*
  871. ==============
  872. idPhysics_Player::CheckDuck
  873. Sets clip model size
  874. ==============
  875. */
  876. void idPhysics_Player::CheckDuck( void ) {
  877. trace_t trace;
  878. idVec3 end;
  879. idBounds bounds;
  880. float maxZ;
  881. if ( current.movementType == PM_DEAD ) {
  882. maxZ = pm_deadheight.GetFloat();
  883. } else {
  884. // stand up when up against a ladder
  885. if ( command.upmove < 0 && !ladder ) {
  886. // duck
  887. current.movementFlags |= PMF_DUCKED;
  888. } else {
  889. // stand up if possible
  890. if ( current.movementFlags & PMF_DUCKED ) {
  891. // try to stand up
  892. end = current.origin - ( pm_normalheight.GetFloat() - pm_crouchheight.GetFloat() ) * gravityNormal;
  893. gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self );
  894. if ( trace.fraction >= 1.0f ) {
  895. current.movementFlags &= ~PMF_DUCKED;
  896. }
  897. }
  898. }
  899. if ( current.movementFlags & PMF_DUCKED ) {
  900. playerSpeed = crouchSpeed;
  901. maxZ = pm_crouchheight.GetFloat();
  902. } else {
  903. maxZ = pm_normalheight.GetFloat();
  904. }
  905. }
  906. // if the clipModel height should change
  907. if ( clipModel->GetBounds()[1][2] != maxZ ) {
  908. bounds = clipModel->GetBounds();
  909. bounds[1][2] = maxZ;
  910. if ( pm_usecylinder.GetBool() ) {
  911. clipModel->LoadModel( idTraceModel( bounds, 8 ) );
  912. } else {
  913. clipModel->LoadModel( idTraceModel( bounds ) );
  914. }
  915. }
  916. }
  917. /*
  918. ================
  919. idPhysics_Player::CheckLadder
  920. ================
  921. */
  922. void idPhysics_Player::CheckLadder( void ) {
  923. idVec3 forward, start, end;
  924. trace_t trace;
  925. float tracedist;
  926. if ( current.movementTime ) {
  927. return;
  928. }
  929. // if on the ground moving backwards
  930. if ( walking && command.forwardmove <= 0 ) {
  931. return;
  932. }
  933. // forward vector orthogonal to gravity
  934. forward = viewForward - (gravityNormal * viewForward) * gravityNormal;
  935. forward.Normalize();
  936. if ( walking ) {
  937. // don't want to get sucked towards the ladder when still walking
  938. tracedist = 1.0f;
  939. } else {
  940. tracedist = 48.0f;
  941. }
  942. end = current.origin + tracedist * forward;
  943. gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self );
  944. // if near a surface
  945. if ( trace.fraction < 1.0f ) {
  946. // if a ladder surface
  947. if ( trace.c.material && ( trace.c.material->GetSurfaceFlags() & SURF_LADDER ) ) {
  948. // check a step height higher
  949. end = current.origin - gravityNormal * ( maxStepHeight * 0.75f );
  950. gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self );
  951. start = trace.endpos;
  952. end = start + tracedist * forward;
  953. gameLocal.clip.Translation( trace, start, end, clipModel, clipModel->GetAxis(), clipMask, self );
  954. // if also near a surface a step height higher
  955. if ( trace.fraction < 1.0f ) {
  956. // if it also is a ladder surface
  957. if ( trace.c.material && trace.c.material->GetSurfaceFlags() & SURF_LADDER ) {
  958. ladder = true;
  959. ladderNormal = trace.c.normal;
  960. }
  961. }
  962. }
  963. }
  964. }
  965. /*
  966. =============
  967. idPhysics_Player::CheckJump
  968. =============
  969. */
  970. bool idPhysics_Player::CheckJump( void ) {
  971. idVec3 addVelocity;
  972. if ( command.upmove < 10 ) {
  973. // not holding jump
  974. return false;
  975. }
  976. // must wait for jump to be released
  977. if ( current.movementFlags & PMF_JUMP_HELD ) {
  978. return false;
  979. }
  980. // don't jump if we can't stand up
  981. if ( current.movementFlags & PMF_DUCKED ) {
  982. return false;
  983. }
  984. groundPlane = false; // jumping away
  985. walking = false;
  986. current.movementFlags |= PMF_JUMP_HELD | PMF_JUMPED;
  987. addVelocity = 2.0f * maxJumpHeight * -gravityVector;
  988. addVelocity *= idMath::Sqrt( addVelocity.Normalize() );
  989. current.velocity += addVelocity;
  990. return true;
  991. }
  992. /*
  993. =============
  994. idPhysics_Player::CheckWaterJump
  995. =============
  996. */
  997. bool idPhysics_Player::CheckWaterJump( void ) {
  998. idVec3 spot;
  999. int cont;
  1000. idVec3 flatforward;
  1001. if ( current.movementTime ) {
  1002. return false;
  1003. }
  1004. // check for water jump
  1005. if ( waterLevel != WATERLEVEL_WAIST ) {
  1006. return false;
  1007. }
  1008. flatforward = viewForward - (viewForward * gravityNormal) * gravityNormal;
  1009. flatforward.Normalize();
  1010. spot = current.origin + 30.0f * flatforward;
  1011. spot -= 4.0f * gravityNormal;
  1012. cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self );
  1013. if ( !(cont & CONTENTS_SOLID) ) {
  1014. return false;
  1015. }
  1016. spot -= 16.0f * gravityNormal;
  1017. cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self );
  1018. if ( cont ) {
  1019. return false;
  1020. }
  1021. // jump out of water
  1022. current.velocity = 200.0f * viewForward - 350.0f * gravityNormal;
  1023. current.movementFlags |= PMF_TIME_WATERJUMP;
  1024. current.movementTime = 2000;
  1025. return true;
  1026. }
  1027. /*
  1028. =============
  1029. idPhysics_Player::SetWaterLevel
  1030. =============
  1031. */
  1032. void idPhysics_Player::SetWaterLevel( void ) {
  1033. idVec3 point;
  1034. idBounds bounds;
  1035. int contents;
  1036. //
  1037. // get waterlevel, accounting for ducking
  1038. //
  1039. waterLevel = WATERLEVEL_NONE;
  1040. waterType = 0;
  1041. bounds = clipModel->GetBounds();
  1042. // check at feet level
  1043. point = current.origin - ( bounds[0][2] + 1.0f ) * gravityNormal;
  1044. contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
  1045. if ( contents & MASK_WATER ) {
  1046. waterType = contents;
  1047. waterLevel = WATERLEVEL_FEET;
  1048. // check at waist level
  1049. point = current.origin - ( bounds[1][2] - bounds[0][2] ) * 0.5f * gravityNormal;
  1050. contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
  1051. if ( contents & MASK_WATER ) {
  1052. waterLevel = WATERLEVEL_WAIST;
  1053. // check at head level
  1054. point = current.origin - ( bounds[1][2] - 1.0f ) * gravityNormal;
  1055. contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
  1056. if ( contents & MASK_WATER ) {
  1057. waterLevel = WATERLEVEL_HEAD;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. /*
  1063. ================
  1064. idPhysics_Player::DropTimers
  1065. ================
  1066. */
  1067. void idPhysics_Player::DropTimers( void ) {
  1068. // drop misc timing counter
  1069. if ( current.movementTime ) {
  1070. if ( framemsec >= current.movementTime ) {
  1071. current.movementFlags &= ~PMF_ALL_TIMES;
  1072. current.movementTime = 0;
  1073. }
  1074. else {
  1075. current.movementTime -= framemsec;
  1076. }
  1077. }
  1078. }
  1079. /*
  1080. ================
  1081. idPhysics_Player::MovePlayer
  1082. ================
  1083. */
  1084. void idPhysics_Player::MovePlayer( int msec ) {
  1085. // this counter lets us debug movement problems with a journal
  1086. // by setting a conditional breakpoint for the previous frame
  1087. c_pmove++;
  1088. walking = false;
  1089. groundPlane = false;
  1090. ladder = false;
  1091. // determine the time
  1092. framemsec = msec;
  1093. frametime = framemsec * 0.001f;
  1094. // default speed
  1095. playerSpeed = walkSpeed;
  1096. // remove jumped and stepped up flag
  1097. current.movementFlags &= ~(PMF_JUMPED|PMF_STEPPED_UP|PMF_STEPPED_DOWN);
  1098. current.stepUp = 0.0f;
  1099. if ( command.upmove < 10 ) {
  1100. // not holding jump
  1101. current.movementFlags &= ~PMF_JUMP_HELD;
  1102. }
  1103. // if no movement at all
  1104. if ( current.movementType == PM_FREEZE ) {
  1105. return;
  1106. }
  1107. // move the player velocity into the frame of a pusher
  1108. current.velocity -= current.pushVelocity;
  1109. // view vectors
  1110. viewAngles.ToVectors( &viewForward, NULL, NULL );
  1111. viewForward *= clipModelAxis;
  1112. viewRight = gravityNormal.Cross( viewForward );
  1113. viewRight.Normalize();
  1114. // fly in spectator mode
  1115. if ( current.movementType == PM_SPECTATOR ) {
  1116. SpectatorMove();
  1117. idPhysics_Player::DropTimers();
  1118. return;
  1119. }
  1120. // special no clip mode
  1121. if ( current.movementType == PM_NOCLIP ) {
  1122. idPhysics_Player::NoclipMove();
  1123. idPhysics_Player::DropTimers();
  1124. return;
  1125. }
  1126. // no control when dead
  1127. if ( current.movementType == PM_DEAD ) {
  1128. command.forwardmove = 0;
  1129. command.rightmove = 0;
  1130. command.upmove = 0;
  1131. }
  1132. // set watertype and waterlevel
  1133. idPhysics_Player::SetWaterLevel();
  1134. // check for ground
  1135. idPhysics_Player::CheckGround();
  1136. // check if up against a ladder
  1137. idPhysics_Player::CheckLadder();
  1138. // set clip model size
  1139. idPhysics_Player::CheckDuck();
  1140. // handle timers
  1141. idPhysics_Player::DropTimers();
  1142. // move
  1143. if ( current.movementType == PM_DEAD ) {
  1144. // dead
  1145. idPhysics_Player::DeadMove();
  1146. }
  1147. else if ( ladder ) {
  1148. // going up or down a ladder
  1149. idPhysics_Player::LadderMove();
  1150. }
  1151. else if ( current.movementFlags & PMF_TIME_WATERJUMP ) {
  1152. // jumping out of water
  1153. idPhysics_Player::WaterJumpMove();
  1154. }
  1155. else if ( waterLevel > 1 ) {
  1156. // swimming
  1157. idPhysics_Player::WaterMove();
  1158. }
  1159. else if ( walking ) {
  1160. // walking on ground
  1161. idPhysics_Player::WalkMove();
  1162. }
  1163. else {
  1164. // airborne
  1165. idPhysics_Player::AirMove();
  1166. }
  1167. // set watertype, waterlevel and groundentity
  1168. idPhysics_Player::SetWaterLevel();
  1169. idPhysics_Player::CheckGround();
  1170. // move the player velocity back into the world frame
  1171. current.velocity += current.pushVelocity;
  1172. current.pushVelocity.Zero();
  1173. }
  1174. /*
  1175. ================
  1176. idPhysics_Player::GetWaterLevel
  1177. ================
  1178. */
  1179. waterLevel_t idPhysics_Player::GetWaterLevel( void ) const {
  1180. return waterLevel;
  1181. }
  1182. /*
  1183. ================
  1184. idPhysics_Player::GetWaterType
  1185. ================
  1186. */
  1187. int idPhysics_Player::GetWaterType( void ) const {
  1188. return waterType;
  1189. }
  1190. /*
  1191. ================
  1192. idPhysics_Player::HasJumped
  1193. ================
  1194. */
  1195. bool idPhysics_Player::HasJumped( void ) const {
  1196. return ( ( current.movementFlags & PMF_JUMPED ) != 0 );
  1197. }
  1198. /*
  1199. ================
  1200. idPhysics_Player::HasSteppedUp
  1201. ================
  1202. */
  1203. bool idPhysics_Player::HasSteppedUp( void ) const {
  1204. return ( ( current.movementFlags & ( PMF_STEPPED_UP | PMF_STEPPED_DOWN ) ) != 0 );
  1205. }
  1206. /*
  1207. ================
  1208. idPhysics_Player::GetStepUp
  1209. ================
  1210. */
  1211. float idPhysics_Player::GetStepUp( void ) const {
  1212. return current.stepUp;
  1213. }
  1214. /*
  1215. ================
  1216. idPhysics_Player::IsCrouching
  1217. ================
  1218. */
  1219. bool idPhysics_Player::IsCrouching( void ) const {
  1220. return ( ( current.movementFlags & PMF_DUCKED ) != 0 );
  1221. }
  1222. /*
  1223. ================
  1224. idPhysics_Player::OnLadder
  1225. ================
  1226. */
  1227. bool idPhysics_Player::OnLadder( void ) const {
  1228. return ladder;
  1229. }
  1230. /*
  1231. ================
  1232. idPhysics_Player::idPhysics_Player
  1233. ================
  1234. */
  1235. idPhysics_Player::idPhysics_Player( void ) {
  1236. debugLevel = false;
  1237. clipModel = NULL;
  1238. clipMask = 0;
  1239. memset( &current, 0, sizeof( current ) );
  1240. saved = current;
  1241. walkSpeed = 0;
  1242. crouchSpeed = 0;
  1243. maxStepHeight = 0;
  1244. maxJumpHeight = 0;
  1245. memset( &command, 0, sizeof( command ) );
  1246. viewAngles.Zero();
  1247. framemsec = 0;
  1248. frametime = 0;
  1249. playerSpeed = 0;
  1250. viewForward.Zero();
  1251. viewRight.Zero();
  1252. walking = false;
  1253. groundPlane = false;
  1254. memset( &groundTrace, 0, sizeof( groundTrace ) );
  1255. groundMaterial = NULL;
  1256. ladder = false;
  1257. ladderNormal.Zero();
  1258. waterLevel = WATERLEVEL_NONE;
  1259. waterType = 0;
  1260. }
  1261. /*
  1262. ================
  1263. idPhysics_Player_SavePState
  1264. ================
  1265. */
  1266. void idPhysics_Player_SavePState( idSaveGame *savefile, const playerPState_t &state ) {
  1267. savefile->WriteVec3( state.origin );
  1268. savefile->WriteVec3( state.velocity );
  1269. savefile->WriteVec3( state.localOrigin );
  1270. savefile->WriteVec3( state.pushVelocity );
  1271. savefile->WriteFloat( state.stepUp );
  1272. savefile->WriteInt( state.movementType );
  1273. savefile->WriteInt( state.movementFlags );
  1274. savefile->WriteInt( state.movementTime );
  1275. }
  1276. /*
  1277. ================
  1278. idPhysics_Player_RestorePState
  1279. ================
  1280. */
  1281. void idPhysics_Player_RestorePState( idRestoreGame *savefile, playerPState_t &state ) {
  1282. savefile->ReadVec3( state.origin );
  1283. savefile->ReadVec3( state.velocity );
  1284. savefile->ReadVec3( state.localOrigin );
  1285. savefile->ReadVec3( state.pushVelocity );
  1286. savefile->ReadFloat( state.stepUp );
  1287. savefile->ReadInt( state.movementType );
  1288. savefile->ReadInt( state.movementFlags );
  1289. savefile->ReadInt( state.movementTime );
  1290. }
  1291. /*
  1292. ================
  1293. idPhysics_Player::Save
  1294. ================
  1295. */
  1296. void idPhysics_Player::Save( idSaveGame *savefile ) const {
  1297. idPhysics_Player_SavePState( savefile, current );
  1298. idPhysics_Player_SavePState( savefile, saved );
  1299. savefile->WriteFloat( walkSpeed );
  1300. savefile->WriteFloat( crouchSpeed );
  1301. savefile->WriteFloat( maxStepHeight );
  1302. savefile->WriteFloat( maxJumpHeight );
  1303. savefile->WriteInt( debugLevel );
  1304. savefile->WriteUsercmd( command );
  1305. savefile->WriteAngles( viewAngles );
  1306. savefile->WriteInt( framemsec );
  1307. savefile->WriteFloat( frametime );
  1308. savefile->WriteFloat( playerSpeed );
  1309. savefile->WriteVec3( viewForward );
  1310. savefile->WriteVec3( viewRight );
  1311. savefile->WriteBool( walking );
  1312. savefile->WriteBool( groundPlane );
  1313. savefile->WriteTrace( groundTrace );
  1314. savefile->WriteMaterial( groundMaterial );
  1315. savefile->WriteBool( ladder );
  1316. savefile->WriteVec3( ladderNormal );
  1317. savefile->WriteInt( (int)waterLevel );
  1318. savefile->WriteInt( waterType );
  1319. }
  1320. /*
  1321. ================
  1322. idPhysics_Player::Restore
  1323. ================
  1324. */
  1325. void idPhysics_Player::Restore( idRestoreGame *savefile ) {
  1326. idPhysics_Player_RestorePState( savefile, current );
  1327. idPhysics_Player_RestorePState( savefile, saved );
  1328. savefile->ReadFloat( walkSpeed );
  1329. savefile->ReadFloat( crouchSpeed );
  1330. savefile->ReadFloat( maxStepHeight );
  1331. savefile->ReadFloat( maxJumpHeight );
  1332. savefile->ReadInt( debugLevel );
  1333. savefile->ReadUsercmd( command );
  1334. savefile->ReadAngles( viewAngles );
  1335. savefile->ReadInt( framemsec );
  1336. savefile->ReadFloat( frametime );
  1337. savefile->ReadFloat( playerSpeed );
  1338. savefile->ReadVec3( viewForward );
  1339. savefile->ReadVec3( viewRight );
  1340. savefile->ReadBool( walking );
  1341. savefile->ReadBool( groundPlane );
  1342. savefile->ReadTrace( groundTrace );
  1343. savefile->ReadMaterial( groundMaterial );
  1344. savefile->ReadBool( ladder );
  1345. savefile->ReadVec3( ladderNormal );
  1346. savefile->ReadInt( (int &)waterLevel );
  1347. savefile->ReadInt( waterType );
  1348. }
  1349. /*
  1350. ================
  1351. idPhysics_Player::SetPlayerInput
  1352. ================
  1353. */
  1354. void idPhysics_Player::SetPlayerInput( const usercmd_t &cmd, const idAngles &newViewAngles ) {
  1355. command = cmd;
  1356. viewAngles = newViewAngles; // can't use cmd.angles cause of the delta_angles
  1357. }
  1358. /*
  1359. ================
  1360. idPhysics_Player::SetSpeed
  1361. ================
  1362. */
  1363. void idPhysics_Player::SetSpeed( const float newWalkSpeed, const float newCrouchSpeed ) {
  1364. walkSpeed = newWalkSpeed;
  1365. crouchSpeed = newCrouchSpeed;
  1366. }
  1367. /*
  1368. ================
  1369. idPhysics_Player::SetMaxStepHeight
  1370. ================
  1371. */
  1372. void idPhysics_Player::SetMaxStepHeight( const float newMaxStepHeight ) {
  1373. maxStepHeight = newMaxStepHeight;
  1374. }
  1375. /*
  1376. ================
  1377. idPhysics_Player::GetMaxStepHeight
  1378. ================
  1379. */
  1380. float idPhysics_Player::GetMaxStepHeight( void ) const {
  1381. return maxStepHeight;
  1382. }
  1383. /*
  1384. ================
  1385. idPhysics_Player::SetMaxJumpHeight
  1386. ================
  1387. */
  1388. void idPhysics_Player::SetMaxJumpHeight( const float newMaxJumpHeight ) {
  1389. maxJumpHeight = newMaxJumpHeight;
  1390. }
  1391. /*
  1392. ================
  1393. idPhysics_Player::SetMovementType
  1394. ================
  1395. */
  1396. void idPhysics_Player::SetMovementType( const pmtype_t type ) {
  1397. current.movementType = type;
  1398. }
  1399. /*
  1400. ================
  1401. idPhysics_Player::SetKnockBack
  1402. ================
  1403. */
  1404. void idPhysics_Player::SetKnockBack( const int knockBackTime ) {
  1405. if ( current.movementTime ) {
  1406. return;
  1407. }
  1408. current.movementFlags |= PMF_TIME_KNOCKBACK;
  1409. current.movementTime = knockBackTime;
  1410. }
  1411. /*
  1412. ================
  1413. idPhysics_Player::SetDebugLevel
  1414. ================
  1415. */
  1416. void idPhysics_Player::SetDebugLevel( bool set ) {
  1417. debugLevel = set;
  1418. }
  1419. /*
  1420. ================
  1421. idPhysics_Player::Evaluate
  1422. ================
  1423. */
  1424. bool idPhysics_Player::Evaluate( int timeStepMSec, int endTimeMSec ) {
  1425. idVec3 masterOrigin, oldOrigin;
  1426. idMat3 masterAxis;
  1427. waterLevel = WATERLEVEL_NONE;
  1428. waterType = 0;
  1429. oldOrigin = current.origin;
  1430. clipModel->Unlink();
  1431. // if bound to a master
  1432. if ( masterEntity ) {
  1433. self->GetMasterPosition( masterOrigin, masterAxis );
  1434. current.origin = masterOrigin + current.localOrigin * masterAxis;
  1435. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  1436. current.velocity = ( current.origin - oldOrigin ) / ( timeStepMSec * 0.001f );
  1437. masterDeltaYaw = masterYaw;
  1438. masterYaw = masterAxis[0].ToYaw();
  1439. masterDeltaYaw = masterYaw - masterDeltaYaw;
  1440. return true;
  1441. }
  1442. ActivateContactEntities();
  1443. idPhysics_Player::MovePlayer( timeStepMSec );
  1444. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  1445. if ( IsOutsideWorld() ) {
  1446. gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
  1447. }
  1448. return true; //( current.origin != oldOrigin );
  1449. }
  1450. /*
  1451. ================
  1452. idPhysics_Player::UpdateTime
  1453. ================
  1454. */
  1455. void idPhysics_Player::UpdateTime( int endTimeMSec ) {
  1456. }
  1457. /*
  1458. ================
  1459. idPhysics_Player::GetTime
  1460. ================
  1461. */
  1462. int idPhysics_Player::GetTime( void ) const {
  1463. return gameLocal.time;
  1464. }
  1465. /*
  1466. ================
  1467. idPhysics_Player::GetImpactInfo
  1468. ================
  1469. */
  1470. void idPhysics_Player::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
  1471. info->invMass = invMass;
  1472. info->invInertiaTensor.Zero();
  1473. info->position.Zero();
  1474. info->velocity = current.velocity;
  1475. }
  1476. /*
  1477. ================
  1478. idPhysics_Player::ApplyImpulse
  1479. ================
  1480. */
  1481. void idPhysics_Player::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
  1482. if ( current.movementType != PM_NOCLIP ) {
  1483. current.velocity += impulse * invMass;
  1484. }
  1485. }
  1486. /*
  1487. ================
  1488. idPhysics_Player::IsAtRest
  1489. ================
  1490. */
  1491. bool idPhysics_Player::IsAtRest( void ) const {
  1492. return false;
  1493. }
  1494. /*
  1495. ================
  1496. idPhysics_Player::GetRestStartTime
  1497. ================
  1498. */
  1499. int idPhysics_Player::GetRestStartTime( void ) const {
  1500. return -1;
  1501. }
  1502. /*
  1503. ================
  1504. idPhysics_Player::SaveState
  1505. ================
  1506. */
  1507. void idPhysics_Player::SaveState( void ) {
  1508. saved = current;
  1509. }
  1510. /*
  1511. ================
  1512. idPhysics_Player::RestoreState
  1513. ================
  1514. */
  1515. void idPhysics_Player::RestoreState( void ) {
  1516. current = saved;
  1517. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  1518. EvaluateContacts();
  1519. }
  1520. /*
  1521. ================
  1522. idPhysics_Player::SetOrigin
  1523. ================
  1524. */
  1525. void idPhysics_Player::SetOrigin( const idVec3 &newOrigin, int id ) {
  1526. idVec3 masterOrigin;
  1527. idMat3 masterAxis;
  1528. current.localOrigin = newOrigin;
  1529. if ( masterEntity ) {
  1530. self->GetMasterPosition( masterOrigin, masterAxis );
  1531. current.origin = masterOrigin + newOrigin * masterAxis;
  1532. }
  1533. else {
  1534. current.origin = newOrigin;
  1535. }
  1536. clipModel->Link( gameLocal.clip, self, 0, newOrigin, clipModel->GetAxis() );
  1537. }
  1538. /*
  1539. ================
  1540. idPhysics_Player::GetOrigin
  1541. ================
  1542. */
  1543. const idVec3 & idPhysics_Player::PlayerGetOrigin( void ) const {
  1544. return current.origin;
  1545. }
  1546. /*
  1547. ================
  1548. idPhysics_Player::SetAxis
  1549. ================
  1550. */
  1551. void idPhysics_Player::SetAxis( const idMat3 &newAxis, int id ) {
  1552. clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), newAxis );
  1553. }
  1554. /*
  1555. ================
  1556. idPhysics_Player::Translate
  1557. ================
  1558. */
  1559. void idPhysics_Player::Translate( const idVec3 &translation, int id ) {
  1560. current.localOrigin += translation;
  1561. current.origin += translation;
  1562. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  1563. }
  1564. /*
  1565. ================
  1566. idPhysics_Player::Rotate
  1567. ================
  1568. */
  1569. void idPhysics_Player::Rotate( const idRotation &rotation, int id ) {
  1570. idVec3 masterOrigin;
  1571. idMat3 masterAxis;
  1572. current.origin *= rotation;
  1573. if ( masterEntity ) {
  1574. self->GetMasterPosition( masterOrigin, masterAxis );
  1575. current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
  1576. }
  1577. else {
  1578. current.localOrigin = current.origin;
  1579. }
  1580. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
  1581. }
  1582. /*
  1583. ================
  1584. idPhysics_Player::SetLinearVelocity
  1585. ================
  1586. */
  1587. void idPhysics_Player::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
  1588. current.velocity = newLinearVelocity;
  1589. }
  1590. /*
  1591. ================
  1592. idPhysics_Player::GetLinearVelocity
  1593. ================
  1594. */
  1595. const idVec3 &idPhysics_Player::GetLinearVelocity( int id ) const {
  1596. return current.velocity;
  1597. }
  1598. /*
  1599. ================
  1600. idPhysics_Player::SetPushed
  1601. ================
  1602. */
  1603. void idPhysics_Player::SetPushed( int deltaTime ) {
  1604. idVec3 velocity;
  1605. float d;
  1606. // velocity with which the player is pushed
  1607. velocity = ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC );
  1608. // remove any downward push velocity
  1609. d = velocity * gravityNormal;
  1610. if ( d > 0.0f ) {
  1611. velocity -= d * gravityNormal;
  1612. }
  1613. current.pushVelocity += velocity;
  1614. }
  1615. /*
  1616. ================
  1617. idPhysics_Player::GetPushedLinearVelocity
  1618. ================
  1619. */
  1620. const idVec3 &idPhysics_Player::GetPushedLinearVelocity( const int id ) const {
  1621. return current.pushVelocity;
  1622. }
  1623. /*
  1624. ================
  1625. idPhysics_Player::ClearPushedVelocity
  1626. ================
  1627. */
  1628. void idPhysics_Player::ClearPushedVelocity( void ) {
  1629. current.pushVelocity.Zero();
  1630. }
  1631. /*
  1632. ================
  1633. idPhysics_Player::SetMaster
  1634. the binding is never orientated
  1635. ================
  1636. */
  1637. void idPhysics_Player::SetMaster( idEntity *master, const bool orientated ) {
  1638. idVec3 masterOrigin;
  1639. idMat3 masterAxis;
  1640. if ( master ) {
  1641. if ( !masterEntity ) {
  1642. // transform from world space to master space
  1643. self->GetMasterPosition( masterOrigin, masterAxis );
  1644. current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
  1645. masterEntity = master;
  1646. masterYaw = masterAxis[0].ToYaw();
  1647. }
  1648. ClearContacts();
  1649. }
  1650. else {
  1651. if ( masterEntity ) {
  1652. masterEntity = NULL;
  1653. }
  1654. }
  1655. }
  1656. const float PLAYER_VELOCITY_MAX = 4000;
  1657. const int PLAYER_VELOCITY_TOTAL_BITS = 16;
  1658. const int PLAYER_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( PLAYER_VELOCITY_MAX ) ) + 1;
  1659. const int PLAYER_VELOCITY_MANTISSA_BITS = PLAYER_VELOCITY_TOTAL_BITS - 1 - PLAYER_VELOCITY_EXPONENT_BITS;
  1660. const int PLAYER_MOVEMENT_TYPE_BITS = 3;
  1661. const int PLAYER_MOVEMENT_FLAGS_BITS = 8;
  1662. /*
  1663. ================
  1664. idPhysics_Player::WriteToSnapshot
  1665. ================
  1666. */
  1667. void idPhysics_Player::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1668. msg.WriteFloat( current.origin[0] );
  1669. msg.WriteFloat( current.origin[1] );
  1670. msg.WriteFloat( current.origin[2] );
  1671. msg.WriteFloat( current.velocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1672. msg.WriteFloat( current.velocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1673. msg.WriteFloat( current.velocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1674. msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] );
  1675. msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] );
  1676. msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] );
  1677. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1678. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1679. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1680. msg.WriteDeltaFloat( 0.0f, current.stepUp );
  1681. msg.WriteBits( current.movementType, PLAYER_MOVEMENT_TYPE_BITS );
  1682. msg.WriteBits( current.movementFlags, PLAYER_MOVEMENT_FLAGS_BITS );
  1683. msg.WriteDeltaLong( 0, current.movementTime );
  1684. }
  1685. /*
  1686. ================
  1687. idPhysics_Player::ReadFromSnapshot
  1688. ================
  1689. */
  1690. void idPhysics_Player::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1691. current.origin[0] = msg.ReadFloat();
  1692. current.origin[1] = msg.ReadFloat();
  1693. current.origin[2] = msg.ReadFloat();
  1694. current.velocity[0] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1695. current.velocity[1] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1696. current.velocity[2] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1697. current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] );
  1698. current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] );
  1699. current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] );
  1700. current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1701. current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1702. current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
  1703. current.stepUp = msg.ReadDeltaFloat( 0.0f );
  1704. current.movementType = msg.ReadBits( PLAYER_MOVEMENT_TYPE_BITS );
  1705. current.movementFlags = msg.ReadBits( PLAYER_MOVEMENT_FLAGS_BITS );
  1706. current.movementTime = msg.ReadDeltaLong( 0 );
  1707. if ( clipModel ) {
  1708. clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
  1709. }
  1710. }