Physics_Player.cpp 56 KB

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