doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Physics_Player.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "../Game_local.h"
33 
36 
37 // movement parameters
38 const float PM_STOPSPEED = 100.0f;
39 const float PM_SWIMSCALE = 0.5f;
40 const float PM_LADDERSPEED = 100.0f;
41 const float PM_STEPSCALE = 1.0f;
42 
43 const float PM_ACCELERATE = 10.0f;
44 const float PM_AIRACCELERATE = 1.0f;
46 const float PM_FLYACCELERATE = 8.0f;
47 
48 const float PM_FRICTION = 6.0f;
49 const float PM_AIRFRICTION = 0.0f;
50 const float PM_WATERFRICTION = 1.0f;
51 const float PM_FLYFRICTION = 3.0f;
52 const float PM_NOCLIPFRICTION = 12.0f;
53 
54 const float MIN_WALK_NORMAL = 0.7f; // can't walk on very steep slopes
55 const float OVERCLIP = 1.001f;
56 
57 // movementFlags
58 const int PMF_DUCKED = 1; // set when ducking
59 const int PMF_JUMPED = 2; // set when the player jumped this frame
60 const int PMF_STEPPED_UP = 4; // set when the player stepped up this frame
61 const int PMF_STEPPED_DOWN = 8; // set when the player stepped down this frame
62 const int PMF_JUMP_HELD = 16; // set when jump button is held down
63 const int PMF_TIME_LAND = 32; // movementTime is time before rejump
64 const int PMF_TIME_KNOCKBACK = 64; // movementTime is an air-accelerate only time
65 const int PMF_TIME_WATERJUMP = 128; // movementTime is waterjump
66 const int PMF_ALL_TIMES = (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK);
67 
68 int c_pmove = 0;
69 
70 /*
71 ============
72 idPhysics_Player::CmdScale
73 
74 Returns the scale factor to apply to cmd movements
75 This allows the clients to use axial -127 to 127 values for all directions
76 without getting a sqrt(2) distortion in speed.
77 ============
78 */
79 float idPhysics_Player::CmdScale( const usercmd_t &cmd ) const {
80  int max;
81  float total;
82  float scale;
83  int forwardmove;
84  int rightmove;
85  int upmove;
86 
87  forwardmove = cmd.forwardmove;
88  rightmove = cmd.rightmove;
89 
90  // since the crouch key doubles as downward movement, ignore downward movement when we're on the ground
91  // otherwise crouch speed will be lower than specified
92  if ( walking ) {
93  upmove = 0;
94  } else {
95  upmove = cmd.upmove;
96  }
97 
98  max = abs( forwardmove );
99  if ( abs( rightmove ) > max ) {
100  max = abs( rightmove );
101  }
102  if ( abs( upmove ) > max ) {
103  max = abs( upmove );
104  }
105 
106  if ( !max ) {
107  return 0.0f;
108  }
109 
110  total = idMath::Sqrt( (float) forwardmove * forwardmove + rightmove * rightmove + upmove * upmove );
111  scale = (float) playerSpeed * max / ( 127.0f * total );
112 
113  return scale;
114 }
115 
116 /*
117 ==============
118 idPhysics_Player::Accelerate
119 
120 Handles user intended acceleration
121 ==============
122 */
123 void idPhysics_Player::Accelerate( const idVec3 &wishdir, const float wishspeed, const float accel ) {
124 #if 1
125  // q2 style
126  float addspeed, accelspeed, currentspeed;
127 
128  currentspeed = current.velocity * wishdir;
129  addspeed = wishspeed - currentspeed;
130  if (addspeed <= 0) {
131  return;
132  }
133  accelspeed = accel * frametime * wishspeed;
134  if (accelspeed > addspeed) {
135  accelspeed = addspeed;
136  }
137 
138  current.velocity += accelspeed * wishdir;
139 #else
140  // proper way (avoids strafe jump maxspeed bug), but feels bad
141  idVec3 wishVelocity;
142  idVec3 pushDir;
143  float pushLen;
144  float canPush;
145 
146  wishVelocity = wishdir * wishspeed;
147  pushDir = wishVelocity - current.velocity;
148  pushLen = pushDir.Normalize();
149 
150  canPush = accel * frametime * wishspeed;
151  if (canPush > pushLen) {
152  canPush = pushLen;
153  }
154 
155  current.velocity += canPush * pushDir;
156 #endif
157 }
158 
159 /*
160 ==================
161 idPhysics_Player::SlideMove
162 
163 Returns true if the velocity was clipped in some way
164 ==================
165 */
166 #define MAX_CLIP_PLANES 5
167 
168 bool idPhysics_Player::SlideMove( bool gravity, bool stepUp, bool stepDown, bool push ) {
169  int i, j, k, pushFlags;
170  int bumpcount, numbumps, numplanes;
171  float d, time_left, into, totalMass;
172  idVec3 dir, planes[MAX_CLIP_PLANES];
173  idVec3 end, stepEnd, primal_velocity, endVelocity, endClipVelocity, clipVelocity;
174  trace_t trace, stepTrace, downTrace;
175  bool nearGround, stepped, pushed;
176 
177  numbumps = 4;
178 
179  primal_velocity = current.velocity;
180 
181  if ( gravity ) {
182  endVelocity = current.velocity + gravityVector * frametime;
183  current.velocity = ( current.velocity + endVelocity ) * 0.5f;
184  primal_velocity = endVelocity;
185  if ( groundPlane ) {
186  // slide along the ground plane
188  }
189  }
190  else {
191  endVelocity = current.velocity;
192  }
193 
194  time_left = frametime;
195 
196  // never turn against the ground plane
197  if ( groundPlane ) {
198  numplanes = 1;
199  planes[0] = groundTrace.c.normal;
200  } else {
201  numplanes = 0;
202  }
203 
204  // never turn against original velocity
205  planes[numplanes] = current.velocity;
206  planes[numplanes].Normalize();
207  numplanes++;
208 
209  for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) {
210 
211  // calculate position we are trying to move to
212  end = current.origin + time_left * current.velocity;
213 
214  // see if we can make it there
216 
217  time_left -= time_left * trace.fraction;
218  current.origin = trace.endpos;
219 
220  // if moved the entire distance
221  if ( trace.fraction >= 1.0f ) {
222  break;
223  }
224 
225  stepped = pushed = false;
226 
227  // if we are allowed to step up
228  if ( stepUp ) {
229 
230  nearGround = groundPlane | ladder;
231 
232  if ( !nearGround ) {
233  // trace down to see if the player is near the ground
234  // step checking when near the ground allows the player to move up stairs smoothly while jumping
237  nearGround = ( downTrace.fraction < 1.0f && (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL );
238  }
239 
240  // may only step up if near the ground or on a ladder
241  if ( nearGround ) {
242 
243  // step up
246 
247  // trace along velocity
248  stepEnd = downTrace.endpos + time_left * current.velocity;
249  gameLocal.clip.Translation( stepTrace, downTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
250 
251  // step down
252  stepEnd = stepTrace.endpos + maxStepHeight * gravityNormal;
253  gameLocal.clip.Translation( downTrace, stepTrace.endpos, stepEnd, clipModel, clipModel->GetAxis(), clipMask, self );
254 
255  if ( downTrace.fraction >= 1.0f || (downTrace.c.normal * -gravityNormal) > MIN_WALK_NORMAL ) {
256 
257  // if moved the entire distance
258  if ( stepTrace.fraction >= 1.0f ) {
259  time_left = 0;
260  current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
261  current.origin = downTrace.endpos;
264  break;
265  }
266 
267  // if the move is further when stepping up
268  if ( stepTrace.fraction > trace.fraction ) {
269  time_left -= time_left * stepTrace.fraction;
270  current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
271  current.origin = downTrace.endpos;
274  trace = stepTrace;
275  stepped = true;
276  }
277  }
278  }
279  }
280 
281  // if we can push other entities and not blocked by the world
282  if ( push && trace.c.entityNum != ENTITYNUM_WORLD ) {
283 
285 
286  // clip movement, only push idMoveables, don't push entities the player is standing on
287  // apply impact to pushed objects
289 
290  // clip & push
291  totalMass = gameLocal.push.ClipTranslationalPush( trace, self, pushFlags, end, end - current.origin );
292 
293  if ( totalMass > 0.0f ) {
294  // decrease velocity based on the total mass of the objects being pushed ?
295  current.velocity *= 1.0f - idMath::ClampFloat( 0.0f, 1000.0f, totalMass - 20.0f ) * ( 1.0f / 950.0f );
296  pushed = true;
297  }
298 
299  current.origin = trace.endpos;
300  time_left -= time_left * trace.fraction;
301 
302  // if moved the entire distance
303  if ( trace.fraction >= 1.0f ) {
304  break;
305  }
306  }
307 
308  if ( !stepped ) {
309  // let the entity know about the collision
310  self->Collide( trace, current.velocity );
311  }
312 
313  if ( numplanes >= MAX_CLIP_PLANES ) {
314  // MrElusive: I think we have some relatively high poly LWO models with a lot of slanted tris
315  // where it may hit the max clip planes
317  return true;
318  }
319 
320  //
321  // if this is the same plane we hit before, nudge velocity
322  // out along it, which fixes some epsilon issues with
323  // non-axial planes
324  //
325  for ( i = 0; i < numplanes; i++ ) {
326  if ( ( trace.c.normal * planes[i] ) > 0.999f ) {
327  current.velocity += trace.c.normal;
328  break;
329  }
330  }
331  if ( i < numplanes ) {
332  continue;
333  }
334  planes[numplanes] = trace.c.normal;
335  numplanes++;
336 
337  //
338  // modify velocity so it parallels all of the clip planes
339  //
340 
341  // find a plane that it enters
342  for ( i = 0; i < numplanes; i++ ) {
343  into = current.velocity * planes[i];
344  if ( into >= 0.1f ) {
345  continue; // move doesn't interact with the plane
346  }
347 
348  // slide along the plane
349  clipVelocity = current.velocity;
350  clipVelocity.ProjectOntoPlane( planes[i], OVERCLIP );
351 
352  // slide along the plane
353  endClipVelocity = endVelocity;
354  endClipVelocity.ProjectOntoPlane( planes[i], OVERCLIP );
355 
356  // see if there is a second plane that the new move enters
357  for ( j = 0; j < numplanes; j++ ) {
358  if ( j == i ) {
359  continue;
360  }
361  if ( ( clipVelocity * planes[j] ) >= 0.1f ) {
362  continue; // move doesn't interact with the plane
363  }
364 
365  // try clipping the move to the plane
366  clipVelocity.ProjectOntoPlane( planes[j], OVERCLIP );
367  endClipVelocity.ProjectOntoPlane( planes[j], OVERCLIP );
368 
369  // see if it goes back into the first clip plane
370  if ( ( clipVelocity * planes[i] ) >= 0 ) {
371  continue;
372  }
373 
374  // slide the original velocity along the crease
375  dir = planes[i].Cross( planes[j] );
376  dir.Normalize();
377  d = dir * current.velocity;
378  clipVelocity = d * dir;
379 
380  dir = planes[i].Cross( planes[j] );
381  dir.Normalize();
382  d = dir * endVelocity;
383  endClipVelocity = d * dir;
384 
385  // see if there is a third plane the the new move enters
386  for ( k = 0; k < numplanes; k++ ) {
387  if ( k == i || k == j ) {
388  continue;
389  }
390  if ( ( clipVelocity * planes[k] ) >= 0.1f ) {
391  continue; // move doesn't interact with the plane
392  }
393 
394  // stop dead at a tripple plane interaction
396  return true;
397  }
398  }
399 
400  // if we have fixed all interactions, try another move
401  current.velocity = clipVelocity;
402  endVelocity = endClipVelocity;
403  break;
404  }
405  }
406 
407  // step down
408  if ( stepDown && groundPlane ) {
411  if ( downTrace.fraction > 1e-4f && downTrace.fraction < 1.0f ) {
412  current.stepUp -= ( downTrace.endpos - current.origin ) * gravityNormal;
413  current.origin = downTrace.endpos;
416  }
417  }
418 
419  if ( gravity ) {
420  current.velocity = endVelocity;
421  }
422 
423  // come to a dead stop when the velocity orthogonal to the gravity flipped
425  endClipVelocity = endVelocity - gravityNormal * endVelocity * gravityNormal;
426  if ( clipVelocity * endClipVelocity < 0.0f ) {
427  current.velocity = gravityNormal * current.velocity * gravityNormal;
428  }
429 
430  return (bool)( bumpcount == 0 );
431 }
432 
433 /*
434 ==================
435 idPhysics_Player::Friction
436 
437 Handles both ground friction and water friction
438 ==================
439 */
441  idVec3 vel;
442  float speed, newspeed, control;
443  float drop;
444 
445  vel = current.velocity;
446  if ( walking ) {
447  // ignore slope movement, remove all velocity in gravity direction
448  vel += (vel * gravityNormal) * gravityNormal;
449  }
450 
451  speed = vel.Length();
452  if ( speed < 1.0f ) {
453  // remove all movement orthogonal to gravity, allows for sinking underwater
454  if ( fabs( current.velocity * gravityNormal ) < 1e-5f ) {
456  } else {
458  }
459  // FIXME: still have z friction underwater?
460  return;
461  }
462 
463  drop = 0;
464 
465  // spectator friction
466  if ( current.movementType == PM_SPECTATOR ) {
467  drop += speed * PM_FLYFRICTION * frametime;
468  }
469  // apply ground friction
470  else if ( walking && waterLevel <= WATERLEVEL_FEET ) {
471  // no friction on slick surfaces
473  // if getting knocked back, no friction
475  control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed;
476  drop += control * PM_FRICTION * frametime;
477  }
478  }
479  }
480  // apply water friction even if just wading
481  else if ( waterLevel ) {
482  drop += speed * PM_WATERFRICTION * waterLevel * frametime;
483  }
484  // apply air friction
485  else {
486  drop += speed * PM_AIRFRICTION * frametime;
487  }
488 
489  // scale the velocity
490  newspeed = speed - drop;
491  if (newspeed < 0) {
492  newspeed = 0;
493  }
494  current.velocity *= ( newspeed / speed );
495 }
496 
497 /*
498 ===================
499 idPhysics_Player::WaterJumpMove
500 
501 Flying out of the water
502 ===================
503 */
505 
506  // waterjump has no control, but falls
507  idPhysics_Player::SlideMove( true, true, false, false );
508 
509  // add gravity
511  // if falling down
512  if ( current.velocity * gravityNormal > 0.0f ) {
513  // cancel as soon as we are falling down again
515  current.movementTime = 0;
516  }
517 }
518 
519 /*
520 ===================
521 idPhysics_Player::WaterMove
522 ===================
523 */
525  idVec3 wishvel;
526  float wishspeed;
527  idVec3 wishdir;
528  float scale;
529  float vel;
530 
533  return;
534  }
535 
537 
539 
540  // user intentions
541  if ( !scale ) {
542  wishvel = gravityNormal * 60; // sink towards bottom
543  } else {
544  wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
545  wishvel -= scale * gravityNormal * command.upmove;
546  }
547 
548  wishdir = wishvel;
549  wishspeed = wishdir.Normalize();
550 
551  if ( wishspeed > playerSpeed * PM_SWIMSCALE ) {
552  wishspeed = playerSpeed * PM_SWIMSCALE;
553  }
554 
555  idPhysics_Player::Accelerate( wishdir, wishspeed, PM_WATERACCELERATE );
556 
557  // make sure we can go up slopes easily under water
558  if ( groundPlane && ( current.velocity * groundTrace.c.normal ) < 0.0f ) {
559  vel = current.velocity.Length();
560  // slide along the ground plane
562 
564  current.velocity *= vel;
565  }
566 
567  idPhysics_Player::SlideMove( false, true, false, false );
568 }
569 
570 /*
571 ===================
572 idPhysics_Player::FlyMove
573 ===================
574 */
576  idVec3 wishvel;
577  float wishspeed;
578  idVec3 wishdir;
579  float scale;
580 
581  // normal slowdown
583 
585 
586  if ( !scale ) {
587  wishvel = vec3_origin;
588  } else {
589  wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
590  wishvel -= scale * gravityNormal * command.upmove;
591  }
592 
593  wishdir = wishvel;
594  wishspeed = wishdir.Normalize();
595 
596  idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE );
597 
598  idPhysics_Player::SlideMove( false, false, false, false );
599 }
600 
601 /*
602 ===================
603 idPhysics_Player::AirMove
604 ===================
605 */
607  idVec3 wishvel;
608  idVec3 wishdir;
609  float wishspeed;
610  float scale;
611 
613 
615 
616  // project moves down to flat plane
621 
623  wishvel -= (wishvel * gravityNormal) * gravityNormal;
624  wishdir = wishvel;
625  wishspeed = wishdir.Normalize();
626  wishspeed *= scale;
627 
628  // not on ground, so little effect on velocity
629  idPhysics_Player::Accelerate( wishdir, wishspeed, PM_AIRACCELERATE );
630 
631  // we may have a ground plane that is very steep, even
632  // though we don't have a groundentity
633  // slide along the steep plane
634  if ( groundPlane ) {
636  }
637 
638  idPhysics_Player::SlideMove( true, false, false, false );
639 }
640 
641 /*
642 ===================
643 idPhysics_Player::WalkMove
644 ===================
645 */
647  idVec3 wishvel;
648  idVec3 wishdir;
649  float wishspeed;
650  float scale;
651  float accelerate;
652  idVec3 oldVelocity, vel;
653  float oldVel, newVel;
654 
655  if ( waterLevel > WATERLEVEL_WAIST && ( viewForward * groundTrace.c.normal ) > 0.0f ) {
656  // begin swimming
658  return;
659  }
660 
661  if ( idPhysics_Player::CheckJump() ) {
662  // jumped away
663  if ( waterLevel > WATERLEVEL_FEET ) {
665  }
666  else {
668  }
669  return;
670  }
671 
673 
675 
676  // project moves down to flat plane
679 
680  // project the forward and right directions onto the ground plane
683  //
686 
688  wishdir = wishvel;
689  wishspeed = wishdir.Normalize();
690  wishspeed *= scale;
691 
692  // clamp the speed lower if wading or walking on the bottom
693  if ( waterLevel ) {
694  float waterScale;
695 
696  waterScale = waterLevel / 3.0f;
697  waterScale = 1.0f - ( 1.0f - PM_SWIMSCALE ) * waterScale;
698  if ( wishspeed > playerSpeed * waterScale ) {
699  wishspeed = playerSpeed * waterScale;
700  }
701  }
702 
703  // when a player gets hit, they temporarily lose full control, which allows them to be moved a bit
705  accelerate = PM_AIRACCELERATE;
706  }
707  else {
708  accelerate = PM_ACCELERATE;
709  }
710 
711  idPhysics_Player::Accelerate( wishdir, wishspeed, accelerate );
712 
715  }
716 
717  oldVelocity = current.velocity;
718 
719  // slide along the ground plane
721 
722  // if not clipped into the opposite direction
723  if ( oldVelocity * current.velocity > 0.0f ) {
724  newVel = current.velocity.LengthSqr();
725  if ( newVel > 1.0f ) {
726  oldVel = oldVelocity.LengthSqr();
727  if ( oldVel > 1.0f ) {
728  // don't decrease velocity when going up or down a slope
729  current.velocity *= idMath::Sqrt( oldVel / newVel );
730  }
731  }
732  }
733 
734  // don't do anything if standing still
736  if ( !vel.LengthSqr() ) {
737  return;
738  }
739 
741 
742  idPhysics_Player::SlideMove( false, true, true, true );
743 }
744 
745 /*
746 ==============
747 idPhysics_Player::DeadMove
748 ==============
749 */
751  float forward;
752 
753  if ( !walking ) {
754  return;
755  }
756 
757  // extra friction
758  forward = current.velocity.Length();
759  forward -= 20;
760  if ( forward <= 0 ) {
762  }
763  else {
765  current.velocity *= forward;
766  }
767 }
768 
769 /*
770 ===============
771 idPhysics_Player::NoclipMove
772 ===============
773 */
775  float speed, drop, friction, newspeed, stopspeed;
776  float scale, wishspeed;
777  idVec3 wishdir;
778 
779  // friction
780  speed = current.velocity.Length();
781  if ( speed < 20.0f ) {
783  }
784  else {
785  stopspeed = playerSpeed * 0.3f;
786  if ( speed < stopspeed ) {
787  speed = stopspeed;
788  }
789  friction = PM_NOCLIPFRICTION;
790  drop = speed * friction * frametime;
791 
792  // scale the velocity
793  newspeed = speed - drop;
794  if (newspeed < 0) {
795  newspeed = 0;
796  }
797 
798  current.velocity *= newspeed / speed;
799  }
800 
801  // accelerate
803 
804  wishdir = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
805  wishdir -= scale * gravityNormal * command.upmove;
806  wishspeed = wishdir.Normalize();
807  wishspeed *= scale;
808 
809  idPhysics_Player::Accelerate( wishdir, wishspeed, PM_ACCELERATE );
810 
811  // move
813 }
814 
815 /*
816 ===============
817 idPhysics_Player::SpectatorMove
818 ===============
819 */
821  idVec3 wishvel;
822  float wishspeed;
823  idVec3 wishdir;
824  float scale;
825 
826  trace_t trace;
827  idVec3 end;
828 
829  // fly movement
830 
832 
834 
835  if ( !scale ) {
836  wishvel = vec3_origin;
837  } else {
838  wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
839  }
840 
841  wishdir = wishvel;
842  wishspeed = wishdir.Normalize();
843 
844  idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE );
845 
846  idPhysics_Player::SlideMove( false, false, false, false );
847 }
848 
849 /*
850 ============
851 idPhysics_Player::LadderMove
852 ============
853 */
855  idVec3 wishdir, wishvel, right;
856  float wishspeed, scale;
857  float upscale;
858 
859  // stick to the ladder
860  wishvel = -100.0f * ladderNormal;
862 
863  upscale = (-gravityNormal * viewForward + 0.5f) * 2.5f;
864  if ( upscale > 1.0f ) {
865  upscale = 1.0f;
866  }
867  else if ( upscale < -1.0f ) {
868  upscale = -1.0f;
869  }
870 
872  wishvel = -0.9f * gravityNormal * upscale * scale * (float)command.forwardmove;
873 
874  // strafe
875  if ( command.rightmove ) {
876  // right vector orthogonal to gravity
878  // project right vector into ladder plane
879  right = right - (ladderNormal * right) * ladderNormal;
880  right.Normalize();
881 
882  // if we are looking away from the ladder, reverse the right vector
883  if ( ladderNormal * viewForward > 0.0f ) {
884  right = -right;
885  }
886  wishvel += 2.0f * right * scale * (float) command.rightmove;
887  }
888 
889  // up down movement
890  if ( command.upmove ) {
891  wishvel += -0.5f * gravityNormal * scale * (float) command.upmove;
892  }
893 
894  // do strafe friction
896 
897  // accelerate
898  wishspeed = wishvel.Normalize();
899  idPhysics_Player::Accelerate( wishvel, wishspeed, PM_ACCELERATE );
900 
901  // cap the vertical velocity
902  upscale = current.velocity * -gravityNormal;
903  if ( upscale < -PM_LADDERSPEED ) {
904  current.velocity += gravityNormal * (upscale + PM_LADDERSPEED);
905  }
906  else if ( upscale > PM_LADDERSPEED ) {
907  current.velocity += gravityNormal * (upscale - PM_LADDERSPEED);
908  }
909 
910  if ( (wishvel * gravityNormal) == 0.0f ) {
911  if ( current.velocity * gravityNormal < 0.0f ) {
913  if ( current.velocity * gravityNormal > 0.0f ) {
914  current.velocity -= (gravityNormal * current.velocity) * gravityNormal;
915  }
916  }
917  else {
919  if ( current.velocity * gravityNormal < 0.0f ) {
920  current.velocity -= (gravityNormal * current.velocity) * gravityNormal;
921  }
922  }
923  }
924 
925  idPhysics_Player::SlideMove( false, ( command.forwardmove > 0 ), false, false );
926 }
927 
928 /*
929 =============
930 idPhysics_Player::CorrectAllSolid
931 =============
932 */
933 void idPhysics_Player::CorrectAllSolid( trace_t &trace, int contents ) {
934  if ( debugLevel ) {
935  gameLocal.Printf( "%i:allsolid\n", c_pmove );
936  }
937 
938  // FIXME: jitter around to find a free spot ?
939 
940  if ( trace.fraction >= 1.0f ) {
941  memset( &trace, 0, sizeof( trace ) );
942  trace.endpos = current.origin;
943  trace.endAxis = clipModelAxis;
944  trace.fraction = 0.0f;
945  trace.c.dist = current.origin.z;
946  trace.c.normal.Set( 0, 0, 1 );
947  trace.c.point = current.origin;
948  trace.c.entityNum = ENTITYNUM_WORLD;
949  trace.c.id = 0;
950  trace.c.type = CONTACT_TRMVERTEX;
951  trace.c.material = NULL;
952  trace.c.contents = contents;
953  }
954 }
955 
956 /*
957 =============
958 idPhysics_Player::CheckGround
959 =============
960 */
962  int i, contents;
963  idVec3 point;
964  bool hadGroundContacts;
965 
966  hadGroundContacts = HasGroundContacts();
967 
968  // set the clip model origin before getting the contacts
970 
972 
973  // setup a ground trace from the contacts
976  if ( contacts.Num() ) {
977  groundTrace.fraction = 0.0f;
978  groundTrace.c = contacts[0];
979  for ( i = 1; i < contacts.Num(); i++ ) {
980  groundTrace.c.normal += contacts[i].normal;
981  }
983  } else {
984  groundTrace.fraction = 1.0f;
985  }
986 
988  if ( contents & MASK_SOLID ) {
989  // do something corrective if stuck in solid
991  }
992 
993  // if the trace didn't hit anything, we are in free fall
994  if ( groundTrace.fraction == 1.0f ) {
995  groundPlane = false;
996  walking = false;
998  return;
999  }
1000 
1003 
1004  // check if getting thrown off the ground
1005  if ( (current.velocity * -gravityNormal) > 0.0f && ( current.velocity * groundTrace.c.normal ) > 10.0f ) {
1006  if ( debugLevel ) {
1007  gameLocal.Printf( "%i:kickoff\n", c_pmove );
1008  }
1009 
1010  groundPlane = false;
1011  walking = false;
1012  return;
1013  }
1014 
1015  // slopes that are too steep will not be considered onground
1017  if ( debugLevel ) {
1018  gameLocal.Printf( "%i:steep\n", c_pmove );
1019  }
1020 
1021  // FIXME: if they can't slide down the slope, let them walk (sharp crevices)
1022 
1023  // make sure we don't die from sliding down a steep slope
1024  if ( current.velocity * gravityNormal > 150.0f ) {
1026  }
1027 
1028  groundPlane = true;
1029  walking = false;
1030  return;
1031  }
1032 
1033  groundPlane = true;
1034  walking = true;
1035 
1036  // hitting solid ground will end a waterjump
1039  current.movementTime = 0;
1040  }
1041 
1042  // if the player didn't have ground contacts the previous frame
1043  if ( !hadGroundContacts ) {
1044 
1045  // don't do landing time if we were just going down a slope
1046  if ( (current.velocity * -gravityNormal) < -200.0f ) {
1047  // don't allow another jump for a little while
1049  current.movementTime = 250;
1050  }
1051  }
1052 
1053  // let the entity know about the collision
1054  self->Collide( groundTrace, current.velocity );
1055 
1056  if ( groundEntityPtr.GetEntity() ) {
1057  impactInfo_t info;
1059  if ( info.invMass != 0.0f ) {
1061  }
1062  }
1063 }
1064 
1065 /*
1066 ==============
1067 idPhysics_Player::CheckDuck
1068 
1069 Sets clip model size
1070 ==============
1071 */
1073  trace_t trace;
1074  idVec3 end;
1075  idBounds bounds;
1076  float maxZ;
1077 
1078  if ( current.movementType == PM_DEAD ) {
1079  maxZ = pm_deadheight.GetFloat();
1080  } else {
1081  // stand up when up against a ladder
1082  if ( command.upmove < 0 && !ladder ) {
1083  // duck
1085  } else {
1086  // stand up if possible
1087  if ( current.movementFlags & PMF_DUCKED ) {
1088  // try to stand up
1091  if ( trace.fraction >= 1.0f ) {
1093  }
1094  }
1095  }
1096 
1097  if ( current.movementFlags & PMF_DUCKED ) {
1099  maxZ = pm_crouchheight.GetFloat();
1100  } else {
1101  maxZ = pm_normalheight.GetFloat();
1102  }
1103  }
1104  // if the clipModel height should change
1105  if ( clipModel->GetBounds()[1][2] != maxZ ) {
1106 
1107  bounds = clipModel->GetBounds();
1108  bounds[1][2] = maxZ;
1109  if ( pm_usecylinder.GetBool() ) {
1110  clipModel->LoadModel( idTraceModel( bounds, 8 ) );
1111  } else {
1112  clipModel->LoadModel( idTraceModel( bounds ) );
1113  }
1114  }
1115 }
1116 
1117 /*
1118 ================
1119 idPhysics_Player::CheckLadder
1120 ================
1121 */
1123  idVec3 forward, start, end;
1124  trace_t trace;
1125  float tracedist;
1126 
1127  if ( current.movementTime ) {
1128  return;
1129  }
1130 
1131  // if on the ground moving backwards
1132  if ( walking && command.forwardmove <= 0 ) {
1133  return;
1134  }
1135 
1136  // forward vector orthogonal to gravity
1138  forward.Normalize();
1139 
1140  if ( walking ) {
1141  // don't want to get sucked towards the ladder when still walking
1142  tracedist = 1.0f;
1143  } else {
1144  tracedist = 48.0f;
1145  }
1146 
1147  end = current.origin + tracedist * forward;
1149 
1150  // if near a surface
1151  if ( trace.fraction < 1.0f ) {
1152 
1153  // if a ladder surface
1154  if ( trace.c.material && ( trace.c.material->GetSurfaceFlags() & SURF_LADDER ) ) {
1155 
1156  // check a step height higher
1157  end = current.origin - gravityNormal * ( maxStepHeight * 0.75f );
1159  start = trace.endpos;
1160  end = start + tracedist * forward;
1161  gameLocal.clip.Translation( trace, start, end, clipModel, clipModel->GetAxis(), clipMask, self );
1162 
1163  // if also near a surface a step height higher
1164  if ( trace.fraction < 1.0f ) {
1165 
1166  // if it also is a ladder surface
1167  if ( trace.c.material && trace.c.material->GetSurfaceFlags() & SURF_LADDER ) {
1168  ladder = true;
1169  ladderNormal = trace.c.normal;
1170  }
1171  }
1172  }
1173  }
1174 }
1175 
1176 /*
1177 =============
1178 idPhysics_Player::CheckJump
1179 =============
1180 */
1182  idVec3 addVelocity;
1183 
1184  if ( command.upmove < 10 ) {
1185  // not holding jump
1186  return false;
1187  }
1188 
1189  // must wait for jump to be released
1191  return false;
1192  }
1193 
1194  // don't jump if we can't stand up
1195  if ( current.movementFlags & PMF_DUCKED ) {
1196  return false;
1197  }
1198 
1199  groundPlane = false; // jumping away
1200  walking = false;
1202 
1203  addVelocity = 2.0f * maxJumpHeight * -gravityVector;
1204  addVelocity *= idMath::Sqrt( addVelocity.Normalize() );
1205  current.velocity += addVelocity;
1206 
1207  return true;
1208 }
1209 
1210 /*
1211 =============
1212 idPhysics_Player::CheckWaterJump
1213 =============
1214 */
1216  idVec3 spot;
1217  int cont;
1218  idVec3 flatforward;
1219 
1220  if ( current.movementTime ) {
1221  return false;
1222  }
1223 
1224  // check for water jump
1225  if ( waterLevel != WATERLEVEL_WAIST ) {
1226  return false;
1227  }
1228 
1229  flatforward = viewForward - (viewForward * gravityNormal) * gravityNormal;
1230  flatforward.Normalize();
1231 
1232  spot = current.origin + 30.0f * flatforward;
1233  spot -= 4.0f * gravityNormal;
1234  cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self );
1235  if ( !(cont & CONTENTS_SOLID) ) {
1236  return false;
1237  }
1238 
1239  spot -= 16.0f * gravityNormal;
1240  cont = gameLocal.clip.Contents( spot, NULL, mat3_identity, -1, self );
1241  if ( cont ) {
1242  return false;
1243  }
1244 
1245  // jump out of water
1246  current.velocity = 200.0f * viewForward - 350.0f * gravityNormal;
1248  current.movementTime = 2000;
1249 
1250  return true;
1251 }
1252 
1253 /*
1254 =============
1255 idPhysics_Player::SetWaterLevel
1256 =============
1257 */
1259  idVec3 point;
1260  idBounds bounds;
1261  int contents;
1262 
1263  //
1264  // get waterlevel, accounting for ducking
1265  //
1267  waterType = 0;
1268 
1269  bounds = clipModel->GetBounds();
1270 
1271  // check at feet level
1272  point = current.origin - ( bounds[0][2] + 1.0f ) * gravityNormal;
1273  contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
1274  if ( contents & MASK_WATER ) {
1275 
1276  waterType = contents;
1278 
1279  // check at waist level
1280  point = current.origin - ( bounds[1][2] - bounds[0][2] ) * 0.5f * gravityNormal;
1281  contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
1282  if ( contents & MASK_WATER ) {
1283 
1285 
1286  // check at head level
1287  point = current.origin - ( bounds[1][2] - 1.0f ) * gravityNormal;
1288  contents = gameLocal.clip.Contents( point, NULL, mat3_identity, -1, self );
1289  if ( contents & MASK_WATER ) {
1291  }
1292  }
1293  }
1294 }
1295 
1296 /*
1297 ================
1298 idPhysics_Player::DropTimers
1299 ================
1300 */
1302  // drop misc timing counter
1303  if ( current.movementTime ) {
1304  if ( framemsec >= current.movementTime ) {
1306  current.movementTime = 0;
1307  }
1308  else {
1310  }
1311  }
1312 }
1313 
1314 /*
1315 ================
1316 idPhysics_Player::MovePlayer
1317 ================
1318 */
1320 
1321  // this counter lets us debug movement problems with a journal
1322  // by setting a conditional breakpoint for the previous frame
1323  c_pmove++;
1324 
1325  walking = false;
1326  groundPlane = false;
1327  ladder = false;
1328 
1329  // determine the time
1330  framemsec = msec;
1331  frametime = framemsec * 0.001f;
1332 
1333  // default speed
1335 
1336  // remove jumped and stepped up flag
1338  current.stepUp = 0.0f;
1339 
1340  if ( command.upmove < 10 ) {
1341  // not holding jump
1343  }
1344 
1345  // if no movement at all
1346  if ( current.movementType == PM_FREEZE ) {
1347  return;
1348  }
1349 
1350  // move the player velocity into the frame of a pusher
1352 
1353  // view vectors
1357  viewRight.Normalize();
1358 
1359  // fly in spectator mode
1360  if ( current.movementType == PM_SPECTATOR ) {
1361  SpectatorMove();
1363  return;
1364  }
1365 
1366  // special no clip mode
1367  if ( current.movementType == PM_NOCLIP ) {
1370  return;
1371  }
1372 
1373  // no control when dead
1374  if ( current.movementType == PM_DEAD ) {
1375  command.forwardmove = 0;
1376  command.rightmove = 0;
1377  command.upmove = 0;
1378  }
1379 
1380  // set watertype and waterlevel
1382 
1383  // check for ground
1385 
1386  // check if up against a ladder
1388 
1389  // set clip model size
1391 
1392  // handle timers
1394 
1395  // move
1396  if ( current.movementType == PM_DEAD ) {
1397  // dead
1399  }
1400  else if ( ladder ) {
1401  // going up or down a ladder
1403  }
1404  else if ( current.movementFlags & PMF_TIME_WATERJUMP ) {
1405  // jumping out of water
1407  }
1408  else if ( waterLevel > 1 ) {
1409  // swimming
1411  }
1412  else if ( walking ) {
1413  // walking on ground
1415  }
1416  else {
1417  // airborne
1419  }
1420 
1421  // set watertype, waterlevel and groundentity
1424 
1425  // move the player velocity back into the world frame
1428 }
1429 
1430 /*
1431 ================
1432 idPhysics_Player::GetWaterLevel
1433 ================
1434 */
1436  return waterLevel;
1437 }
1438 
1439 /*
1440 ================
1441 idPhysics_Player::GetWaterType
1442 ================
1443 */
1445  return waterType;
1446 }
1447 
1448 /*
1449 ================
1450 idPhysics_Player::HasJumped
1451 ================
1452 */
1453 bool idPhysics_Player::HasJumped( void ) const {
1454  return ( ( current.movementFlags & PMF_JUMPED ) != 0 );
1455 }
1456 
1457 /*
1458 ================
1459 idPhysics_Player::HasSteppedUp
1460 ================
1461 */
1463  return ( ( current.movementFlags & ( PMF_STEPPED_UP | PMF_STEPPED_DOWN ) ) != 0 );
1464 }
1465 
1466 /*
1467 ================
1468 idPhysics_Player::GetStepUp
1469 ================
1470 */
1471 float idPhysics_Player::GetStepUp( void ) const {
1472  return current.stepUp;
1473 }
1474 
1475 /*
1476 ================
1477 idPhysics_Player::IsCrouching
1478 ================
1479 */
1480 bool idPhysics_Player::IsCrouching( void ) const {
1481  return ( ( current.movementFlags & PMF_DUCKED ) != 0 );
1482 }
1483 
1484 /*
1485 ================
1486 idPhysics_Player::OnLadder
1487 ================
1488 */
1489 bool idPhysics_Player::OnLadder( void ) const {
1490  return ladder;
1491 }
1492 
1493 /*
1494 ================
1495 idPhysics_Player::idPhysics_Player
1496 ================
1497 */
1499  debugLevel = false;
1500  clipModel = NULL;
1501  clipMask = 0;
1502  memset( &current, 0, sizeof( current ) );
1503  saved = current;
1504  walkSpeed = 0;
1505  crouchSpeed = 0;
1506  maxStepHeight = 0;
1507  maxJumpHeight = 0;
1508  memset( &command, 0, sizeof( command ) );
1509  viewAngles.Zero();
1510  framemsec = 0;
1511  frametime = 0;
1512  playerSpeed = 0;
1513  viewForward.Zero();
1514  viewRight.Zero();
1515  walking = false;
1516  groundPlane = false;
1517  memset( &groundTrace, 0, sizeof( groundTrace ) );
1518  groundMaterial = NULL;
1519  ladder = false;
1520  ladderNormal.Zero();
1522  waterType = 0;
1523 }
1524 
1525 /*
1526 ================
1527 idPhysics_Player_SavePState
1528 ================
1529 */
1530 void idPhysics_Player_SavePState( idSaveGame *savefile, const playerPState_t &state ) {
1531  savefile->WriteVec3( state.origin );
1532  savefile->WriteVec3( state.velocity );
1533  savefile->WriteVec3( state.localOrigin );
1534  savefile->WriteVec3( state.pushVelocity );
1535  savefile->WriteFloat( state.stepUp );
1536  savefile->WriteInt( state.movementType );
1537  savefile->WriteInt( state.movementFlags );
1538  savefile->WriteInt( state.movementTime );
1539 }
1540 
1541 /*
1542 ================
1543 idPhysics_Player_RestorePState
1544 ================
1545 */
1547  savefile->ReadVec3( state.origin );
1548  savefile->ReadVec3( state.velocity );
1549  savefile->ReadVec3( state.localOrigin );
1550  savefile->ReadVec3( state.pushVelocity );
1551  savefile->ReadFloat( state.stepUp );
1552  savefile->ReadInt( state.movementType );
1553  savefile->ReadInt( state.movementFlags );
1554  savefile->ReadInt( state.movementTime );
1555 }
1556 
1557 /*
1558 ================
1559 idPhysics_Player::Save
1560 ================
1561 */
1562 void idPhysics_Player::Save( idSaveGame *savefile ) const {
1563 
1564  idPhysics_Player_SavePState( savefile, current );
1565  idPhysics_Player_SavePState( savefile, saved );
1566 
1567  savefile->WriteFloat( walkSpeed );
1568  savefile->WriteFloat( crouchSpeed );
1569  savefile->WriteFloat( maxStepHeight );
1570  savefile->WriteFloat( maxJumpHeight );
1571  savefile->WriteInt( debugLevel );
1572 
1573  savefile->WriteUsercmd( command );
1574  savefile->WriteAngles( viewAngles );
1575 
1576  savefile->WriteInt( framemsec );
1577  savefile->WriteFloat( frametime );
1578  savefile->WriteFloat( playerSpeed );
1579  savefile->WriteVec3( viewForward );
1580  savefile->WriteVec3( viewRight );
1581 
1582  savefile->WriteBool( walking );
1583  savefile->WriteBool( groundPlane );
1584  savefile->WriteTrace( groundTrace );
1585  savefile->WriteMaterial( groundMaterial );
1586 
1587  savefile->WriteBool( ladder );
1588  savefile->WriteVec3( ladderNormal );
1589 
1590  savefile->WriteInt( (int)waterLevel );
1591  savefile->WriteInt( waterType );
1592 }
1593 
1594 /*
1595 ================
1596 idPhysics_Player::Restore
1597 ================
1598 */
1600 
1603 
1604  savefile->ReadFloat( walkSpeed );
1605  savefile->ReadFloat( crouchSpeed );
1606  savefile->ReadFloat( maxStepHeight );
1607  savefile->ReadFloat( maxJumpHeight );
1608  savefile->ReadInt( debugLevel );
1609 
1610  savefile->ReadUsercmd( command );
1611  savefile->ReadAngles( viewAngles );
1612 
1613  savefile->ReadInt( framemsec );
1614  savefile->ReadFloat( frametime );
1615  savefile->ReadFloat( playerSpeed );
1616  savefile->ReadVec3( viewForward );
1617  savefile->ReadVec3( viewRight );
1618 
1619  savefile->ReadBool( walking );
1620  savefile->ReadBool( groundPlane );
1621  savefile->ReadTrace( groundTrace );
1622  savefile->ReadMaterial( groundMaterial );
1623 
1624  savefile->ReadBool( ladder );
1625  savefile->ReadVec3( ladderNormal );
1626 
1627  savefile->ReadInt( (int &)waterLevel );
1628  savefile->ReadInt( waterType );
1629 }
1630 
1631 /*
1632 ================
1633 idPhysics_Player::SetPlayerInput
1634 ================
1635 */
1636 void idPhysics_Player::SetPlayerInput( const usercmd_t &cmd, const idAngles &newViewAngles ) {
1637  command = cmd;
1638  viewAngles = newViewAngles; // can't use cmd.angles cause of the delta_angles
1639 }
1640 
1641 /*
1642 ================
1643 idPhysics_Player::SetSpeed
1644 ================
1645 */
1646 void idPhysics_Player::SetSpeed( const float newWalkSpeed, const float newCrouchSpeed ) {
1647  walkSpeed = newWalkSpeed;
1648  crouchSpeed = newCrouchSpeed;
1649 }
1650 
1651 /*
1652 ================
1653 idPhysics_Player::SetMaxStepHeight
1654 ================
1655 */
1656 void idPhysics_Player::SetMaxStepHeight( const float newMaxStepHeight ) {
1657  maxStepHeight = newMaxStepHeight;
1658 }
1659 
1660 /*
1661 ================
1662 idPhysics_Player::GetMaxStepHeight
1663 ================
1664 */
1666  return maxStepHeight;
1667 }
1668 
1669 /*
1670 ================
1671 idPhysics_Player::SetMaxJumpHeight
1672 ================
1673 */
1674 void idPhysics_Player::SetMaxJumpHeight( const float newMaxJumpHeight ) {
1675  maxJumpHeight = newMaxJumpHeight;
1676 }
1677 
1678 /*
1679 ================
1680 idPhysics_Player::SetMovementType
1681 ================
1682 */
1685 }
1686 
1687 /*
1688 ================
1689 idPhysics_Player::SetKnockBack
1690 ================
1691 */
1692 void idPhysics_Player::SetKnockBack( const int knockBackTime ) {
1693  if ( current.movementTime ) {
1694  return;
1695  }
1697  current.movementTime = knockBackTime;
1698 }
1699 
1700 /*
1701 ================
1702 idPhysics_Player::SetDebugLevel
1703 ================
1704 */
1706  debugLevel = set;
1707 }
1708 
1709 /*
1710 ================
1711 idPhysics_Player::Evaluate
1712 ================
1713 */
1714 bool idPhysics_Player::Evaluate( int timeStepMSec, int endTimeMSec ) {
1715  idVec3 masterOrigin, oldOrigin;
1716  idMat3 masterAxis;
1717 
1719  waterType = 0;
1720  oldOrigin = current.origin;
1721 
1722  clipModel->Unlink();
1723 
1724  // if bound to a master
1725  if ( masterEntity ) {
1726  self->GetMasterPosition( masterOrigin, masterAxis );
1727  current.origin = masterOrigin + current.localOrigin * masterAxis;
1729  current.velocity = ( current.origin - oldOrigin ) / ( timeStepMSec * 0.001f );
1731  masterYaw = masterAxis[0].ToYaw();
1733  return true;
1734  }
1735 
1737 
1738  idPhysics_Player::MovePlayer( timeStepMSec );
1739 
1741 
1742  if ( IsOutsideWorld() ) {
1743  gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
1744  }
1745 
1746  return true; //( current.origin != oldOrigin );
1747 }
1748 
1749 /*
1750 ================
1751 idPhysics_Player::UpdateTime
1752 ================
1753 */
1754 void idPhysics_Player::UpdateTime( int endTimeMSec ) {
1755 }
1756 
1757 /*
1758 ================
1759 idPhysics_Player::GetTime
1760 ================
1761 */
1762 int idPhysics_Player::GetTime( void ) const {
1763  return gameLocal.time;
1764 }
1765 
1766 /*
1767 ================
1768 idPhysics_Player::GetImpactInfo
1769 ================
1770 */
1771 void idPhysics_Player::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
1772  info->invMass = invMass;
1773  info->invInertiaTensor.Zero();
1774  info->position.Zero();
1775  info->velocity = current.velocity;
1776 }
1777 
1778 /*
1779 ================
1780 idPhysics_Player::ApplyImpulse
1781 ================
1782 */
1783 void idPhysics_Player::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
1784  if ( current.movementType != PM_NOCLIP ) {
1785  current.velocity += impulse * invMass;
1786  }
1787 }
1788 
1789 /*
1790 ================
1791 idPhysics_Player::IsAtRest
1792 ================
1793 */
1794 bool idPhysics_Player::IsAtRest( void ) const {
1795  return false;
1796 }
1797 
1798 /*
1799 ================
1800 idPhysics_Player::GetRestStartTime
1801 ================
1802 */
1804  return -1;
1805 }
1806 
1807 /*
1808 ================
1809 idPhysics_Player::SaveState
1810 ================
1811 */
1813  saved = current;
1814 }
1815 
1816 /*
1817 ================
1818 idPhysics_Player::RestoreState
1819 ================
1820 */
1822  current = saved;
1823 
1825 
1826  EvaluateContacts();
1827 }
1828 
1829 /*
1830 ================
1831 idPhysics_Player::SetOrigin
1832 ================
1833 */
1834 void idPhysics_Player::SetOrigin( const idVec3 &newOrigin, int id ) {
1835  idVec3 masterOrigin;
1836  idMat3 masterAxis;
1837 
1838  current.localOrigin = newOrigin;
1839  if ( masterEntity ) {
1840  self->GetMasterPosition( masterOrigin, masterAxis );
1841  current.origin = masterOrigin + newOrigin * masterAxis;
1842  }
1843  else {
1844  current.origin = newOrigin;
1845  }
1846 
1847  clipModel->Link( gameLocal.clip, self, 0, newOrigin, clipModel->GetAxis() );
1848 }
1849 
1850 /*
1851 ================
1852 idPhysics_Player::GetOrigin
1853 ================
1854 */
1856  return current.origin;
1857 }
1858 
1859 /*
1860 ================
1861 idPhysics_Player::SetAxis
1862 ================
1863 */
1864 void idPhysics_Player::SetAxis( const idMat3 &newAxis, int id ) {
1865  clipModel->Link( gameLocal.clip, self, 0, clipModel->GetOrigin(), newAxis );
1866 }
1867 
1868 /*
1869 ================
1870 idPhysics_Player::Translate
1871 ================
1872 */
1873 void idPhysics_Player::Translate( const idVec3 &translation, int id ) {
1874 
1875  current.localOrigin += translation;
1876  current.origin += translation;
1877 
1879 }
1880 
1881 /*
1882 ================
1883 idPhysics_Player::Rotate
1884 ================
1885 */
1886 void idPhysics_Player::Rotate( const idRotation &rotation, int id ) {
1887  idVec3 masterOrigin;
1888  idMat3 masterAxis;
1889 
1890  current.origin *= rotation;
1891  if ( masterEntity ) {
1892  self->GetMasterPosition( masterOrigin, masterAxis );
1893  current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
1894  }
1895  else {
1897  }
1898 
1899  clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
1900 }
1901 
1902 /*
1903 ================
1904 idPhysics_Player::SetLinearVelocity
1905 ================
1906 */
1907 void idPhysics_Player::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
1908  current.velocity = newLinearVelocity;
1909 }
1910 
1911 /*
1912 ================
1913 idPhysics_Player::GetLinearVelocity
1914 ================
1915 */
1917  return current.velocity;
1918 }
1919 
1920 /*
1921 ================
1922 idPhysics_Player::SetPushed
1923 ================
1924 */
1925 void idPhysics_Player::SetPushed( int deltaTime ) {
1926  idVec3 velocity;
1927  float d;
1928 
1929  // velocity with which the player is pushed
1930  velocity = ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC );
1931 
1932  // remove any downward push velocity
1933  d = velocity * gravityNormal;
1934  if ( d > 0.0f ) {
1935  velocity -= d * gravityNormal;
1936  }
1937 
1938  current.pushVelocity += velocity;
1939 }
1940 
1941 /*
1942 ================
1943 idPhysics_Player::GetPushedLinearVelocity
1944 ================
1945 */
1947  return current.pushVelocity;
1948 }
1949 
1950 /*
1951 ================
1952 idPhysics_Player::ClearPushedVelocity
1953 ================
1954 */
1957 }
1958 
1959 /*
1960 ================
1961 idPhysics_Player::SetMaster
1962 
1963  the binding is never orientated
1964 ================
1965 */
1966 void idPhysics_Player::SetMaster( idEntity *master, const bool orientated ) {
1967  idVec3 masterOrigin;
1968  idMat3 masterAxis;
1969 
1970  if ( master ) {
1971  if ( !masterEntity ) {
1972  // transform from world space to master space
1973  self->GetMasterPosition( masterOrigin, masterAxis );
1974  current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
1975  masterEntity = master;
1976  masterYaw = masterAxis[0].ToYaw();
1977  }
1978  ClearContacts();
1979  }
1980  else {
1981  if ( masterEntity ) {
1982  masterEntity = NULL;
1983  }
1984  }
1985 }
1986 
1987 const float PLAYER_VELOCITY_MAX = 4000;
1993 
1994 /*
1995 ================
1996 idPhysics_Player::WriteToSnapshot
1997 ================
1998 */
2000  msg.WriteFloat( current.origin[0] );
2001  msg.WriteFloat( current.origin[1] );
2002  msg.WriteFloat( current.origin[2] );
2003  msg.WriteFloat( current.velocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2004  msg.WriteFloat( current.velocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2005  msg.WriteFloat( current.velocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2009  msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2010  msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2011  msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2012  msg.WriteDeltaFloat( 0.0f, current.stepUp );
2013  msg.WriteBits( current.movementType, PLAYER_MOVEMENT_TYPE_BITS );
2014  msg.WriteBits( current.movementFlags, PLAYER_MOVEMENT_FLAGS_BITS );
2016 }
2017 
2018 /*
2019 ================
2020 idPhysics_Player::ReadFromSnapshot
2021 ================
2022 */
2024  current.origin[0] = msg.ReadFloat();
2025  current.origin[1] = msg.ReadFloat();
2026  current.origin[2] = msg.ReadFloat();
2027  current.velocity[0] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2028  current.velocity[1] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2029  current.velocity[2] = msg.ReadFloat( PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2033  current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2034  current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2035  current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, PLAYER_VELOCITY_EXPONENT_BITS, PLAYER_VELOCITY_MANTISSA_BITS );
2036  current.stepUp = msg.ReadDeltaFloat( 0.0f );
2037  current.movementType = msg.ReadBits( PLAYER_MOVEMENT_TYPE_BITS );
2038  current.movementFlags = msg.ReadBits( PLAYER_MOVEMENT_FLAGS_BITS );
2039  current.movementTime = msg.ReadDeltaLong( 0 );
2040 
2041  if ( clipModel ) {
2043  }
2044 }
2045 
void WaterJumpMove(void)
int GetWaterType(void) const
const float PM_WATERACCELERATE
playerPState_t saved
void WriteTrace(const trace_t &trace)
Definition: SaveGame.cpp:694
idCVar pm_usecylinder("pm_usecylinder","0", CVAR_GAME|CVAR_NETWORKSYNC|CVAR_BOOL,"use a cylinder approximation instead of a bounding box for player collision detection")
float Normalize(void)
Definition: Vector.h:646
void Link(idClip &clp)
Definition: Clip.cpp:545
idCVar pm_crouchheight("pm_crouchheight","38", CVAR_GAME|CVAR_NETWORKSYNC|CVAR_FLOAT,"height of player's bounding box while crouched")
idMat3 mat3_identity(idVec3(1, 0, 0), idVec3(0, 1, 0), idVec3(0, 0, 1))
const idMaterial * groundMaterial
void ReadMaterial(const idMaterial *&material)
Definition: SaveGame.cpp:1132
void CorrectAllSolid(trace_t &trace, int contents)
idClip clip
Definition: Game_local.h:296
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
#define PUSHFL_CLIP
Definition: Push.h:42
bool EvaluateContacts(void)
type * GetEntity(void) const
Definition: Game_local.h:695
waterLevel_t GetWaterLevel(void) const
float GetFloat(void) const
Definition: CVarSystem.h:144
#define const
Definition: getdate.c:251
const int PLAYER_VELOCITY_TOTAL_BITS
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
const int PMF_TIME_KNOCKBACK
idMat3 Transpose(void) const
Definition: Matrix.h:677
void InitSavingPushedEntityPositions(void)
Definition: Push.cpp:40
int GetTime(void) const
void Set(const float x, const float y, const float z)
Definition: Vector.h:409
bool IsOutsideWorld(void) const
const idMat3 & GetAxis(void) const
Definition: Clip.h:210
float z
Definition: Vector.h:320
const float PM_SWIMSCALE
#define MASK_SOLID
Definition: Game_local.h:735
void WriteBits(int value, int numBits)
Definition: BitMsg.cpp:648
static float ClampFloat(float min, float max, float value)
Definition: Math.h:893
const idVec3 & GetPushedLinearVelocity(const int id=0) const
#define MASK_WATER
Definition: Game_local.h:739
Definition: Vector.h:316
const int PMF_TIME_LAND
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
float ClipTranslationalPush(trace_t &results, idEntity *pusher, const int flags, const idVec3 &newOrigin, const idVec3 &move)
Definition: Push.cpp:1042
static float Sqrt(float x)
Definition: Math.h:302
void SpectatorMove(void)
#define PUSHFL_NOGROUNDENTITIES
Definition: Push.h:41
contactType_t type
const idVec3 & GetOrigin(void) const
Definition: Clip.h:206
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
#define MAX_CLIP_PLANES
void SetWaterLevel(void)
float GetStepUp(void) const
void SetPlayerInput(const usercmd_t &cmd, const idAngles &newViewAngles)
void WriteFloat(float f)
Definition: BitMsg.h:558
virtual void ApplyImpulse(idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse)
Definition: Entity.cpp:2887
GLdouble right
Definition: qgl.h:273
idVec3 Cross(const idVec3 &a) const
Definition: Vector.h:619
int ReadBits(int numBits) const
Definition: BitMsg.cpp:709
void ReadUsercmd(usercmd_t &usercmd)
Definition: SaveGame.cpp:1429
int i
Definition: process.py:33
bool HasJumped(void) const
contactInfo_t c
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
void SetDebugLevel(bool set)
idAngles & Zero(void)
Definition: Angles.h:126
void WriteMaterial(const idMaterial *material)
Definition: SaveGame.cpp:380
float fraction
idVec3 endpos
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
float CmdScale(const usercmd_t &cmd) const
void WriteUsercmd(const usercmd_t &usercmd)
Definition: SaveGame.cpp:653
idEntity * self
Definition: Physics_Base.h:145
const float PLAYER_VELOCITY_MAX
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
#define PUSHFL_ONLYMOVEABLE
Definition: Push.h:40
void Translate(const idVec3 &translation, int id=-1)
void ReadTrace(trace_t &trace)
Definition: SaveGame.cpp:1470
waterLevel_t
bool Evaluate(int timeStepMSec, int endTimeMSec)
const float PM_AIRACCELERATE
float invMass
Definition: Physics.h:69
const idMaterial * material
idCVar pm_normalheight("pm_normalheight","74", CVAR_GAME|CVAR_NETWORKSYNC|CVAR_FLOAT,"height of player's bounding box while standing")
void SetLinearVelocity(const idVec3 &newLinearVelocity, int id=0)
const int PMF_STEPPED_UP
const int PLAYER_MOVEMENT_FLAGS_BITS
void SetMaxStepHeight(const float newMaxStepHeight)
int GetRestStartTime(void) const
const int PMF_TIME_WATERJUMP
idVec3 velocity
Definition: Physics.h:72
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
float Length(void) const
Definition: Vector.h:631
void WriteDeltaFloat(float oldValue, float newValue)
Definition: BitMsg.h:595
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
bool OnLadder(void) const
const int PMF_DUCKED
GLuint GLuint end
Definition: glext.h:2845
virtual void GetImpactInfo(idEntity *ent, int id, const idVec3 &point, impactInfo_t *info)
Definition: Entity.cpp:2878
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
const int PMF_JUMPED
idEntity * masterEntity
const float PM_LADDERSPEED
idMat3 clipModelAxis
Definition: Physics_Actor.h:98
#define NULL
Definition: Lib.h:88
void SetPushed(int deltaTime)
const idVec3 & GetLinearVelocity(int id=0) const
const idBounds & GetBounds(void) const
Definition: Clip.h:198
const int PLAYER_VELOCITY_MANTISSA_BITS
const float PM_WATERFRICTION
signed char upmove
Definition: UsercmdGen.h:97
const int PLAYER_MOVEMENT_TYPE_BITS
const int GetSurfaceFlags(void) const
Definition: Material.h:500
idMat3 endAxis
float GetMaxStepHeight(void) const
float ReadDeltaFloat(float oldValue) const
Definition: BitMsg.h:664
const int PLAYER_VELOCITY_EXPONENT_BITS
idGameLocal gameLocal
Definition: Game_local.cpp:64
float LengthSqr(void) const
Definition: Vector.h:635
#define END_CLASS
Definition: Class.h:54
void Rotate(const idRotation &rotation, int id=-1)
const float PM_NOCLIPFRICTION
const float PM_AIRFRICTION
static int BitsForInteger(int i)
Definition: Math.h:727
#define PUSHFL_APPLYIMPULSE
Definition: Push.h:44
const float MIN_WALK_NORMAL
const idVec3 & PlayerGetOrigin(void) const
const float PM_FLYACCELERATE
void GetImpactInfo(const int id, const idVec3 &point, impactInfo_t *info) const
void ApplyImpulse(const int id, const idVec3 &point, const idVec3 &impulse)
END_CLASS const float PM_STOPSPEED
const char * ToString(int precision=2) const
Definition: Vector.cpp:221
void WriteInt(const int value)
Definition: SaveGame.cpp:168
void Zero(void)
Definition: Matrix.h:587
idList< contactInfo_t > contacts
Definition: Physics_Base.h:149
idEntity * entities[MAX_GENTITIES]
Definition: Game_local.h:275
idCVar pm_deadheight("pm_deadheight","20", CVAR_GAME|CVAR_NETWORKSYNC|CVAR_FLOAT,"height of player's bounding box while dead")
idPush push
Definition: Game_local.h:297
idVec3 position
Definition: Physics.h:71
void idPhysics_Player_RestorePState(idRestoreGame *savefile, playerPState_t &state)
Definition: Matrix.h:333
void Restore(idRestoreGame *savefile)
idVec3 gravityNormal
Definition: Physics_Base.h:148
void ProjectOntoPlane(const idVec3 &normal, const float overBounce=1.0f)
Definition: Vector.h:769
void WriteAngles(const idAngles &angles)
Definition: SaveGame.cpp:318
int c_pmove
void CheckGround(void)
bool CheckWaterJump(void)
bool GetBool(void) const
Definition: CVarSystem.h:142
void UpdateTime(int endTimeMSec)
tuple f
Definition: idal.py:89
void Accelerate(const idVec3 &wishdir, const float wishspeed, const float accel)
#define ENTITYNUM_WORLD
Definition: Game_local.h:85
bool LoadModel(const char *name)
Definition: Clip.cpp:215
const idMat3 & ToMat3(void) const
Definition: Rotation.cpp:60
idMat3 invInertiaTensor
Definition: Physics.h:70
int Num(void) const
Definition: List.h:265
bool IsAtRest(void) const
void idPhysics_Player_SavePState(idSaveGame *savefile, const playerPState_t &state)
signed char forwardmove
Definition: UsercmdGen.h:95
bool IsCrouching(void) const
int ReadDeltaLong(int oldValue) const
Definition: BitMsg.h:660
void SetSpeed(const float newWalkSpeed, const float newCrouchSpeed)
int Contents(const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1429
#define CLASS_DECLARATION(nameofsuperclass, nameofclass)
Definition: Class.h:110
pmtype_t
const int PMF_JUMP_HELD
void WriteDeltaLong(int oldValue, int newValue)
Definition: BitMsg.h:591
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
idEntityPtr< idEntity > groundEntityPtr
const char * c_str(void) const
Definition: Str.h:487
void MovePlayer(int msec)
void ClearContacts(void)
void ClearPushedVelocity(void)
void SetOrigin(const idVec3 &newOrigin, int id=-1)
void ReadAngles(idAngles &angles)
Definition: SaveGame.cpp:1073
idVec3 gravityVector
Definition: Physics_Base.h:147
idClipModel * clipModel
Definition: Physics_Actor.h:97
const float PM_ACCELERATE
float ReadFloat(void) const
Definition: BitMsg.h:625
void ReadFromSnapshot(const idBitMsgDelta &msg)
const float PM_FRICTION
waterLevel_t waterLevel
void SetMovementType(const pmtype_t type)
playerPState_t current
bool HasGroundContacts(void) const
void WriteToSnapshot(idBitMsgDelta &msg) const
void ActivateContactEntities(void)
GLint j
Definition: qgl.h:264
const int PMF_ALL_TIMES
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
const float OVERCLIP
bool Translation(trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1056
const float PM_FLYFRICTION
#define max(x, y)
Definition: os.h:70
signed char rightmove
Definition: UsercmdGen.h:96
void SetAxis(const idMat3 &newAxis, int id=-1)
idStr name
Definition: Entity.h:121
void ToVectors(idVec3 *forward, idVec3 *right=NULL, idVec3 *up=NULL) const
Definition: Angles.cpp:92
void Unlink(void)
Definition: Clip.cpp:491
void SetMaxJumpHeight(const float newMaxJumpHeight)
void Zero(void)
Definition: Vector.h:415
void SetKnockBack(const int knockBackTime)
void Save(idSaveGame *savefile) const
const float PM_STEPSCALE
void ReadInt(int &value)
Definition: SaveGame.cpp:922
bool HasSteppedUp(void) const
void SetPosition(const idVec3 &newOrigin, const idMat3 &newAxis)
Definition: Clip.cpp:444
static const float M_MS2SEC
Definition: Math.h:217
void SetMaster(idEntity *master, const bool orientated=true)
GLuint start
Definition: glext.h:2845
bool SlideMove(bool gravity, bool stepUp, bool stepDown, bool push)
const int PMF_STEPPED_DOWN
static int BitsForFloat(float f)
Definition: Math.h:723