Advertisement
Guest User

Untitled

a guest
Jun 26th, 2017
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 56.87 KB | None | 0 0
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. #include "q_arch.h"
  22. #include "q_math.h"
  23. #include "q_shared.h"
  24. #include "q_comref.h"
  25. #include "q_collision.h"
  26. #include "gs_public.h"
  27.  
  28. //===============================================================
  29. //      WARSOW player AAboxes sizes
  30.  
  31. vec3_t playerbox_stand_mins = { -16, -16, -24 };
  32. vec3_t playerbox_stand_maxs = { 16, 16, 40 };
  33. int playerbox_stand_viewheight = 30;
  34.  
  35. vec3_t playerbox_crouch_mins = { -16, -16, -24 };
  36. vec3_t playerbox_crouch_maxs = { 16, 16, 16 };
  37. int playerbox_crouch_viewheight = 12;
  38.  
  39. vec3_t playerbox_gib_mins = { -16, -16, 0 };
  40. vec3_t playerbox_gib_maxs = { 16, 16, 16 };
  41. int playerbox_gib_viewheight = 8;
  42.  
  43. #define SPEEDKEY    500
  44.  
  45. #define PM_DASHJUMP_TIMEDELAY 1000 // delay in milliseconds
  46. #define PM_WALLJUMP_TIMEDELAY   1700
  47. #define PM_WALLJUMP_FAILED_TIMEDELAY    700
  48. #define PM_SPECIAL_CROUCH_INHIBIT 600
  49. #define PM_AIRCONTROL_BOUNCE_DELAY 200
  50. #define PM_OVERBOUNCE       1.01f
  51.  
  52. #define CROUCHTIME 100
  53.  
  54. //===============================================================
  55.  
  56. // all of the locals will be zeroed before each
  57. // pmove, just to make damn sure we don't have
  58. // any differences when running on client or server
  59.  
  60. typedef struct
  61. {
  62.     vec3_t origin;          // full float precision
  63.     vec3_t velocity;        // full float precision
  64.  
  65.     vec3_t forward, right, up;
  66.     vec3_t flatforward;     // normalized forward without z component, saved here because it needs
  67.     // special handling for looking straight up or down
  68.     float frametime;
  69.  
  70.     int groundsurfFlags;
  71.     cplane_t groundplane;
  72.     int groundcontents;
  73.  
  74.     vec3_t previous_origin;
  75.     qboolean ladder;
  76.  
  77.     float forwardPush, sidePush, upPush;
  78.  
  79.     float maxPlayerSpeed;
  80.     float maxWalkSpeed;
  81.     float maxCrouchedSpeed;
  82.     float jumpPlayerSpeed;
  83.     float dashPlayerSpeed;
  84. } pml_t;
  85.  
  86. pmove_t *pm;
  87. pml_t pml;
  88.  
  89. // movement parameters
  90.  
  91. #define DEFAULT_WALKSPEED 160.0f
  92. #define DEFAULT_CROUCHEDSPEED 100.0f
  93.  
  94. const float pm_friction = 8; //  ( initially 6 )
  95. const float pm_waterfriction = 1;
  96. const float pm_wateraccelerate = 10; // user intended acceleration when swimming ( initially 6 )
  97.  
  98. const float pm_accelerate = 12; // user intended acceleration when on ground or fly movement ( initially 10 )
  99. const float pm_decelerate = 12; // user intended deceleration when on ground
  100.  
  101. const float pm_airaccelerate = 1; // user intended aceleration when on air
  102. const float pm_airdecelerate = 2.0f; // air deceleration (not +strafe one, just at normal moving).
  103.  
  104. // special movement parameters
  105.  
  106. const float pm_aircontrol = 150.0f; // aircontrol multiplier (intertia velocity to forward velocity conversion)
  107. const float pm_strafebunnyaccel = 70; // forward acceleration when strafe bunny hopping
  108. const float pm_wishspeed = 30;
  109.  
  110. const float pm_dashupspeed = ( 174.0f * GRAVITY_COMPENSATE );
  111.  
  112. #ifdef OLDWALLJUMP
  113. const float pm_wjupspeed = 370;
  114. const float pm_wjbouncefactor = 0.5f;
  115. #define pm_wjminspeed pm_maxspeed
  116. #else
  117. const float pm_wjupspeed = ( 330.0f * GRAVITY_COMPENSATE );
  118. const float pm_failedwjupspeed = ( 50.0f * GRAVITY_COMPENSATE );
  119. const float pm_wjbouncefactor = 0.3f;
  120. const float pm_failedwjbouncefactor = 0.1f;
  121. #define pm_wjminspeed ( ( pml.maxWalkSpeed + pml.maxPlayerSpeed ) * 0.5f )
  122. #endif
  123.  
  124. //
  125. // Kurim : some functions/defines that can be useful to work on the horizontal movement of player :
  126. //
  127. #define VectorScale2D( in, scale, out ) ( ( out )[0] = ( in )[0]*( scale ), ( out )[1] = ( in )[1]*( scale ) )
  128. #define DotProduct2D( x, y )           ( ( x )[0]*( y )[0]+( x )[1]*( y )[1] )
  129.  
  130. static vec_t VectorNormalize2D( vec3_t v ) // ByMiK : normalize horizontally (don't affect Z value)
  131. {
  132.     float length, ilength;
  133.     length = v[0]*v[0] + v[1]*v[1];
  134.     if( length )
  135.     {
  136.         length = sqrt( length ); // FIXME
  137.         ilength = 1.0f/length;
  138.         v[0] *= ilength;
  139.         v[1] *= ilength;
  140.     }
  141.     return length;
  142. }
  143.  
  144. // Could be used to test if player walk touching a wall, if not used in any other part of pm code i'll integrate
  145. // this function to the walljumpcheck function.
  146. // usage : nbTestDir = nb of direction to test around the player
  147. // maxZnormal is the Z value of the normal of a poly to considere it as a wall
  148. // normal is a pointer to the normal of the nearest wall
  149.  
  150. static void PlayerTouchWall( int nbTestDir, float maxZnormal, vec3_t *normal )
  151. {
  152.     vec3_t min, max, dir;
  153.     int i, j;
  154.     trace_t trace;
  155.     float dist = 1.0;
  156.     entity_state_t *state;
  157.  
  158.     for( i = 0; i < nbTestDir; i++ )
  159.     {
  160.         dir[0] = pml.origin[0] + ( pm->maxs[0]*cos( ( 360/nbTestDir )*i ) ); // cos( (360/Imax) * i )
  161.         dir[1] = pml.origin[1] + ( pm->maxs[1]*sin( ( 360/nbTestDir )*i ) );
  162.         dir[2] = pml.origin[2];
  163.  
  164.         for( j = 0; j < 2; j++ )
  165.         {
  166.             min[j] = pm->mins[j];
  167.             max[j] = pm->maxs[j];
  168.         }
  169.         min[2] = max[2] = 0;
  170.         VectorScale( dir, 1.002, dir );
  171.  
  172.         module_Trace( &trace, pml.origin, min, max, dir, pm->playerState->POVnum, pm->contentmask, 0 );
  173.  
  174.         if( trace.allsolid ) return;
  175.  
  176.         if( trace.fraction == 1 )
  177.             continue; // no wall in this direction
  178.  
  179.         if( trace.surfFlags & (SURF_SKY|SURF_NOWALLJUMP) )
  180.             continue;
  181.  
  182.         if( trace.ent > 0 )
  183.         {
  184.             state = module_GetEntityState( trace.ent, 0 );
  185.             if( state->type == ET_PLAYER )
  186.                 continue;
  187.         }
  188.  
  189.         if( trace.fraction > 0 )
  190.         {
  191.             if( dist > trace.fraction && abs( trace.plane.normal[2] ) < maxZnormal )
  192.             {
  193.                 dist = trace.fraction;
  194.                 VectorCopy( trace.plane.normal, *normal );
  195.             }
  196.         }
  197.     }
  198. }
  199.  
  200. //
  201. //  walking up a step should kill some velocity
  202. //
  203.  
  204. //==================
  205. //PM_SlideMove
  206. //
  207. //Returns a new origin, velocity, and contact entity
  208. //Does not modify any world state?
  209. //==================
  210.  
  211. #define MIN_STEP_NORMAL 0.7     // can't step up onto very steep slopes
  212. #define MAX_CLIP_PLANES 5
  213.  
  214. static void PM_AddTouchEnt( int entNum )
  215. {
  216.     int i;
  217.  
  218.     if( pm->numtouch >= MAXTOUCH || entNum < 0 )
  219.         return;
  220.  
  221.     // see if it is already added
  222.     for( i = 0; i < pm->numtouch; i++ )
  223.     {
  224.         if( pm->touchents[i] == entNum )
  225.             return;
  226.     }
  227.  
  228.     // add it
  229.     pm->touchents[pm->numtouch] = entNum;
  230.     pm->numtouch++;
  231. }
  232.  
  233.  
  234. static int PM_SlideMove( void )
  235. {
  236.     vec3_t end, dir;
  237.     vec3_t old_velocity, last_valid_origin;
  238.     float value;
  239.     vec3_t planes[MAX_CLIP_PLANES];
  240.     int numplanes = 0;
  241.     trace_t trace;
  242.     int moves, i, j, k;
  243.     int maxmoves = 4;
  244.     float remainingTime = pml.frametime;
  245.     int blockedmask = 0;
  246.  
  247.     VectorCopy( pml.velocity, old_velocity );
  248.     VectorCopy( pml.origin, last_valid_origin );
  249.  
  250.     if( pm->groundentity != -1 )
  251.     {                          // clip velocity to ground, no need to wait
  252.         // if the ground is not horizontal (a ramp) clipping will slow the player down
  253.         if( pml.groundplane.normal[2] == 1.0f && pml.velocity[2] < 0.0f )
  254.             pml.velocity[2] = 0.0f;
  255.     }
  256.  
  257.     numplanes = 0; // clean up planes count for checking
  258.  
  259.     for( moves = 0; moves < maxmoves; moves++ )
  260.     {
  261.         VectorMA( pml.origin, remainingTime, pml.velocity, end );
  262.         module_Trace( &trace, pml.origin, pm->mins, pm->maxs, end, pm->playerState->POVnum, pm->contentmask, 0 );
  263.         if( trace.allsolid )
  264.         {               // trapped into a solid
  265.             VectorCopy( last_valid_origin, pml.origin );
  266.             return SLIDEMOVEFLAG_TRAPPED;
  267.         }
  268.  
  269.         if( trace.fraction > 0 )
  270.         {                   // actually covered some distance
  271.             VectorCopy( trace.endpos, pml.origin );
  272.             VectorCopy( trace.endpos, last_valid_origin );
  273.         }
  274.  
  275.         if( trace.fraction == 1 )
  276.             break; // move done
  277.  
  278.         // save touched entity for return output
  279.         PM_AddTouchEnt( trace.ent );
  280.  
  281.         // at this point we are blocked but not trapped.
  282.  
  283.         blockedmask |= SLIDEMOVEFLAG_BLOCKED;
  284.         if( trace.plane.normal[2] < SLIDEMOVE_PLANEINTERACT_EPSILON )
  285.         {                                                       // is it a vertical wall?
  286.             blockedmask |= SLIDEMOVEFLAG_WALL_BLOCKED;
  287.         }
  288.  
  289.         remainingTime -= ( trace.fraction * remainingTime );
  290.  
  291.         // we got blocked, add the plane for sliding along it
  292.  
  293.         // if this is a plane we have touched before, try clipping
  294.         // the velocity along it's normal and repeat.
  295.         for( i = 0; i < numplanes; i++ )
  296.         {
  297.             if( DotProduct( trace.plane.normal, planes[i] ) > ( 1.0f - SLIDEMOVE_PLANEINTERACT_EPSILON ) )
  298.             {
  299.                 VectorAdd( trace.plane.normal, pml.velocity, pml.velocity );
  300.                 break;
  301.             }
  302.         }
  303.         if( i < numplanes )  // found a repeated plane, so don't add it, just repeat the trace
  304.             continue;
  305.  
  306.         // security check: we can't store more planes
  307.         if( numplanes >= MAX_CLIP_PLANES )
  308.         {
  309.             VectorClear( pml.velocity );
  310.             return SLIDEMOVEFLAG_TRAPPED;
  311.         }
  312.  
  313.         // put the actual plane in the list
  314.         VectorCopy( trace.plane.normal, planes[numplanes] );
  315.         numplanes++;
  316.  
  317.         //
  318.         // modify original_velocity so it parallels all of the clip planes
  319.         //
  320.  
  321.         for( i = 0; i < numplanes; i++ )
  322.         {
  323.             if( DotProduct( pml.velocity, planes[i] ) >= SLIDEMOVE_PLANEINTERACT_EPSILON )  // would not touch it
  324.                 continue;
  325.  
  326.             GS_ClipVelocity( pml.velocity, planes[i], pml.velocity, PM_OVERBOUNCE );
  327.             // see if we enter a second plane
  328.             for( j = 0; j < numplanes; j++ )
  329.             {
  330.                 if( j == i )  // it's the same plane
  331.                     continue;
  332.                 if( DotProduct( pml.velocity, planes[j] ) >= SLIDEMOVE_PLANEINTERACT_EPSILON )
  333.                     continue; // not with this one
  334.  
  335.                 //there was a second one. Try to slide along it too
  336.                 GS_ClipVelocity( pml.velocity, planes[j], pml.velocity, PM_OVERBOUNCE );
  337.  
  338.                 // check if the slide sent it back to the first plane
  339.                 if( DotProduct( pml.velocity, planes[i] ) >= SLIDEMOVE_PLANEINTERACT_EPSILON )
  340.                     continue;
  341.  
  342.                 // bad luck: slide the original velocity along the crease
  343.                 CrossProduct( planes[i], planes[j], dir );
  344.                 VectorNormalize( dir );
  345.                 value = DotProduct( dir, pml.velocity );
  346.                 VectorScale( dir, value, pml.velocity );
  347.  
  348.                 // check if there is a third plane, in that case we're trapped
  349.                 for( k = 0; k < numplanes; k++ )
  350.                 {
  351.                     if( j == k || i == k )  // it's the same plane
  352.                         continue;
  353.                     if( DotProduct( pml.velocity, planes[k] ) >= SLIDEMOVE_PLANEINTERACT_EPSILON )
  354.                         continue; // not with this one
  355.                     VectorClear( pml.velocity );
  356.                     break;
  357.                 }
  358.             }
  359.         }
  360.     }
  361.  
  362.     if( pm->playerState->pmove.pm_time )
  363.     {
  364.         VectorCopy( old_velocity, pml.velocity );
  365.     }
  366.  
  367.     return blockedmask;
  368. }
  369.  
  370. //==================
  371. //PM_StepSlideMove
  372. //
  373. //Each intersection will try to step over the obstruction instead of
  374. //sliding along it.
  375. //==================
  376. static void PM_StepSlideMove( void )
  377. {
  378.     vec3_t start_o, start_v;
  379.     vec3_t down_o, down_v;
  380.     trace_t trace;
  381.     float down_dist, up_dist;
  382.     vec3_t up, down;
  383.     int blocked;
  384.  
  385.     VectorCopy( pml.origin, start_o );
  386.     VectorCopy( pml.velocity, start_v );
  387.  
  388.     blocked = PM_SlideMove();
  389.  
  390.     VectorCopy( pml.origin, down_o );
  391.     VectorCopy( pml.velocity, down_v );
  392.  
  393.     VectorCopy( start_o, up );
  394.     up[2] += STEPSIZE;
  395.  
  396.     module_Trace( &trace, up, pm->mins, pm->maxs, up, pm->playerState->POVnum, pm->contentmask, 0 );
  397.     if( trace.allsolid )
  398.         return; // can't step up
  399.  
  400.     // try sliding above
  401.     VectorCopy( up, pml.origin );
  402.     VectorCopy( start_v, pml.velocity );
  403.  
  404.     PM_SlideMove();
  405.  
  406.     // push down the final amount
  407.     VectorCopy( pml.origin, down );
  408.     down[2] -= STEPSIZE;
  409.     module_Trace( &trace, pml.origin, pm->mins, pm->maxs, down, pm->playerState->POVnum, pm->contentmask, 0 );
  410.     if( !trace.allsolid )
  411.     {
  412.         VectorCopy( trace.endpos, pml.origin );
  413.     }
  414.  
  415.     VectorCopy( pml.origin, up );
  416.  
  417.     // decide which one went farther
  418.     down_dist = ( down_o[0] - start_o[0] )*( down_o[0] - start_o[0] )
  419.         + ( down_o[1] - start_o[1] )*( down_o[1] - start_o[1] );
  420.     up_dist = ( up[0] - start_o[0] )*( up[0] - start_o[0] )
  421.         + ( up[1] - start_o[1] )*( up[1] - start_o[1] );
  422.  
  423.     if( down_dist >= up_dist || trace.allsolid || ( trace.fraction != 1.0 && trace.plane.normal[2] < MIN_STEP_NORMAL ) )
  424.     {
  425.         VectorCopy( down_o, pml.origin );
  426.         VectorCopy( down_v, pml.velocity );
  427.         return;
  428.     }
  429.  
  430.     // only add the stepping output when it was a vertical step (second case is at the exit of a ramp)
  431.     if( ( blocked & SLIDEMOVEFLAG_WALL_BLOCKED ) || trace.plane.normal[2] == 1.0f - SLIDEMOVE_PLANEINTERACT_EPSILON )
  432.     {
  433.         pm->step = ( pml.origin[2] - pml.previous_origin[2] );
  434.     }
  435.  
  436.     // wsw : jal : The following line is what produces the ramp sliding.
  437.  
  438.     //!! Special case
  439.     // if we were walking along a plane, then we need to copy the Z over
  440.     pml.velocity[2] = down_v[2];
  441. }
  442.  
  443. //==================
  444. //PM_Friction -- Modified for wsw
  445. //
  446. //Handles both ground friction and water friction
  447. //==================
  448. static void PM_Friction( void )
  449. {
  450.     float *vel;
  451.     float speed, newspeed, control;
  452.     float friction;
  453.     float drop;
  454.  
  455.     vel = pml.velocity;
  456.  
  457.     speed = vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2];
  458.     if( speed < 1 )
  459.     {
  460.         vel[0] = 0;
  461.         vel[1] = 0;
  462.         return;
  463.     }
  464.  
  465.     speed = sqrt( speed );
  466.     drop = 0;
  467.  
  468.     // apply ground friction
  469.     if( ( ( ( ( pm->groundentity != -1 ) && !( pml.groundsurfFlags & SURF_SLICK ) ) ) && ( pm->waterlevel < 2 ) ) || ( pml.ladder ) )
  470.     {
  471.         if( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] <= 0 )
  472.         {
  473.             friction = pm_friction;
  474.             control = speed < pm_decelerate ? pm_decelerate : speed;
  475.             drop += control * friction * pml.frametime;
  476.         }
  477.     }
  478.  
  479.     // apply water friction
  480.     if( ( pm->waterlevel >= 2 ) && !pml.ladder )
  481.         drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime;
  482.  
  483.     // scale the velocity
  484.     newspeed = speed - drop;
  485.     if( newspeed <= 0 )
  486.     {
  487.         newspeed = 0;
  488.         VectorClear( vel );
  489.     }
  490.     else
  491.     {
  492.         newspeed /= speed;
  493.         VectorScale( vel, newspeed, vel );
  494.     }
  495. }
  496.  
  497. //==============
  498. //PM_Accelerate
  499. //
  500. //Handles user intended acceleration
  501. //==============
  502. static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel )
  503. {
  504.     int i;
  505.     float addspeed, accelspeed, currentspeed;
  506.  
  507.     currentspeed = DotProduct( pml.velocity, wishdir );
  508.     addspeed = wishspeed - currentspeed;
  509.     if( addspeed <= 0 )
  510.         return;
  511.     accelspeed = accel*pml.frametime*wishspeed;
  512.     if( accelspeed > addspeed )
  513.         accelspeed = addspeed;
  514.  
  515.     for( i = 0; i < 3; i++ )
  516.         pml.velocity[i] += accelspeed*wishdir[i];
  517. }
  518.  
  519. static void PM_AirAccelerate( vec3_t wishdir, float wishspeed )
  520. {
  521.     vec3_t curvel, wishvel, acceldir, curdir;
  522.     float addspeed, accelspeed, curspeed;
  523.     float dot;
  524.     // air movement parameters:
  525.     float airforwardaccel = 1.00001f; // Default: 1.0f : how fast you accelerate until you reach pm_maxspeed
  526.     float bunnyaccel = 0.1585f; // (0.42 0.1593f) Default: 0.1585f how fast you accelerate after reaching pm_maxspeed
  527.     // (it gets harder as you near bunnytopspeed)
  528.     float bunnytopspeed = 900; // (0.42: 925) soft speed limit (can get faster with rjs and on ramps)
  529.     float turnaccel = 6.0f;    // (0.42: 9.0) Default: 7 max sharpness of turns
  530.     float backtosideratio = 0.9f; // (0.42: 0.8) Default: 0.8f lower values make it easier to change direction without
  531.     // losing speed; the drawback is "understeering" in sharp turns
  532.  
  533.     if( !wishspeed )
  534.         return;
  535.  
  536.     VectorCopy( pml.velocity, curvel );
  537.     curvel[2] = 0;
  538.     curspeed = VectorLength( curvel );
  539.  
  540.     if( wishspeed > curspeed * 1.01f ) // moving below pm_maxspeed
  541.     {
  542.         float accelspeed = curspeed + airforwardaccel * pml.maxPlayerSpeed * pml.frametime;
  543.         if( accelspeed < wishspeed )
  544.             wishspeed = accelspeed;
  545.     }
  546.     else
  547.     {
  548.         float f = ( bunnytopspeed - curspeed ) / ( bunnytopspeed - pml.maxPlayerSpeed );
  549.         if( f < 0 )
  550.             f = 0;
  551.         wishspeed = max( curspeed, pml.maxPlayerSpeed ) + bunnyaccel * f * pml.maxPlayerSpeed * pml.frametime;
  552.     }
  553.     VectorScale( wishdir, wishspeed, wishvel );
  554.     VectorSubtract( wishvel, curvel, acceldir );
  555.     addspeed = VectorNormalize( acceldir );
  556.  
  557.     accelspeed = turnaccel * pml.maxPlayerSpeed * pml.frametime;
  558.     if( accelspeed > addspeed )
  559.         accelspeed = addspeed;
  560.  
  561.     if( backtosideratio < 1.0f )
  562.     {
  563.         VectorNormalize2( curvel, curdir );
  564.         dot = DotProduct( acceldir, curdir );
  565.         if( dot < 0 )
  566.             VectorMA( acceldir, -( 1.0f - backtosideratio ) * dot, curdir, acceldir );
  567.     }
  568.  
  569.     VectorMA( pml.velocity, accelspeed, acceldir, pml.velocity );
  570. }
  571.  
  572. // when using +strafe convert the inertia to forward speed.
  573. static void PM_Aircontrol( pmove_t *pm, vec3_t wishdir, float wishspeed )
  574. {
  575.     float zspeed, speed, dot, k;
  576.     int i;
  577.     float fmove, smove;
  578.  
  579.     if( !pm_aircontrol )
  580.         return;
  581.  
  582.     // accelerate
  583.     fmove = pml.forwardPush;
  584.     smove = pml.sidePush;
  585.  
  586.     if( ( smove > 0 || smove < 0 ) || ( wishspeed == 0.0 ) )
  587.         return; // can't control movement if not moving forward or backward
  588.  
  589.     zspeed = pml.velocity[2];
  590.     pml.velocity[2] = 0;
  591.     speed = VectorNormalize( pml.velocity );
  592.  
  593.  
  594.     dot = DotProduct( pml.velocity, wishdir );
  595.     k = 32.0f * pm_aircontrol * dot * dot * pml.frametime;
  596.  
  597.     if( dot > 0 )
  598.     {
  599.         // we can't change direction while slowing down
  600.         for( i = 0; i < 2; i++ )
  601.             pml.velocity[i] = pml.velocity[i] * speed + wishdir[i] * k;
  602.  
  603.         VectorNormalize( pml.velocity );
  604.     }
  605.  
  606.     for( i = 0; i < 2; i++ )
  607.         pml.velocity[i] *= speed;
  608.  
  609.     pml.velocity[2] = zspeed;
  610. }
  611.  
  612. #if 0 // never used
  613. static void PM_AirAccelerate( vec3_t wishdir, float wishspeed, float accel )
  614. {
  615.     int i;
  616.     float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
  617.  
  618.     if( wishspd > 30 )
  619.         wishspd = 30;
  620.     currentspeed = DotProduct( pml.velocity, wishdir );
  621.     addspeed = wishspd - currentspeed;
  622.     if( addspeed <= 0 )
  623.         return;
  624.     accelspeed = accel * wishspeed * pml.frametime;
  625.     if( accelspeed > addspeed )
  626.         accelspeed = addspeed;
  627.  
  628.     for( i = 0; i < 3; i++ )
  629.         pml.velocity[i] += accelspeed*wishdir[i];
  630. }
  631. #endif
  632.  
  633.  
  634. //=============
  635. //PM_AddCurrents
  636. //=============
  637. static void PM_AddCurrents( vec3_t wishvel )
  638. {
  639.     //
  640.     // account for ladders
  641.     //
  642.  
  643.     if( pml.ladder && fabs( pml.velocity[2] ) <= 200 )
  644.     {
  645.         if( ( pm->playerState->viewangles[PITCH] <= -15 ) && ( pml.forwardPush > 0 ) )
  646.             wishvel[2] = 200;
  647.         else if( ( pm->playerState->viewangles[PITCH] >= 15 ) && ( pml.forwardPush > 0 ) )
  648.             wishvel[2] = -200;
  649.         else if( pml.upPush > 0 )
  650.             wishvel[2] = 200;
  651.         else if( pml.upPush < 0 )
  652.             wishvel[2] = -200;
  653.         else
  654.             wishvel[2] = 0;
  655.  
  656.         // limit horizontal speed when on a ladder
  657.         clamp( wishvel[0], -25, 25 );
  658.         clamp( wishvel[1], -25, 25 );
  659.     }
  660. }
  661.  
  662. //===================
  663. //PM_WaterMove
  664. //
  665. //===================
  666. static void PM_WaterMove( void )
  667. {
  668.     int i;
  669.     vec3_t wishvel;
  670.     float wishspeed;
  671.     vec3_t wishdir;
  672.  
  673.     // user intentions
  674.     for( i = 0; i < 3; i++ )
  675.         wishvel[i] = pml.forward[i]*pml.forwardPush + pml.right[i]*pml.sidePush;
  676.  
  677.     if( !pml.forwardPush && !pml.sidePush && !pml.upPush )
  678.         wishvel[2] -= 60; // drift towards bottom
  679.     else
  680.         wishvel[2] += pml.upPush;
  681.  
  682.     PM_AddCurrents( wishvel );
  683.  
  684.     VectorCopy( wishvel, wishdir );
  685.     wishspeed = VectorNormalize( wishdir );
  686.  
  687.     if( wishspeed > pml.maxPlayerSpeed )
  688.     {
  689.         wishspeed = pml.maxPlayerSpeed / wishspeed;
  690.         VectorScale( wishvel, wishspeed, wishvel );
  691.         wishspeed = pml.maxPlayerSpeed;
  692.     }
  693.     wishspeed *= 0.5;
  694.  
  695.     PM_Accelerate( wishdir, wishspeed, pm_wateraccelerate );
  696.     PM_StepSlideMove();
  697. }
  698.  
  699. //===================
  700. //PM_Move -- Kurim
  701. //
  702. //===================
  703. static void PM_Move( void )
  704. {
  705.     int i;
  706.     vec3_t wishvel;
  707.     float fmove, smove;
  708.     vec3_t wishdir;
  709.     float wishspeed;
  710.     float maxspeed;
  711.     float accel;
  712.     float wishspeed2;
  713.  
  714.     fmove = pml.forwardPush;
  715.     smove = pml.sidePush;
  716.  
  717.     for( i = 0; i < 2; i++ )
  718.         wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
  719.     wishvel[2] = 0;
  720.  
  721.     PM_AddCurrents( wishvel );
  722.  
  723.     VectorCopy( wishvel, wishdir );
  724.     wishspeed = VectorNormalize( wishdir );
  725.  
  726.     // clamp to server defined max speed
  727.  
  728.     if( pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] )
  729.     {
  730.         maxspeed = pml.maxCrouchedSpeed;
  731.     }
  732.     else if( ( pm->cmd.buttons & BUTTON_WALK ) && ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_WALK ) )
  733.     {
  734.         maxspeed = pml.maxWalkSpeed;
  735.     }
  736.     else
  737.         maxspeed = pml.maxPlayerSpeed;
  738.  
  739.     if( wishspeed > maxspeed )
  740.     {
  741.         wishspeed = maxspeed / wishspeed;
  742.         VectorScale( wishvel, wishspeed, wishvel );
  743.         wishspeed = maxspeed;
  744.     }
  745.  
  746.     if( pml.ladder )
  747.     {
  748.         PM_Accelerate( wishdir, wishspeed, pm_accelerate );
  749.  
  750.         if( !wishvel[2] )
  751.         {
  752.             if( pml.velocity[2] > 0 )
  753.             {
  754.                 pml.velocity[2] -= pm->playerState->pmove.gravity * pml.frametime;
  755.                 if( pml.velocity[2] < 0 )
  756.                     pml.velocity[2]  = 0;
  757.             }
  758.             else
  759.             {
  760.                 pml.velocity[2] += pm->playerState->pmove.gravity * pml.frametime;
  761.                 if( pml.velocity[2] > 0 )
  762.                     pml.velocity[2]  = 0;
  763.             }
  764.         }
  765.  
  766.         PM_StepSlideMove();
  767.     }
  768.     else if( pm->groundentity != -1 )
  769.     {
  770.         // walking on ground
  771.         if( pml.velocity[2] > 0 )
  772.             pml.velocity[2] = 0; //!!! this is before the accel
  773.  
  774.         PM_Accelerate( wishdir, wishspeed, pm_accelerate );
  775.  
  776.         // fix for negative trigger_gravity fields
  777.         if( pm->playerState->pmove.gravity > 0 )
  778.         {
  779.             if( pml.velocity[2] > 0 )
  780.                 pml.velocity[2] = 0;
  781.         }
  782.         else
  783.             pml.velocity[2] -= pm->playerState->pmove.gravity * pml.frametime;
  784.  
  785.         if( !pml.velocity[0] && !pml.velocity[1] )
  786.             return;
  787.  
  788.         PM_StepSlideMove();
  789.     }
  790.     else if( ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_AIRCONTROL )
  791.         && !( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_FWDBUNNY ) )
  792.     {
  793.         // Air Control
  794.         wishspeed2 = wishspeed;
  795.         if( DotProduct( pml.velocity, wishdir ) < 0
  796.             && !( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING )
  797.             && ( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] <= 0 ) )
  798.             accel = pm_airdecelerate;
  799.         else
  800.             accel = pm_airaccelerate;
  801.  
  802.         if( ( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING )
  803.             || ( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] > 0 ) )
  804.             accel = 0; // no stopmove while walljumping
  805.  
  806.         if( ( smove > 0 || smove < 0 ) && !fmove && ( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] <= 0 ) )
  807.         {
  808.             if( wishspeed > pm_wishspeed )
  809.                 wishspeed = pm_wishspeed;
  810.             accel = pm_strafebunnyaccel;
  811.         }
  812.  
  813.         // Air control
  814.         PM_Accelerate( wishdir, wishspeed, accel );
  815.         if( pm_aircontrol && !( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING ) && ( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] <= 0 ) )  // no air ctrl while wjing
  816.             PM_Aircontrol( pm, wishdir, wishspeed2 );
  817.  
  818.         // add gravity
  819.         pml.velocity[2] -= pm->playerState->pmove.gravity * pml.frametime;
  820.         PM_StepSlideMove();
  821.     }
  822.     else // air movement
  823.     {
  824.         qboolean inhibit = qfalse;
  825.         qboolean accelerating, decelerating;
  826.  
  827.         accelerating = ( DotProduct( pml.velocity, wishdir ) > 0.0f );
  828.         decelerating = ( DotProduct( pml.velocity, wishdir ) < -0.0f );
  829.        
  830.         if( ( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING ) &&
  831.             ( pm->playerState->pmove.stats[PM_STAT_WJTIME] >= ( PM_WALLJUMP_TIMEDELAY - PM_AIRCONTROL_BOUNCE_DELAY ) ) )
  832.             inhibit = qtrue;
  833.  
  834.         if( ( pm->playerState->pmove.pm_flags & PMF_DASHING ) &&
  835.             ( pm->playerState->pmove.stats[PM_STAT_DASHTIME] >= ( PM_DASHJUMP_TIMEDELAY - PM_AIRCONTROL_BOUNCE_DELAY ) ) )
  836.             inhibit = qtrue;
  837.  
  838.         if( !( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_FWDBUNNY ) )
  839.             inhibit = qtrue;
  840.  
  841.         if( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] > 0 )
  842.             inhibit = qtrue;
  843.  
  844.         // (aka +fwdbunny) pressing forward or backward but not pressing strafe and not dashing
  845.         if( accelerating && !inhibit && !smove && fmove )
  846.         {
  847.             PM_AirAccelerate( wishdir, wishspeed );
  848.         }
  849.         else // strafe running
  850.         {
  851.             qboolean aircontrol = qtrue;
  852.  
  853.             wishspeed2 = wishspeed;
  854.             if( decelerating &&
  855.                 !( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING ) )
  856.                 accel = pm_airdecelerate;
  857.             else
  858.                 accel = pm_airaccelerate;
  859.  
  860.             if( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING
  861.                 || ( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] > 0 ) )
  862.             {
  863.                 accel = 0; // no stop-move while wall-jumping
  864.                 aircontrol = qfalse;
  865.             }
  866.  
  867.             if( ( pm->playerState->pmove.pm_flags & PMF_DASHING ) &&
  868.                 ( pm->playerState->pmove.stats[PM_STAT_DASHTIME] >= ( PM_DASHJUMP_TIMEDELAY - PM_AIRCONTROL_BOUNCE_DELAY ) ) )
  869.                 aircontrol = qfalse;
  870.  
  871.             if( !( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_AIRCONTROL ) )
  872.                 aircontrol = qfalse;
  873.  
  874.             // +strafe bunnyhopping
  875.             if( aircontrol && smove && !fmove )
  876.             {
  877.                 if( wishspeed > pm_wishspeed )
  878.                     wishspeed = pm_wishspeed;
  879.  
  880.                 PM_Accelerate( wishdir, wishspeed, pm_strafebunnyaccel );
  881.                 PM_Aircontrol( pm, wishdir, wishspeed2 );
  882.             }
  883.             else // standard movement (includes strafejumping)
  884.             {
  885.                 PM_Accelerate( wishdir, wishspeed, accel );
  886.             }
  887.         }
  888.  
  889.         // add gravity
  890.         pml.velocity[2] -= pm->playerState->pmove.gravity * pml.frametime;
  891.         PM_StepSlideMove();
  892.     }
  893. }
  894.  
  895.  
  896. //=============
  897. //PM_CategorizePosition
  898. //=============
  899. //#define JITSPOES_CLIPBUGFIX // jal : it bugs more than fixes?
  900. static void PM_CategorizePosition( void )
  901. {
  902.     vec3_t point;
  903.     int cont;
  904.     trace_t trace;
  905.     int sample1;
  906.     int sample2;
  907.  
  908.     // if the player hull point one-quarter unit down is solid, the player is on ground
  909.  
  910.     // see if standing on something solid
  911.     point[0] = pml.origin[0];
  912.     point[1] = pml.origin[1];
  913.     point[2] = pml.origin[2] - 0.25;
  914.  
  915.     if( pml.velocity[2] > 180 ) // !!ZOID changed from 100 to 180 (ramp accel)
  916.     {
  917.         pm->playerState->pmove.pm_flags &= ~PMF_ON_GROUND;
  918.         pm->groundentity = -1;
  919.     }
  920.     else
  921.     {
  922.         module_Trace( &trace, pml.origin, pm->mins, pm->maxs, point, pm->playerState->POVnum, pm->contentmask, 0 );
  923.         pml.groundplane = trace.plane;
  924.         pml.groundsurfFlags = trace.surfFlags;
  925.         pml.groundcontents = trace.contents;
  926.  
  927.         if( ( trace.fraction == 1 ) || ( trace.plane.normal[2] < 0.7 && !trace.startsolid ) )
  928.         {
  929. #ifdef JITSPOES_CLIPBUGFIX
  930.             trace_t trace2;
  931.             vec3_t mins, maxs;
  932.  
  933.             // try a slightly smaller bounding box -- this is to fix getting stuck up
  934.             // on angled walls and not being able to move (like you're stuck in the air)
  935.             mins[0] = pm->mins[0] ? pm->mins[0] + 1 : 0;
  936.             mins[1] = pm->mins[1] ? pm->mins[1] + 1 : 0;
  937.             mins[2] = pm->mins[2];
  938.             maxs[0] = pm->maxs[0] ? pm->maxs[0] - 1 : 0;
  939.             maxs[1] = pm->maxs[1] ? pm->maxs[1] - 1 : 0;
  940.             maxs[2] = pm->maxs[2];
  941.             pm->trace( &trace2, pml.origin, mins, maxs, point );
  942.  
  943.             if( !( trace2.plane.normal[2] < 0.7f && !trace2.startsolid ) )
  944.             {
  945.                 memcpy( &trace, &trace2, sizeof( trace ) );
  946.                 pml.groundplane = trace.plane;
  947.                 pml.groundsurfFlags = trace.surfFlags;
  948.                 pml.groundcontents = trace.contents;
  949.                 pm->groundentity = trace.ent;
  950.             }
  951. #else //JITSPOES_CLIPBUGFIX
  952.             pm->groundentity = -1;
  953.             pm->playerState->pmove.pm_flags &= ~PMF_ON_GROUND;
  954. #endif //JITSPOES_CLIPBUGFIX
  955.         }
  956.         else
  957.         {
  958.             pm->groundentity = trace.ent;
  959.  
  960.             // hitting solid ground will end a waterjump
  961.             if( pm->playerState->pmove.pm_flags & PMF_TIME_WATERJUMP )
  962.             {
  963.                 pm->playerState->pmove.pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT );
  964.                 pm->playerState->pmove.pm_time = 0;
  965.             }
  966.  
  967.             if( !( pm->playerState->pmove.pm_flags & PMF_ON_GROUND ) )
  968.             { // just hit the ground
  969.                 pm->playerState->pmove.pm_flags |= PMF_ON_GROUND;
  970.             }
  971.         }
  972.  
  973.         if( ( pm->numtouch < MAXTOUCH ) && ( trace.fraction < 1.0 ) )
  974.         {
  975.             pm->touchents[pm->numtouch] = trace.ent;
  976.             pm->numtouch++;
  977.         }
  978.     }
  979.  
  980.     //
  981.     // get waterlevel, accounting for ducking
  982.     //
  983.     pm->waterlevel = 0;
  984.     pm->watertype = 0;
  985.  
  986.     sample2 = pm->playerState->viewheight - pm->mins[2];
  987.     sample1 = sample2 / 2;
  988.  
  989.     point[2] = pml.origin[2] + pm->mins[2] + 1;
  990.     cont = module_PointContents( point, 0 );
  991.  
  992.     if( cont & MASK_WATER )
  993.     {
  994.         pm->watertype = cont;
  995.         pm->waterlevel = 1;
  996.         point[2] = pml.origin[2] + pm->mins[2] + sample1;
  997.         cont = module_PointContents( point, 0 );
  998.         if( cont & MASK_WATER )
  999.         {
  1000.             pm->waterlevel = 2;
  1001.             point[2] = pml.origin[2] + pm->mins[2] + sample2;
  1002.             cont = module_PointContents( point, 0 );
  1003.             if( cont & MASK_WATER )
  1004.                 pm->waterlevel = 3;
  1005.         }
  1006.     }
  1007. }
  1008.  
  1009. static void PM_ClearDash( void )
  1010. {
  1011.     pm->playerState->pmove.pm_flags &= ~PMF_DASHING;
  1012.     pm->playerState->pmove.stats[PM_STAT_DASHTIME] = 0;
  1013. }
  1014.  
  1015. static void PM_ClearWallJump( void )
  1016. {
  1017.     pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPING;
  1018.     pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPCOUNT;
  1019.     pm->playerState->pmove.stats[PM_STAT_WJTIME] = 0;
  1020. }
  1021.  
  1022. static void PM_ClearStun( void )
  1023. {
  1024.     pm->playerState->pmove.stats[PM_STAT_STUN] = 0;
  1025. }
  1026.  
  1027. //=============
  1028. //PM_CheckJump
  1029. //=============
  1030. static void PM_CheckJump( void )
  1031. {
  1032.     if( pml.upPush < 10 )
  1033.     { // not holding jump
  1034.         pm->playerState->pmove.pm_flags &= ~PMF_JUMP_HELD;
  1035.         return;
  1036.     }
  1037.  
  1038.     // must wait for jump to be released
  1039.     if( pm->playerState->pmove.pm_flags & PMF_JUMP_HELD )
  1040.         return;
  1041.  
  1042.     if( pm->playerState->pmove.pm_type != PM_NORMAL )
  1043.         return;
  1044.  
  1045.     if( pm->waterlevel >= 2 )
  1046.     { // swimming, not jumping
  1047.         pm->groundentity = -1;
  1048.         return;
  1049.     }
  1050.  
  1051.     if( pm->groundentity == -1 )
  1052.         return;
  1053.  
  1054.     if( !( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_JUMP ) )
  1055.         return;
  1056.  
  1057.     pm->playerState->pmove.pm_flags |= PMF_JUMP_HELD;
  1058.     pm->groundentity = -1;
  1059.  
  1060.     //if( gs.module == GS_MODULE_GAME ) GS_Printf( "upvel %f\n", pml.velocity[2] );
  1061.     if( pml.velocity[2] > 100 )
  1062.     {
  1063.         module_PredictedEvent( pm->playerState->POVnum, EV_DOUBLEJUMP, 0 );
  1064.         pml.velocity[2] += pml.jumpPlayerSpeed;
  1065.     }
  1066.     else if( pml.velocity[2] > 0 )
  1067.     {
  1068.         module_PredictedEvent( pm->playerState->POVnum, EV_JUMP, 0 );
  1069.         pml.velocity[2] += pml.jumpPlayerSpeed;
  1070.     }
  1071.     else
  1072.     {
  1073.         module_PredictedEvent( pm->playerState->POVnum, EV_JUMP, 0 );
  1074.         pml.velocity[2] = pml.jumpPlayerSpeed;
  1075.     }
  1076.  
  1077.     // remove wj count
  1078.     pm->playerState->pmove.pm_flags &= ~PMF_JUMPPAD_TIME;
  1079.     PM_ClearDash();
  1080.     PM_ClearWallJump();
  1081. }
  1082.  
  1083. //=============
  1084. //PM_CheckDash -- by Kurim
  1085. //=============
  1086. static void PM_CheckDash( void )
  1087. {
  1088.     float actual_velocity;
  1089.     float upspeed;
  1090.     vec3_t dashdir;
  1091.  
  1092.     if( !( pm->cmd.buttons & BUTTON_SPECIAL ) )
  1093.         pm->playerState->pmove.pm_flags &= ~PMF_SPECIAL_HELD;
  1094.  
  1095.     if( pm->playerState->pmove.pm_type != PM_NORMAL )
  1096.         return;
  1097.  
  1098.     if( pm->playerState->pmove.stats[PM_STAT_DASHTIME] > 0 )
  1099.         return;
  1100.  
  1101.     if( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] > 0 ) // can not start a new dash during knockback time
  1102.         return;
  1103.  
  1104.     if( ( pm->cmd.buttons & BUTTON_SPECIAL ) && pm->groundentity != -1
  1105.         && ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_DASH ) )
  1106.     {
  1107.         if( pm->playerState->pmove.pm_flags & PMF_SPECIAL_HELD )
  1108.             return;
  1109.  
  1110.         pm->playerState->pmove.pm_flags &= ~PMF_JUMPPAD_TIME;
  1111.         PM_ClearWallJump();
  1112.  
  1113.         pm->playerState->pmove.pm_flags |= PMF_DASHING;
  1114.         pm->playerState->pmove.pm_flags |= PMF_SPECIAL_HELD;
  1115.         pm->groundentity = -1;
  1116.  
  1117.         if( pml.velocity[2] <= 0.0f )
  1118.             upspeed = pm_dashupspeed;
  1119.         else
  1120.             upspeed = pm_dashupspeed + pml.velocity[2];
  1121.  
  1122.         VectorMA( vec3_origin, pml.forwardPush, pml.flatforward, dashdir );
  1123.         VectorMA( dashdir, pml.sidePush, pml.right, dashdir );
  1124.         dashdir[2] = 0.0;
  1125.  
  1126.         if( VectorLength( dashdir ) < 0.01f )  // if not moving, dash like a "forward dash"
  1127.             VectorCopy( pml.flatforward, dashdir );
  1128.  
  1129.         VectorNormalizeFast( dashdir );
  1130.  
  1131.         actual_velocity = VectorNormalize2D( pml.velocity );
  1132.         if( actual_velocity <= pml.dashPlayerSpeed )
  1133.             VectorScale( dashdir, pml.dashPlayerSpeed, dashdir );
  1134.         else
  1135.             VectorScale( dashdir, actual_velocity, dashdir );
  1136.  
  1137.         VectorCopy( dashdir, pml.velocity );
  1138.         pml.velocity[2] = upspeed;
  1139.  
  1140.         pm->playerState->pmove.stats[PM_STAT_DASHTIME] = PM_DASHJUMP_TIMEDELAY;
  1141.  
  1142.         // return sound events
  1143.         if( abs( pml.sidePush ) > 10 && abs( pml.sidePush ) >= abs( pml.forwardPush ) )
  1144.         {
  1145.             if( pml.sidePush > 0 )
  1146.             {
  1147.                 module_PredictedEvent( pm->playerState->POVnum, EV_DASH, 2 );
  1148.             }
  1149.             else
  1150.             {
  1151.                 module_PredictedEvent( pm->playerState->POVnum, EV_DASH, 1 );
  1152.             }
  1153.         }
  1154.         else if( pml.forwardPush < -10 )
  1155.         {
  1156.             module_PredictedEvent( pm->playerState->POVnum, EV_DASH, 3 );
  1157.         }
  1158.         else
  1159.         {
  1160.             module_PredictedEvent( pm->playerState->POVnum, EV_DASH, 0 );
  1161.         }
  1162.     }
  1163.     else if( pm->groundentity == -1 )
  1164.         pm->playerState->pmove.pm_flags &= ~PMF_DASHING;
  1165. }
  1166.  
  1167. //=================
  1168. //PM_CheckWallJump -- By Kurim
  1169. //=================
  1170. static void PM_CheckWallJump( void )
  1171. {
  1172.     vec3_t normal;
  1173.     float hspeed;
  1174.  
  1175.     if( !( pm->cmd.buttons & BUTTON_SPECIAL ) )
  1176.         pm->playerState->pmove.pm_flags &= ~PMF_SPECIAL_HELD;
  1177.  
  1178.     if( pm->groundentity != -1 )
  1179.     {
  1180.         pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPING;
  1181.         pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPCOUNT;
  1182.     }
  1183.  
  1184.     if( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING && pml.velocity[2] < 0.0 )
  1185.         pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPING;
  1186.  
  1187.     if( pm->playerState->pmove.stats[PM_STAT_WJTIME] <= 0 )  // reset the wj count after wj delay
  1188.         pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPCOUNT;
  1189.  
  1190.     if( pm->playerState->pmove.pm_type != PM_NORMAL )
  1191.         return;
  1192.  
  1193.     // don't walljump in the first 100 milliseconds of a dash jump
  1194.     if( pm->playerState->pmove.pm_flags & PMF_DASHING
  1195.         && ( pm->playerState->pmove.stats[PM_STAT_DASHTIME] > ( PM_DASHJUMP_TIMEDELAY - 100 ) ) )
  1196.         return;
  1197.  
  1198.     if( pm->groundentity == -1 && ( pm->cmd.buttons & BUTTON_SPECIAL )
  1199.         && ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_WALLJUMP ) &&
  1200.         ( !( pm->playerState->pmove.pm_flags & PMF_WALLJUMPCOUNT ) )
  1201.         && pm->playerState->pmove.stats[PM_STAT_WJTIME] <= 0
  1202.         )
  1203.     {
  1204.         VectorClear( normal );
  1205.         PlayerTouchWall( 12, 0.3f, &normal );
  1206.         if( !VectorLength( normal ) )
  1207.             return;
  1208.  
  1209.         if( !( pm->playerState->pmove.pm_flags & PMF_SPECIAL_HELD )
  1210.             && !( pm->playerState->pmove.pm_flags & PMF_WALLJUMPING ) )
  1211.         {
  1212.             float oldupvelocity = pml.velocity[2];
  1213.             pml.velocity[2] = 0.0;
  1214.  
  1215.             hspeed = VectorNormalize2D( pml.velocity );
  1216.  
  1217.             // if stunned almost do nothing
  1218.             if( pm->playerState->pmove.stats[PM_STAT_STUN] > 0 )
  1219.             {
  1220.                 GS_ClipVelocity( pml.velocity, normal, pml.velocity, 1.0f );
  1221.                 VectorMA( pml.velocity, pm_failedwjbouncefactor, normal, pml.velocity );
  1222.  
  1223.                 VectorNormalize( pml.velocity );
  1224.  
  1225.                 VectorScale( pml.velocity, hspeed, pml.velocity );
  1226.                 pml.velocity[2] = ( oldupvelocity + pm_failedwjupspeed > pm_failedwjupspeed ) ? oldupvelocity : oldupvelocity + pm_failedwjupspeed;
  1227.             }
  1228.             else
  1229.             {
  1230.                 GS_ClipVelocity( pml.velocity, normal, pml.velocity, 1.0005f );
  1231.                 VectorMA( pml.velocity, pm_wjbouncefactor, normal, pml.velocity );
  1232.  
  1233.                 if( hspeed < pm_wjminspeed )
  1234.                     hspeed = pm_wjminspeed;
  1235.  
  1236.                 VectorNormalize( pml.velocity );
  1237.  
  1238.                 VectorScale( pml.velocity, hspeed, pml.velocity );
  1239.                 pml.velocity[2] = ( oldupvelocity > pm_wjupspeed ) ? oldupvelocity : pm_wjupspeed; // jal: if we had a faster upwards speed, keep it
  1240.             }
  1241.  
  1242.             // set the walljumping state
  1243.             PM_ClearDash();
  1244.             pm->playerState->pmove.pm_flags &= ~PMF_JUMPPAD_TIME;
  1245.  
  1246.             pm->playerState->pmove.pm_flags |= PMF_WALLJUMPING;
  1247.             pm->playerState->pmove.pm_flags |= PMF_SPECIAL_HELD;
  1248.  
  1249.             pm->playerState->pmove.pm_flags |= PMF_WALLJUMPCOUNT;
  1250.  
  1251.             if( pm->playerState->pmove.stats[PM_STAT_STUN] > 0 )
  1252.             {
  1253.                 pm->playerState->pmove.stats[PM_STAT_WJTIME] = PM_WALLJUMP_FAILED_TIMEDELAY;
  1254.  
  1255.                 // Create the event
  1256.                 module_PredictedEvent( pm->playerState->POVnum, EV_WALLJUMP_FAILED, DirToByte( normal ) );
  1257.             }
  1258.             else
  1259.             {
  1260.                 pm->playerState->pmove.stats[PM_STAT_WJTIME] = PM_WALLJUMP_TIMEDELAY;
  1261.  
  1262.                 // Create the event
  1263.                 module_PredictedEvent( pm->playerState->POVnum, EV_WALLJUMP, DirToByte( normal ) );
  1264.             }
  1265.         }
  1266.     }
  1267.     else
  1268.         pm->playerState->pmove.pm_flags &= ~PMF_WALLJUMPING;
  1269. }
  1270.  
  1271. //=============
  1272. //PM_CheckSpecialMovement
  1273. //=============
  1274. static void PM_CheckSpecialMovement( void )
  1275. {
  1276.     vec3_t spot;
  1277.     int cont;
  1278.     trace_t trace;
  1279.  
  1280.     if( pm->playerState->pmove.pm_time )
  1281.         return;
  1282.  
  1283.     pml.ladder = qfalse;
  1284.  
  1285.     // check for ladder
  1286.     VectorMA( pml.origin, 1, pml.flatforward, spot );
  1287.     module_Trace( &trace, pml.origin, pm->mins, pm->maxs, spot, pm->playerState->POVnum, pm->contentmask, 0 );
  1288.     if( ( trace.fraction < 1 ) && ( trace.surfFlags & SURF_LADDER ) )
  1289.         pml.ladder = qtrue;
  1290.  
  1291.     // check for water jump
  1292.     if( pm->waterlevel != 2 )
  1293.         return;
  1294.  
  1295.     VectorMA( pml.origin, 30, pml.flatforward, spot );
  1296.     spot[2] += 4;
  1297.     cont = module_PointContents( spot, 0 );
  1298.     if( !( cont & CONTENTS_SOLID ) )
  1299.         return;
  1300.  
  1301.     spot[2] += 16;
  1302.     cont = module_PointContents( spot, 0 );
  1303.     if( cont )
  1304.         return;
  1305.     // jump out of water
  1306.     VectorScale( pml.flatforward, 50, pml.velocity );
  1307.     pml.velocity[2] = 350;
  1308.  
  1309.     pm->playerState->pmove.pm_flags |= PMF_TIME_WATERJUMP;
  1310.     pm->playerState->pmove.pm_time = 255;
  1311. }
  1312.  
  1313. //===============
  1314. //PM_FlyMove
  1315. //===============
  1316. static void PM_FlyMove( qboolean doclip )
  1317. {
  1318.     float speed, drop, friction, control, newspeed;
  1319.     float currentspeed, addspeed, accelspeed, maxspeed;
  1320.     int i;
  1321.     vec3_t wishvel;
  1322.     float fmove, smove;
  1323.     vec3_t wishdir;
  1324.     float wishspeed;
  1325.     vec3_t end;
  1326.     trace_t trace;
  1327.  
  1328.     maxspeed = pml.maxPlayerSpeed * 1.5;
  1329.  
  1330.     if( pm->cmd.buttons & BUTTON_SPECIAL )
  1331.         maxspeed *= 2;
  1332.  
  1333.     // friction
  1334.     speed = VectorLength( pml.velocity );
  1335.     if( speed < 1 )
  1336.     {
  1337.         VectorClear( pml.velocity );
  1338.     }
  1339.     else
  1340.     {
  1341.         drop = 0;
  1342.  
  1343.         friction = pm_friction * 1.5; // extra friction
  1344.         control = speed < pm_decelerate ? pm_decelerate : speed;
  1345.         drop += control * friction * pml.frametime;
  1346.  
  1347.         // scale the velocity
  1348.         newspeed = speed - drop;
  1349.         if( newspeed < 0 )
  1350.             newspeed = 0;
  1351.         newspeed /= speed;
  1352.  
  1353.         VectorScale( pml.velocity, newspeed, pml.velocity );
  1354.     }
  1355.  
  1356.     // accelerate
  1357.     fmove = pml.forwardPush;
  1358.     smove = pml.sidePush;
  1359.  
  1360.     if( pm->cmd.buttons & BUTTON_SPECIAL )
  1361.     {
  1362.         fmove *= 2;
  1363.         smove *= 2;
  1364.     }
  1365.  
  1366.     VectorNormalize( pml.forward );
  1367.     VectorNormalize( pml.right );
  1368.  
  1369.     for( i = 0; i < 3; i++ )
  1370.         wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
  1371.     wishvel[2] += pml.upPush;
  1372.  
  1373.     VectorCopy( wishvel, wishdir );
  1374.     wishspeed = VectorNormalize( wishdir );
  1375.  
  1376.  
  1377.     // clamp to server defined max speed
  1378.     //
  1379.     if( wishspeed > maxspeed )
  1380.     {
  1381.         wishspeed = maxspeed/wishspeed;
  1382.         VectorScale( wishvel, wishspeed, wishvel );
  1383.         wishspeed = maxspeed;
  1384.     }
  1385.  
  1386.     currentspeed = DotProduct( pml.velocity, wishdir );
  1387.     addspeed = wishspeed - currentspeed;
  1388.     if( addspeed > 0 )
  1389.     {
  1390.         accelspeed = pm_accelerate * pml.frametime * wishspeed;
  1391.         if( accelspeed > addspeed )
  1392.             accelspeed = addspeed;
  1393.  
  1394.         for( i = 0; i < 3; i++ )
  1395.             pml.velocity[i] += accelspeed*wishdir[i];
  1396.     }
  1397.  
  1398.     if( doclip )
  1399.     {
  1400.         for( i = 0; i < 3; i++ )
  1401.             end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
  1402.  
  1403.         module_Trace( &trace, pml.origin, pm->mins, pm->maxs, end, pm->playerState->POVnum, pm->contentmask, 0 );
  1404.  
  1405.         VectorCopy( trace.endpos, pml.origin );
  1406.     }
  1407.     else
  1408.     {
  1409.         // move
  1410.         VectorMA( pml.origin, pml.frametime, pml.velocity, pml.origin );
  1411.     }
  1412. }
  1413.  
  1414. static void PM_CheckZoom( void )
  1415. {
  1416.     if( pm->playerState->pmove.pm_type != PM_NORMAL )
  1417.     {
  1418.         pm->playerState->pmove.stats[PM_STAT_ZOOMTIME] = 0;
  1419.         return;
  1420.     }
  1421.  
  1422.     if( ( pm->cmd.buttons & BUTTON_ZOOM ) && ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_ZOOM ) )
  1423.     {
  1424.         pm->playerState->pmove.stats[PM_STAT_ZOOMTIME] += pm->cmd.msec;
  1425.         clamp( pm->playerState->pmove.stats[PM_STAT_ZOOMTIME], 0, ZOOMTIME );
  1426.     }
  1427.     else if( pm->playerState->pmove.stats[PM_STAT_ZOOMTIME] > 0 )
  1428.     {
  1429.         pm->playerState->pmove.stats[PM_STAT_ZOOMTIME] -= pm->cmd.msec;
  1430.         clamp( pm->playerState->pmove.stats[PM_STAT_ZOOMTIME], 0, ZOOMTIME );
  1431.     }
  1432. }
  1433.  
  1434. //==============
  1435. //PM_AdjustBBox
  1436. //
  1437. //Sets mins, maxs, and pm->viewheight
  1438. //==============
  1439. static void PM_AdjustBBox( void )
  1440. {
  1441.     float crouchFrac;
  1442.     trace_t trace;
  1443.  
  1444.     if( pm->playerState->pmove.pm_type == PM_GIB )
  1445.     {
  1446.         pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] = 0;
  1447.         VectorCopy( playerbox_gib_maxs, pm->maxs );
  1448.         VectorCopy( playerbox_gib_mins, pm->mins );
  1449.         pm->playerState->viewheight = playerbox_gib_viewheight;
  1450.         return;
  1451.     }
  1452.  
  1453.     if( pm->playerState->pmove.pm_type >= PM_FREEZE )
  1454.     {
  1455.         pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] = 0;
  1456.         pm->playerState->viewheight = 0;
  1457.         return;
  1458.     }
  1459.  
  1460.     if( pm->playerState->pmove.pm_type == PM_SPECTATOR )
  1461.     {
  1462.         pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] = 0;
  1463.         pm->playerState->viewheight = playerbox_stand_viewheight;
  1464.     }
  1465.  
  1466.     if( pml.upPush < 0 && ( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_CROUCH ) &&
  1467.         pm->playerState->pmove.stats[PM_STAT_WJTIME] < ( PM_WALLJUMP_TIMEDELAY - PM_SPECIAL_CROUCH_INHIBIT ) &&
  1468.         pm->playerState->pmove.stats[PM_STAT_DASHTIME] < ( PM_DASHJUMP_TIMEDELAY - PM_SPECIAL_CROUCH_INHIBIT ) )
  1469.     {
  1470.         pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] += pm->cmd.msec;
  1471.         clamp( pm->playerState->pmove.stats[PM_STAT_CROUCHTIME], 0, CROUCHTIME );
  1472.  
  1473.         crouchFrac = (float)pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] / (float)CROUCHTIME;
  1474.         VectorLerp( playerbox_stand_mins, crouchFrac, playerbox_crouch_mins, pm->mins );
  1475.         VectorLerp( playerbox_stand_maxs, crouchFrac, playerbox_crouch_maxs, pm->maxs );
  1476.         pm->playerState->viewheight = playerbox_stand_viewheight - ( crouchFrac * ( playerbox_stand_viewheight - playerbox_crouch_viewheight ) );
  1477.  
  1478.         // it's going down, so, no need of checking for head-chomping
  1479.         return;
  1480.     }
  1481.  
  1482.     // it's crouched, but not pressing the crouch button anymore, try to stand up
  1483.     if( pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] != 0 )
  1484.     {
  1485.         vec3_t curmins, curmaxs, wishmins, wishmaxs;
  1486.         float curviewheight, wishviewheight;
  1487.         int newcrouchtime;
  1488.  
  1489.         // find the current size
  1490.         crouchFrac = (float)pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] / (float)CROUCHTIME;
  1491.         VectorLerp( playerbox_stand_mins, crouchFrac, playerbox_crouch_mins, curmins );
  1492.         VectorLerp( playerbox_stand_maxs, crouchFrac, playerbox_crouch_maxs, curmaxs );
  1493.         curviewheight = playerbox_stand_viewheight - ( crouchFrac * ( playerbox_stand_viewheight - playerbox_crouch_viewheight ) );
  1494.  
  1495.         if( !pm->cmd.msec ) // no need to continue
  1496.         {
  1497.             VectorCopy( curmins, pm->mins );
  1498.             VectorCopy( curmaxs, pm->maxs );
  1499.             pm->playerState->viewheight = curviewheight;
  1500.             return;
  1501.         }
  1502.  
  1503.         // find the desired size
  1504.         newcrouchtime = pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] - pm->cmd.msec;
  1505.         clamp( newcrouchtime, 0, CROUCHTIME );
  1506.         crouchFrac = (float)newcrouchtime / (float)CROUCHTIME;
  1507.         VectorLerp( playerbox_stand_mins, crouchFrac, playerbox_crouch_mins, wishmins );
  1508.         VectorLerp( playerbox_stand_maxs, crouchFrac, playerbox_crouch_maxs, wishmaxs );
  1509.         wishviewheight = playerbox_stand_viewheight - ( crouchFrac * ( playerbox_stand_viewheight - playerbox_crouch_viewheight ) );
  1510.  
  1511.         // check that the head is not blocked
  1512.         module_Trace( &trace, pml.origin, wishmins, wishmaxs, pml.origin, pm->playerState->POVnum, pm->contentmask, 0 );
  1513.         if( trace.allsolid || trace.startsolid )
  1514.         {
  1515.             // can't do the uncrouching, let the time alone and use old position
  1516.             VectorCopy( curmins, pm->mins );
  1517.             VectorCopy( curmaxs, pm->maxs );
  1518.             pm->playerState->viewheight = curviewheight;
  1519.             return;
  1520.         }
  1521.  
  1522.         // can do the uncrouching, use new position and update the time
  1523.         pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] = newcrouchtime;
  1524.         VectorCopy( wishmins, pm->mins );
  1525.         VectorCopy( wishmaxs, pm->maxs );
  1526.         pm->playerState->viewheight = wishviewheight;
  1527.         return;
  1528.     }
  1529.  
  1530.     // the player is not crouching at all
  1531.     VectorCopy( playerbox_stand_mins, pm->mins );
  1532.     VectorCopy( playerbox_stand_maxs, pm->maxs );
  1533.     pm->playerState->viewheight = playerbox_stand_viewheight;
  1534. }
  1535.  
  1536. //==============
  1537. //PM_AdjustViewheight
  1538. //==============
  1539. void PM_AdjustViewheight( void )
  1540. {
  1541.     float height;
  1542.     vec3_t pm_maxs, mins, maxs;
  1543.  
  1544.     if( pm->playerState->pmove.pm_type == PM_SPECTATOR )
  1545.     {
  1546.         VectorCopy( playerbox_stand_mins, mins );
  1547.         VectorCopy( playerbox_stand_maxs, maxs );
  1548.     }
  1549.     else
  1550.     {
  1551.         VectorCopy( pm->mins, mins );
  1552.         VectorCopy( pm->maxs, maxs );
  1553.     }
  1554.  
  1555.     VectorCopy( maxs, pm_maxs );
  1556.     module_RoundUpToHullSize( mins, maxs );
  1557.  
  1558.     height = pm_maxs[2] - maxs[2];
  1559.     if( height > 0 )
  1560.         pm->playerState->viewheight -= height;
  1561. }
  1562.  
  1563. static qboolean PM_GoodPosition( int snaptorigin[3] )
  1564. {
  1565.     trace_t trace;
  1566.     vec3_t origin, end;
  1567.     int i;
  1568.  
  1569.     if( pm->playerState->pmove.pm_type == PM_SPECTATOR )
  1570.         return qtrue;
  1571.  
  1572.     for( i = 0; i < 3; i++ )
  1573.         origin[i] = end[i] = snaptorigin[i]*( 1.0/PM_VECTOR_SNAP );
  1574.     module_Trace( &trace, origin, pm->mins, pm->maxs, end, pm->playerState->POVnum, pm->contentmask, 0 );
  1575.  
  1576.     return !trace.allsolid;
  1577. }
  1578.  
  1579. //================
  1580. //PM_SnapPosition
  1581. //
  1582. //On exit, the origin will have a value that is pre-quantized to the (1.0/16.0)
  1583. //precision of the network channel and in a valid position.
  1584. //================
  1585. static void PM_SnapPosition( void )
  1586. {
  1587.     int sign[3];
  1588.     int i, j, bits;
  1589.     int base[3];
  1590.     int velint[3], origint[3];
  1591.     // try all single bits first
  1592.     static const int jitterbits[8] = { 0, 4, 1, 2, 3, 5, 6, 7 };
  1593.  
  1594.     // snap velocity to sixteenths
  1595.     for( i = 0; i < 3; i++ )
  1596.     {
  1597.         velint[i] = (int)( pml.velocity[i]*PM_VECTOR_SNAP );
  1598.         pm->playerState->pmove.velocity[i] = velint[i]*( 1.0/PM_VECTOR_SNAP );
  1599.     }
  1600.  
  1601.     for( i = 0; i < 3; i++ )
  1602.     {
  1603.         if( pml.origin[i] >= 0 )
  1604.             sign[i] = 1;
  1605.         else
  1606.             sign[i] = -1;
  1607.         origint[i] = (int)( pml.origin[i]*PM_VECTOR_SNAP );
  1608.         if( origint[i]*( 1.0/PM_VECTOR_SNAP ) == pml.origin[i] )
  1609.             sign[i] = 0;
  1610.     }
  1611.     VectorCopy( origint, base );
  1612.  
  1613.     // try all combinations
  1614.     for( j = 0; j < 8; j++ )
  1615.     {
  1616.         bits = jitterbits[j];
  1617.         VectorCopy( base, origint );
  1618.         for( i = 0; i < 3; i++ )
  1619.             if( bits & ( 1<<i ) )
  1620.                 origint[i] += sign[i];
  1621.  
  1622.         if( PM_GoodPosition( origint ) )
  1623.         {
  1624.             VectorScale( origint, ( 1.0/PM_VECTOR_SNAP ), pm->playerState->pmove.origin );
  1625.             return;
  1626.         }
  1627.     }
  1628.  
  1629.     // go back to the last position
  1630.     VectorCopy( pml.previous_origin, pm->playerState->pmove.origin );
  1631.     VectorClear( pm->playerState->pmove.velocity );
  1632. }
  1633.  
  1634.  
  1635. //================
  1636. //PM_InitialSnapPosition
  1637. //
  1638. //================
  1639. static void PM_InitialSnapPosition( void )
  1640. {
  1641.     int x, y, z;
  1642.     int base[3];
  1643.     static const int offset[3] = { 0, -1, 1 };
  1644.     int origint[3];
  1645.  
  1646.     VectorScale( pm->playerState->pmove.origin, PM_VECTOR_SNAP, origint );
  1647.     VectorCopy( origint, base );
  1648.  
  1649.     for( z = 0; z < 3; z++ )
  1650.     {
  1651.         origint[2] = base[2] + offset[z];
  1652.         for( y = 0; y < 3; y++ )
  1653.         {
  1654.             origint[1] = base[1] + offset[y];
  1655.             for( x = 0; x < 3; x++ )
  1656.             {
  1657.                 origint[0] = base[0] + offset[x];
  1658.                 if( PM_GoodPosition( origint ) )
  1659.                 {
  1660.                     pml.origin[0] = pm->playerState->pmove.origin[0] = origint[0]*( 1.0/PM_VECTOR_SNAP );
  1661.                     pml.origin[1] = pm->playerState->pmove.origin[1] = origint[1]*( 1.0/PM_VECTOR_SNAP );
  1662.                     pml.origin[2] = pm->playerState->pmove.origin[2] = origint[2]*( 1.0/PM_VECTOR_SNAP );
  1663.                     VectorCopy( pm->playerState->pmove.origin, pml.previous_origin );
  1664.                     return;
  1665.                 }
  1666.             }
  1667.         }
  1668.     }
  1669. }
  1670.  
  1671. static void PM_UpdateDeltaAngles( void )
  1672. {
  1673.     int i;
  1674.  
  1675.     if( gs.module != GS_MODULE_GAME )
  1676.         return;
  1677.  
  1678.     for( i = 0; i < 3; i++ )
  1679.         pm->playerState->pmove.delta_angles[i] = ANGLE2SHORT( pm->playerState->viewangles[i] ) - pm->cmd.angles[i];
  1680. }
  1681.  
  1682. //================
  1683. //PM_ApplyMouseAnglesClamp
  1684. //
  1685. //================
  1686. #if defined ( _WIN32 ) && ( _MSC_VER >= 1400 )
  1687. #pragma warning( push )
  1688. #pragma warning( disable : 4310 )   // cast truncates constant value
  1689. #endif
  1690. static void PM_ApplyMouseAnglesClamp( void )
  1691. {
  1692.     int i;
  1693.     short temp;
  1694.  
  1695.     for( i = 0; i < 3; i++ )
  1696.     {
  1697.         temp = pm->cmd.angles[i] + pm->playerState->pmove.delta_angles[i];
  1698.         if( i == PITCH )
  1699.         {
  1700.             // don't let the player look up or down more than 90 degrees
  1701.             if( temp > (short)ANGLE2SHORT( 90 ) - 1 )
  1702.             {
  1703.                 pm->playerState->pmove.delta_angles[i] = ( ANGLE2SHORT( 90 ) - 1 ) - pm->cmd.angles[i];
  1704.                 temp = ANGLE2SHORT( 90 ) - 1;
  1705.             }
  1706.             else if( temp < (short)ANGLE2SHORT( -90 ) + 1 )
  1707.             {
  1708.                 pm->playerState->pmove.delta_angles[i] = ( ANGLE2SHORT( -90 ) + 1 ) - pm->cmd.angles[i];
  1709.                 temp = ANGLE2SHORT( -90 ) + 1;
  1710.             }
  1711.         }
  1712.  
  1713.         pm->playerState->viewangles[i] = SHORT2ANGLE( temp );
  1714.     }
  1715.  
  1716.     AngleVectors( pm->playerState->viewangles, pml.forward, pml.right, pml.up );
  1717.  
  1718.     VectorCopy( pml.forward, pml.flatforward );
  1719.     pml.flatforward[2] = 0.0f;
  1720.     VectorNormalize( pml.flatforward );
  1721. }
  1722. #if defined ( _WIN32 ) && ( _MSC_VER >= 1400 )
  1723. #pragma warning( pop )
  1724. #endif
  1725.  
  1726. //================
  1727. //Pmove
  1728. //
  1729. //Can be called by either the server or the client
  1730. //================
  1731. void Pmove( pmove_t *pmove )
  1732. {
  1733.     float fallvelocity, falldelta, damage;
  1734.     int oldGroundEntity;
  1735.  
  1736.     if( !pmove->playerState )
  1737.         return;
  1738.  
  1739.     pm = pmove;
  1740.  
  1741.     // clear results
  1742.     pm->numtouch = 0;
  1743.     pm->groundentity = -1;
  1744.     pm->watertype = 0;
  1745.     pm->waterlevel = 0;
  1746.     pm->step = qfalse;
  1747.  
  1748.     // clear all pmove local vars
  1749.     memset( &pml, 0, sizeof( pml ) );
  1750.  
  1751.     VectorCopy( pm->playerState->pmove.origin, pml.origin );
  1752.     VectorCopy( pm->playerState->pmove.velocity, pml.velocity );
  1753.  
  1754.     fallvelocity = ( ( pml.velocity[2] < 0.0f ) ? abs( pml.velocity[2] ) : 0.0f );
  1755.  
  1756.     // save old org in case we get stuck
  1757.     VectorCopy( pm->playerState->pmove.origin, pml.previous_origin );
  1758.  
  1759.     pml.frametime = pm->cmd.msec * 0.001;
  1760.  
  1761.     pml.maxPlayerSpeed = pm->playerState->pmove.stats[PM_STAT_MAXSPEED];
  1762.     if( pml.maxPlayerSpeed < 0 )
  1763.         pml.maxPlayerSpeed = DEFAULT_PLAYERSPEED;
  1764.  
  1765.     pml.jumpPlayerSpeed = (float)pm->playerState->pmove.stats[PM_STAT_JUMPSPEED] * GRAVITY_COMPENSATE;
  1766.     if( pml.jumpPlayerSpeed < 0 )
  1767.         pml.jumpPlayerSpeed = DEFAULT_JUMPSPEED * GRAVITY_COMPENSATE;
  1768.  
  1769.     pml.dashPlayerSpeed = pm->playerState->pmove.stats[PM_STAT_DASHSPEED];
  1770.     if( pml.dashPlayerSpeed < 0 )
  1771.         pml.dashPlayerSpeed = DEFAULT_DASHSPEED;
  1772.  
  1773.     pml.maxWalkSpeed = DEFAULT_WALKSPEED;
  1774.     if( pml.maxWalkSpeed > pml.maxPlayerSpeed * 0.66f )
  1775.         pml.maxWalkSpeed = pml.maxPlayerSpeed * 0.66f;
  1776.  
  1777.     pml.maxCrouchedSpeed = DEFAULT_CROUCHEDSPEED;
  1778.     if( pml.maxCrouchedSpeed > pml.maxPlayerSpeed * 0.5f )
  1779.         pml.maxCrouchedSpeed = pml.maxPlayerSpeed * 0.5f;
  1780.  
  1781.     // assign a contentmask for the movement type
  1782.     switch( pm->playerState->pmove.pm_type )
  1783.     {
  1784.     case PM_FREEZE:
  1785.     case PM_CHASECAM:
  1786.         if( gs.module == GS_MODULE_GAME )
  1787.             pm->playerState->pmove.pm_flags |= PMF_NO_PREDICTION;
  1788.         pm->contentmask = 0;
  1789.         break;
  1790.  
  1791.     case PM_GIB:
  1792.         if( gs.module == GS_MODULE_GAME )
  1793.             pm->playerState->pmove.pm_flags |= PMF_NO_PREDICTION;
  1794.         pm->contentmask = MASK_DEADSOLID;
  1795.         break;
  1796.  
  1797.     case PM_SPECTATOR:
  1798.         if( gs.module == GS_MODULE_GAME )
  1799.             pm->playerState->pmove.pm_flags &= ~PMF_NO_PREDICTION;
  1800.         pm->contentmask = MASK_DEADSOLID;
  1801.         break;
  1802.  
  1803.     default:
  1804.     case PM_NORMAL:
  1805.         if( gs.module == GS_MODULE_GAME )
  1806.             pm->playerState->pmove.pm_flags &= ~PMF_NO_PREDICTION;
  1807.         if( pm->playerState->pmove.stats[PM_STAT_FEATURES] & PMFEAT_GHOSTMOVE )
  1808.             pm->contentmask = MASK_DEADSOLID;
  1809.         else
  1810.             pm->contentmask = MASK_PLAYERSOLID;
  1811.         break;
  1812.     }
  1813.  
  1814.     if( ! GS_MatchPaused() )
  1815.     {
  1816.         // drop timing counters
  1817.         if( pm->playerState->pmove.pm_time )
  1818.         {
  1819.             int msec;
  1820.  
  1821.             msec = pm->cmd.msec >> 3;
  1822.             if( !msec )
  1823.                 msec = 1;
  1824.             if( msec >= pm->playerState->pmove.pm_time )
  1825.             {
  1826.                 pm->playerState->pmove.pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT );
  1827.                 pm->playerState->pmove.pm_time = 0;
  1828.             }
  1829.             else
  1830.                 pm->playerState->pmove.pm_time -= msec;
  1831.         }
  1832.  
  1833.         if( pm->playerState->pmove.stats[PM_STAT_NOUSERCONTROL] > 0 )
  1834.             pm->playerState->pmove.stats[PM_STAT_NOUSERCONTROL] -= pm->cmd.msec;
  1835.         else if( pm->playerState->pmove.stats[PM_STAT_NOUSERCONTROL] < 0 )
  1836.             pm->playerState->pmove.stats[PM_STAT_NOUSERCONTROL] = 0;
  1837.  
  1838.         if( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] > 0 )
  1839.             pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] -= pm->cmd.msec;
  1840.         else if( pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] < 0 )
  1841.             pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] = 0;
  1842.  
  1843.         // PM_STAT_CROUCHTIME is handled at PM_AdjustBBox
  1844.         // PM_STAT_ZOOMTIME is handled at PM_CheckZoom
  1845.  
  1846.         if( pm->playerState->pmove.stats[PM_STAT_DASHTIME] > 0 )
  1847.             pm->playerState->pmove.stats[PM_STAT_DASHTIME] -= pm->cmd.msec;
  1848.         else if( pm->playerState->pmove.stats[PM_STAT_DASHTIME] < 0 )
  1849.             pm->playerState->pmove.stats[PM_STAT_DASHTIME] = 0;
  1850.  
  1851.         if( pm->playerState->pmove.stats[PM_STAT_WJTIME] > 0 )
  1852.             pm->playerState->pmove.stats[PM_STAT_WJTIME] -= pm->cmd.msec;
  1853.         else if( pm->playerState->pmove.stats[PM_STAT_WJTIME] < 0 )
  1854.             pm->playerState->pmove.stats[PM_STAT_WJTIME] = 0;
  1855.  
  1856.         if( pm->playerState->pmove.stats[PM_STAT_NOAUTOATTACK] > 0 )
  1857.             pm->playerState->pmove.stats[PM_STAT_NOAUTOATTACK] -= pm->cmd.msec;
  1858.         else if( pm->playerState->pmove.stats[PM_STAT_NOAUTOATTACK] < 0 )
  1859.             pm->playerState->pmove.stats[PM_STAT_NOAUTOATTACK] = 0;
  1860.  
  1861.         if( pm->playerState->pmove.stats[PM_STAT_STUN] > 0 )
  1862.             pm->playerState->pmove.stats[PM_STAT_STUN] -= pm->cmd.msec;
  1863.         else if( pm->playerState->pmove.stats[PM_STAT_STUN] < 0 )
  1864.             pm->playerState->pmove.stats[PM_STAT_STUN] = 0;
  1865.     }
  1866.  
  1867.     pml.forwardPush = pm->cmd.forwardfrac * SPEEDKEY;
  1868.     pml.sidePush = pm->cmd.sidefrac * SPEEDKEY;
  1869.     pml.upPush = pm->cmd.upfrac * SPEEDKEY;
  1870.  
  1871.     if( pm->playerState->pmove.stats[PM_STAT_NOUSERCONTROL] > 0 )
  1872.     {
  1873.         pml.forwardPush = 0;
  1874.         pml.sidePush = 0;
  1875.         pml.upPush = 0;
  1876.         pm->cmd.buttons = 0;
  1877.     }
  1878.  
  1879.     if( pm->snapinitial )
  1880.         PM_InitialSnapPosition();
  1881.  
  1882.     if( pm->playerState->pmove.pm_type != PM_NORMAL ) // includes dead, freeze, chasecam...
  1883.     {
  1884.         if( !GS_MatchPaused() )
  1885.         {
  1886.             PM_ClearDash();
  1887.             PM_ClearWallJump();
  1888.             PM_ClearStun();
  1889.             pm->playerState->pmove.stats[PM_STAT_KNOCKBACK] = 0;
  1890.             pm->playerState->pmove.stats[PM_STAT_CROUCHTIME] = 0;
  1891.             pm->playerState->pmove.stats[PM_STAT_ZOOMTIME] = 0;
  1892.             pm->playerState->pmove.pm_flags &= ~(PMF_JUMPPAD_TIME|PMF_DOUBLEJUMPED|PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_TELEPORT|PMF_SPECIAL_HELD);
  1893.  
  1894.             PM_AdjustBBox();
  1895.         }
  1896.  
  1897.         PM_AdjustViewheight();
  1898.  
  1899.         if( pm->playerState->pmove.pm_type == PM_SPECTATOR )
  1900.         {
  1901.             PM_ApplyMouseAnglesClamp();
  1902.             PM_FlyMove( qfalse );
  1903.         }
  1904.         else
  1905.         {
  1906.             pml.forwardPush = 0;
  1907.             pml.sidePush = 0;
  1908.             pml.upPush = 0;
  1909.         }
  1910.        
  1911.         PM_SnapPosition();
  1912.         return;
  1913.     }
  1914.  
  1915.     PM_ApplyMouseAnglesClamp();
  1916.  
  1917.     // set mins, maxs, viewheight amd fov
  1918.     PM_AdjustBBox();
  1919.     PM_CheckZoom();
  1920.  
  1921.     // round up mins/maxs to hull size and adjust the viewheight, if needed
  1922.     PM_AdjustViewheight();
  1923.  
  1924.     // set groundentity, watertype, and waterlevel
  1925.     PM_CategorizePosition();
  1926.     oldGroundEntity = pm->groundentity;
  1927.  
  1928.     PM_CheckSpecialMovement();
  1929.  
  1930.     if( pm->playerState->pmove.pm_flags & PMF_TIME_TELEPORT )
  1931.     { // teleport pause stays exactly in place
  1932.     }
  1933.     else if( pm->playerState->pmove.pm_flags & PMF_TIME_WATERJUMP )
  1934.     { // waterjump has no control, but falls
  1935.         pml.velocity[2] -= pm->playerState->pmove.gravity * pml.frametime;
  1936.         if( pml.velocity[2] < 0 )
  1937.         { // cancel as soon as we are falling down again
  1938.             pm->playerState->pmove.pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT );
  1939.             pm->playerState->pmove.pm_time = 0;
  1940.         }
  1941.  
  1942.         PM_StepSlideMove();
  1943.     }
  1944.     else
  1945.     {
  1946.         // Kurim
  1947.         // Keep this order !
  1948.         PM_CheckJump();
  1949.         PM_CheckDash();
  1950.         PM_CheckWallJump();
  1951.  
  1952.         PM_Friction();
  1953.  
  1954.         if( pm->waterlevel >= 2 )
  1955.         {
  1956.             PM_WaterMove();
  1957.         }
  1958.         else
  1959.         {
  1960.             vec3_t angles;
  1961.  
  1962.             VectorCopy( pm->playerState->viewangles, angles );
  1963.             if( angles[PITCH] > 180 )
  1964.                 angles[PITCH] = angles[PITCH] - 360;
  1965.             angles[PITCH] /= 3;
  1966.  
  1967.             AngleVectors( angles, pml.forward, pml.right, pml.up );
  1968.  
  1969.             // hack to work when looking straight up and straight down
  1970.             if( pml.forward[2] == -1.0f )
  1971.             {
  1972.                 VectorCopy( pml.up, pml.flatforward );
  1973.             }
  1974.             else if( pml.forward[2] == 1.0f )
  1975.             {
  1976.                 VectorCopy( pml.up, pml.flatforward );
  1977.                 VectorNegate( pml.flatforward, pml.flatforward );
  1978.             }
  1979.             else
  1980.             {
  1981.                 VectorCopy( pml.forward, pml.flatforward );
  1982.             }
  1983.             pml.flatforward[2] = 0.0f;
  1984.             VectorNormalize( pml.flatforward );
  1985.  
  1986.             PM_Move();
  1987.         }
  1988.     }
  1989.  
  1990.     // set groundentity, watertype, and waterlevel for final spot
  1991.     PM_CategorizePosition();
  1992.     PM_SnapPosition();
  1993.  
  1994.     // falling event
  1995.  
  1996. #define FALL_DAMAGE_MIN_DELTA 675
  1997. #define FALL_STEP_MIN_DELTA 400
  1998. #define MAX_FALLING_DAMAGE 15
  1999. #define FALL_DAMAGE_SCALE 1.0
  2000.  
  2001.     // check for falling damage
  2002.     module_PMoveTouchTriggers( pm );
  2003.  
  2004.     PM_UpdateDeltaAngles(); // in case some trigger action has moved the view angles (like teleported).
  2005.  
  2006.     // touching triggers may force groundentity off
  2007.     if( !( pm->playerState->pmove.pm_flags & PMF_ON_GROUND ) && pm->groundentity != -1 )
  2008.     {
  2009.         pm->groundentity = -1;
  2010.         pml.velocity[2] = 0;
  2011.     }
  2012.  
  2013.     if( pm->groundentity != -1 ) // remove wall-jump and dash bits when touching ground
  2014.     {
  2015.         // always keep the dash flag 50 msecs at least (to prevent being removed at the start of the dash)
  2016.         if( pm->playerState->pmove.stats[PM_STAT_DASHTIME] < ( PM_DASHJUMP_TIMEDELAY - 50 ) )
  2017.             pm->playerState->pmove.pm_flags &= ~PMF_DASHING;
  2018.  
  2019.         if( pm->playerState->pmove.stats[PM_STAT_WJTIME] < ( PM_WALLJUMP_TIMEDELAY - 50 ) )
  2020.             PM_ClearWallJump();
  2021.     }
  2022.  
  2023.     if( oldGroundEntity == -1 )
  2024.     {
  2025.         falldelta = fallvelocity - ( ( pml.velocity[2] < 0.0f ) ? abs( pml.velocity[2] ) : 0.0f );
  2026.  
  2027.         // scale delta if in water
  2028.         if( pm->waterlevel == 3 )
  2029.             falldelta = 0;
  2030.         if( pm->waterlevel == 2 )
  2031.             falldelta *= 0.25;
  2032.         if( pm->waterlevel == 1 )
  2033.             falldelta *= 0.5;
  2034.  
  2035.         if( falldelta > FALL_STEP_MIN_DELTA )
  2036.         {
  2037.             if( !GS_FallDamage() || ( pml.groundsurfFlags & SURF_NODAMAGE ) || ( pm->playerState->pmove.pm_flags & PMF_JUMPPAD_TIME ) )
  2038.                 damage = 0;
  2039.             else
  2040.             {
  2041.                 damage = ( ( falldelta - FALL_DAMAGE_MIN_DELTA ) / 10 ) * FALL_DAMAGE_SCALE;
  2042.                 clamp( damage, 0.0f, MAX_FALLING_DAMAGE );
  2043.             }
  2044.  
  2045.             module_PredictedEvent( pm->playerState->POVnum, EV_FALL, damage );
  2046.         }
  2047.  
  2048.         pm->playerState->pmove.pm_flags &= ~PMF_JUMPPAD_TIME;
  2049.     }
  2050. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement