home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quakeworld_src / client / pmove.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  19.3 KB  |  905 lines

  1. /*
  2. Copyright (C) 1996-1997 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 "quakedef.h"
  22.  
  23.  
  24. movevars_t    movevars;
  25.  
  26. playermove_t  pmove;
  27.  
  28. int     onground;
  29. int     waterlevel;
  30. int     watertype;
  31.  
  32. float   frametime;
  33.  
  34. vec3_t    forward, right, up;
  35.  
  36. vec3_t  player_mins = {-16, -16, -24};
  37. vec3_t  player_maxs = {16, 16, 32};
  38.  
  39. // #define  PM_GRAVITY      800
  40. // #define  PM_STOPSPEED    100
  41. // #define  PM_MAXSPEED     320
  42. // #define  PM_SPECTATORMAXSPEED  500
  43. // #define  PM_ACCELERATE   10
  44. // #define  PM_AIRACCELERATE  0.7
  45. // #define  PM_WATERACCELERATE  10
  46. // #define  PM_FRICTION     6
  47. // #define  PM_WATERFRICTION  1
  48.  
  49. void PM_InitBoxHull (void);
  50.  
  51. void Pmove_Init (void)
  52. {
  53.   PM_InitBoxHull ();
  54. }
  55.  
  56. #define STEPSIZE  18
  57.  
  58.  
  59. #define BUTTON_JUMP 2
  60.  
  61.  
  62. /*
  63. ==================
  64. PM_ClipVelocity
  65.  
  66. Slide off of the impacting object
  67. returns the blocked flags (1 = floor, 2 = step / wall)
  68. ==================
  69. */
  70. #define STOP_EPSILON  0.1
  71.  
  72. int PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
  73. {
  74.   float backoff;
  75.   float change;
  76.   int   i, blocked;
  77.   
  78.   blocked = 0;
  79.   if (normal[2] > 0)
  80.     blocked |= 1;   // floor
  81.   if (!normal[2])
  82.     blocked |= 2;   // step
  83.   
  84.   backoff = DotProduct (in, normal) * overbounce;
  85.  
  86.   for (i=0 ; i<3 ; i++)
  87.   {
  88.     change = normal[i]*backoff;
  89.     out[i] = in[i] - change;
  90.     if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
  91.       out[i] = 0;
  92.   }
  93.   
  94.   return blocked;
  95. }
  96.  
  97.  
  98. /*
  99. ============
  100. PM_FlyMove
  101.  
  102. The basic solid body movement clip that slides along multiple planes
  103. ============
  104. */
  105. #define MAX_CLIP_PLANES 5
  106.  
  107. int PM_FlyMove (void)
  108. {
  109.   int     bumpcount, numbumps;
  110.   vec3_t    dir;
  111.   float   d;
  112.   int     numplanes;
  113.   vec3_t    planes[MAX_CLIP_PLANES];
  114.   vec3_t    primal_velocity, original_velocity;
  115.   int     i, j;
  116.   pmtrace_t   trace;
  117.   vec3_t    end;
  118.   float   time_left;
  119.   int     blocked;
  120.   
  121.   numbumps = 4;
  122.   
  123.   blocked = 0;
  124.   VectorCopy (pmove.velocity, original_velocity);
  125.   VectorCopy (pmove.velocity, primal_velocity);
  126.   numplanes = 0;
  127.   
  128.   time_left = frametime;
  129.  
  130.   for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
  131.   {
  132.     for (i=0 ; i<3 ; i++)
  133.       end[i] = pmove.origin[i] + time_left * pmove.velocity[i];
  134.  
  135.     trace = PM_PlayerMove (pmove.origin, end);
  136.  
  137.     if (trace.startsolid || trace.allsolid)
  138.     { // entity is trapped in another solid
  139.       VectorCopy (vec3_origin, pmove.velocity);
  140.       return 3;
  141.     }
  142.  
  143.     if (trace.fraction > 0)
  144.     { // actually covered some distance
  145.       VectorCopy (trace.endpos, pmove.origin);
  146.       numplanes = 0;
  147.     }
  148.  
  149.     if (trace.fraction == 1)
  150.        break;   // moved the entire distance
  151.  
  152.     // save entity for contact
  153.     pmove.touchindex[pmove.numtouch] = trace.ent;
  154.     pmove.numtouch++;
  155.  
  156.     if (trace.plane.normal[2] > 0.7)
  157.     {
  158.       blocked |= 1;   // floor
  159.     }
  160.     if (!trace.plane.normal[2])
  161.     {
  162.       blocked |= 2;   // step
  163.     }
  164.  
  165.     time_left -= time_left * trace.fraction;
  166.     
  167.   // cliped to another plane
  168.     if (numplanes >= MAX_CLIP_PLANES)
  169.     { // this shouldn't really happen
  170.       VectorCopy (vec3_origin, pmove.velocity);
  171.       break;
  172.     }
  173.  
  174.     VectorCopy (trace.plane.normal, planes[numplanes]);
  175.     numplanes++;
  176.  
  177. //
  178. // modify original_velocity so it parallels all of the clip planes
  179. //
  180.     for (i=0 ; i<numplanes ; i++)
  181.     {
  182.       PM_ClipVelocity (original_velocity, planes[i], pmove.velocity, 1);
  183.       for (j=0 ; j<numplanes ; j++)
  184.         if (j != i)
  185.         {
  186.           if (DotProduct (pmove.velocity, planes[j]) < 0)
  187.             break;  // not ok
  188.         }
  189.       if (j == numplanes)
  190.         break;
  191.     }
  192.     
  193.     if (i != numplanes)
  194.     { // go along this plane
  195.     }
  196.     else
  197.     { // go along the crease
  198.       if (numplanes != 2)
  199.       {
  200. //        Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
  201.         VectorCopy (vec3_origin, pmove.velocity);
  202.         break;
  203.       }
  204.       CrossProduct (planes[0], planes[1], dir);
  205.       d = DotProduct (dir, pmove.velocity);
  206.       VectorScale (dir, d, pmove.velocity);
  207.     }
  208.  
  209. //
  210. // if original velocity is against the original velocity, stop dead
  211. // to avoid tiny occilations in sloping corners
  212. //
  213.     if (DotProduct (pmove.velocity, primal_velocity) <= 0)
  214.     {
  215.       VectorCopy (vec3_origin, pmove.velocity);
  216.       break;
  217.     }
  218.   }
  219.  
  220.   if (pmove.waterjumptime)
  221.   {
  222.     VectorCopy (primal_velocity, pmove.velocity);
  223.   }
  224.   return blocked;
  225. }
  226.  
  227. /*
  228. =============
  229. PM_GroundMove
  230.  
  231. Player is on ground, with no upwards velocity
  232. =============
  233. */
  234. void PM_GroundMove (void)
  235. {
  236.   vec3_t  start, dest;
  237.   pmtrace_t trace;
  238.   vec3_t  original, originalvel, down, up, downvel;
  239.   float downdist, updist;
  240.  
  241.   pmove.velocity[2] = 0;
  242.   if (!pmove.velocity[0] && !pmove.velocity[1] && !pmove.velocity[2])
  243.     return;
  244.  
  245.   // first try just moving to the destination 
  246.   dest[0] = pmove.origin[0] + pmove.velocity[0]*frametime;
  247.   dest[1] = pmove.origin[1] + pmove.velocity[1]*frametime;  
  248.   dest[2] = pmove.origin[2];
  249.  
  250.   // first try moving directly to the next spot
  251.   VectorCopy (dest, start);
  252.   trace = PM_PlayerMove (pmove.origin, dest);
  253.   if (trace.fraction == 1)
  254.   {
  255.     VectorCopy (trace.endpos, pmove.origin);
  256.     return;
  257.   }
  258.  
  259.   // try sliding forward both on ground and up 16 pixels
  260.   // take the move that goes farthest
  261.   VectorCopy (pmove.origin, original);
  262.   VectorCopy (pmove.velocity, originalvel);
  263.  
  264.   // slide move
  265.   PM_FlyMove ();
  266.  
  267.   VectorCopy (pmove.origin, down);
  268.   VectorCopy (pmove.velocity, downvel);
  269.  
  270.   VectorCopy (original, pmove.origin);
  271.   VectorCopy (originalvel, pmove.velocity);
  272.  
  273. // move up a stair height
  274.   VectorCopy (pmove.origin, dest);
  275.   dest[2] += STEPSIZE;
  276.   trace = PM_PlayerMove (pmove.origin, dest);
  277.   if (!trace.startsolid && !trace.allsolid)
  278.   {
  279.     VectorCopy (trace.endpos, pmove.origin);
  280.   }
  281.  
  282. // slide move
  283.   PM_FlyMove ();
  284.  
  285. // press down the stepheight
  286.   VectorCopy (pmove.origin, dest);
  287.   dest[2] -= STEPSIZE;
  288.   trace = PM_PlayerMove (pmove.origin, dest);
  289.   if ( trace.plane.normal[2] < 0.7)
  290.     goto usedown;
  291.   if (!trace.startsolid && !trace.allsolid)
  292.   {
  293.     VectorCopy (trace.endpos, pmove.origin);
  294.   }
  295.   VectorCopy (pmove.origin, up);
  296.  
  297.   // decide which one went farther
  298.   downdist = (down[0] - original[0])*(down[0] - original[0])
  299.     + (down[1] - original[1])*(down[1] - original[1]);
  300.   updist = (up[0] - original[0])*(up[0] - original[0])
  301.     + (up[1] - original[1])*(up[1] - original[1]);
  302.  
  303.   if (downdist > updist)
  304.   {
  305. usedown:
  306.     VectorCopy (down, pmove.origin);
  307.     VectorCopy (downvel, pmove.velocity);
  308.   } else // copy z value from slide move
  309.     pmove.velocity[2] = downvel[2];
  310.  
  311. // if at a dead stop, retry the move with nudges to get around lips
  312.  
  313. }
  314.  
  315.  
  316.  
  317. /*
  318. ==================
  319. PM_Friction
  320.  
  321. Handles both ground friction and water friction
  322. ==================
  323. */
  324. void PM_Friction (void)
  325. {
  326.   float *vel;
  327.   float speed, newspeed, control;
  328.   float friction;
  329.   float drop;
  330.   vec3_t  start, stop;
  331.   pmtrace_t   trace;
  332.   
  333.   if (pmove.waterjumptime)
  334.     return;
  335.  
  336.   vel = pmove.velocity;
  337.   
  338.   speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
  339.   if (speed < 1)
  340.   {
  341.     vel[0] = 0;
  342.     vel[1] = 0;
  343.     return;
  344.   }
  345.  
  346.   friction = movevars.friction;
  347.  
  348. // if the leading edge is over a dropoff, increase friction
  349.   if (onground != -1) {
  350.     start[0] = stop[0] = pmove.origin[0] + vel[0]/speed*16;
  351.     start[1] = stop[1] = pmove.origin[1] + vel[1]/speed*16;
  352.     start[2] = pmove.origin[2] + player_mins[2];
  353.     stop[2] = start[2] - 34;
  354.  
  355.     trace = PM_PlayerMove (start, stop);
  356.  
  357.     if (trace.fraction == 1) {
  358.       friction *= 2;
  359.     }
  360.   }
  361.  
  362.   drop = 0;
  363.  
  364.   if (waterlevel >= 2) // apply water friction
  365.     drop += speed*movevars.waterfriction*waterlevel*frametime;
  366.   else if (onground != -1) // apply ground friction
  367.   {
  368.     control = speed < movevars.stopspeed ? movevars.stopspeed : speed;
  369.     drop += control*friction*frametime;
  370.   }
  371.  
  372.  
  373. // scale the velocity
  374.   newspeed = speed - drop;
  375.   if (newspeed < 0)
  376.     newspeed = 0;
  377.   newspeed /= speed;
  378.  
  379.   vel[0] = vel[0] * newspeed;
  380.   vel[1] = vel[1] * newspeed;
  381.   vel[2] = vel[2] * newspeed;
  382. }
  383.  
  384.  
  385. /*
  386. ==============
  387. PM_Accelerate
  388. ==============
  389. */
  390. void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
  391. {
  392.   int     i;
  393.   float   addspeed, accelspeed, currentspeed;
  394.  
  395.   if (pmove.dead)
  396.     return;
  397.   if (pmove.waterjumptime)
  398.     return;
  399.  
  400.   currentspeed = DotProduct (pmove.velocity, wishdir);
  401.   addspeed = wishspeed - currentspeed;
  402.   if (addspeed <= 0)
  403.     return;
  404.   accelspeed = accel*frametime*wishspeed;
  405.   if (accelspeed > addspeed)
  406.     accelspeed = addspeed;
  407.   
  408.   for (i=0 ; i<3 ; i++)
  409.     pmove.velocity[i] += accelspeed*wishdir[i]; 
  410. }
  411.  
  412. void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
  413. {
  414.   int     i;
  415.   float   addspeed, accelspeed, currentspeed, wishspd = wishspeed;
  416.     
  417.   if (pmove.dead)
  418.     return;
  419.   if (pmove.waterjumptime)
  420.     return;
  421.  
  422.   if (wishspd > 30)
  423.     wishspd = 30;
  424.   currentspeed = DotProduct (pmove.velocity, wishdir);
  425.   addspeed = wishspd - currentspeed;
  426.   if (addspeed <= 0)
  427.     return;
  428.   accelspeed = accel * wishspeed * frametime;
  429.   if (accelspeed > addspeed)
  430.     accelspeed = addspeed;
  431.   
  432.   for (i=0 ; i<3 ; i++)
  433.     pmove.velocity[i] += accelspeed*wishdir[i]; 
  434. }
  435.  
  436.  
  437.  
  438. /*
  439. ===================
  440. PM_WaterMove
  441.  
  442. ===================
  443. */
  444. void PM_WaterMove (void)
  445. {
  446.   int   i;
  447.   vec3_t  wishvel;
  448.   float wishspeed;
  449.   vec3_t  wishdir;
  450.   vec3_t  start, dest;
  451.   pmtrace_t trace;
  452.  
  453. //
  454. // user intentions
  455. //
  456.   for (i=0 ; i<3 ; i++)
  457.     wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove;
  458.  
  459.   if (!pmove.cmd.forwardmove && !pmove.cmd.sidemove && !pmove.cmd.upmove)
  460.     wishvel[2] -= 60;   // drift towards bottom
  461.   else
  462.     wishvel[2] += pmove.cmd.upmove;
  463.  
  464.   VectorCopy (wishvel, wishdir);
  465.   wishspeed = VectorNormalize(wishdir);
  466.  
  467.   if (wishspeed > movevars.maxspeed)
  468.   {
  469.     VectorScale (wishvel, movevars.maxspeed/wishspeed, wishvel);
  470.     wishspeed = movevars.maxspeed;
  471.   }
  472.   wishspeed *= 0.7;
  473.  
  474. //
  475. // water acceleration
  476. //
  477. //  if (pmove.waterjumptime)
  478. //    Con_Printf ("wm->%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]);
  479.   PM_Accelerate (wishdir, wishspeed, movevars.wateraccelerate);
  480.  
  481. // assume it is a stair or a slope, so press down from stepheight above
  482.   VectorMA (pmove.origin, frametime, pmove.velocity, dest);
  483.   VectorCopy (dest, start);
  484.   start[2] += STEPSIZE + 1;
  485.   trace = PM_PlayerMove (start, dest);
  486.   if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope?
  487.   { // walked up the step
  488.     VectorCopy (trace.endpos, pmove.origin);
  489.     return;
  490.   }
  491.   
  492.   PM_FlyMove ();
  493. //  if (pmove.waterjumptime)
  494. //    Con_Printf ("<-wm%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]);
  495. }
  496.  
  497.  
  498. /*
  499. ===================
  500. PM_AirMove
  501.  
  502. ===================
  503. */
  504. void PM_AirMove (void)
  505. {
  506.   int     i;
  507.   vec3_t    wishvel;
  508.   float   fmove, smove;
  509.   vec3_t    wishdir;
  510.   float   wishspeed;
  511.  
  512.   fmove = pmove.cmd.forwardmove;
  513.   smove = pmove.cmd.sidemove;
  514.   
  515.   forward[2] = 0;
  516.   right[2] = 0;
  517.   VectorNormalize (forward);
  518.   VectorNormalize (right);
  519.  
  520.   for (i=0 ; i<2 ; i++)
  521.     wishvel[i] = forward[i]*fmove + right[i]*smove;
  522.   wishvel[2] = 0;
  523.  
  524.   VectorCopy (wishvel, wishdir);
  525.   wishspeed = VectorNormalize(wishdir);
  526.  
  527. //
  528. // clamp to server defined max speed
  529. //
  530.   if (wishspeed > movevars.maxspeed)
  531.   {
  532.     VectorScale (wishvel, movevars.maxspeed/wishspeed, wishvel);
  533.     wishspeed = movevars.maxspeed;
  534.   }
  535.   
  536. //  if (pmove.waterjumptime)
  537. //    Con_Printf ("am->%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]);
  538.  
  539.   if ( onground != -1)
  540.   {
  541.     pmove.velocity[2] = 0;
  542.     PM_Accelerate (wishdir, wishspeed, movevars.accelerate);
  543.     pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime;
  544.     PM_GroundMove ();
  545.   }
  546.   else
  547.   { // not on ground, so little effect on velocity
  548.     PM_AirAccelerate (wishdir, wishspeed, movevars.accelerate);
  549.  
  550.     // add gravity
  551.     pmove.velocity[2] -= movevars.entgravity * movevars.gravity * frametime;
  552.  
  553.     PM_FlyMove ();
  554.  
  555.   }
  556.  
  557. //Con_Printf("airmove:vec: %4.2f %4.2f %4.2f\n",
  558. //      pmove.velocity[0],
  559. //      pmove.velocity[1],
  560. //      pmove.velocity[2]);
  561. //
  562.  
  563. //  if (pmove.waterjumptime)
  564. //    Con_Printf ("<-am%f, %f, %f\n", pmove.velocity[0], pmove.velocity[1], pmove.velocity[2]);
  565. }
  566.  
  567.  
  568.  
  569. /*
  570. =============
  571. PM_CatagorizePosition
  572. =============
  573. */
  574. void PM_CatagorizePosition (void)
  575. {
  576.   vec3_t    point;
  577.   int     cont;
  578.   pmtrace_t   tr;
  579.  
  580. // if the player hull point one unit down is solid, the player
  581. // is on ground
  582.  
  583. // see if standing on something solid 
  584.   point[0] = pmove.origin[0];
  585.   point[1] = pmove.origin[1];
  586.   point[2] = pmove.origin[2] - 1;
  587.   if (pmove.velocity[2] > 180)
  588.   {
  589.     onground = -1;
  590.   }
  591.   else
  592.   {
  593.     tr = PM_PlayerMove (pmove.origin, point);
  594.     if ( tr.plane.normal[2] < 0.7)
  595.       onground = -1;  // too steep
  596.     else
  597.       onground = tr.ent;
  598.     if (onground != -1)
  599.     {
  600.       pmove.waterjumptime = 0;
  601.       if (!tr.startsolid && !tr.allsolid)
  602.         VectorCopy (tr.endpos, pmove.origin);
  603.     }
  604.  
  605.     // standing on an entity other than the world
  606.     if (tr.ent > 0)
  607.     {
  608.       pmove.touchindex[pmove.numtouch] = tr.ent;
  609.       pmove.numtouch++;
  610.     }
  611.   }
  612.  
  613. //
  614. // get waterlevel
  615. //
  616.   waterlevel = 0;
  617.   watertype = CONTENTS_EMPTY;
  618.  
  619.   point[2] = pmove.origin[2] + player_mins[2] + 1;  
  620.   cont = PM_PointContents (point);
  621.  
  622.   if (cont <= CONTENTS_WATER)
  623.   {
  624.     watertype = cont;
  625.     waterlevel = 1;
  626.     point[2] = pmove.origin[2] + (player_mins[2] + player_maxs[2])*0.5;
  627.     cont = PM_PointContents (point);
  628.     if (cont <= CONTENTS_WATER)
  629.     {
  630.       waterlevel = 2;
  631.       point[2] = pmove.origin[2] + 22;
  632.       cont = PM_PointContents (point);
  633.       if (cont <= CONTENTS_WATER)
  634.         waterlevel = 3;
  635.     }
  636.   }
  637. }
  638.  
  639.  
  640. /*
  641. =============
  642. JumpButton
  643. =============
  644. */
  645. void JumpButton (void)
  646. {
  647.   if (pmove.dead)
  648.   {
  649.     pmove.oldbuttons |= BUTTON_JUMP;  // don't jump again until released
  650.     return;
  651.   }
  652.  
  653.   if (pmove.waterjumptime)
  654.   {
  655.     pmove.waterjumptime -= frametime;
  656.     if (pmove.waterjumptime < 0)
  657.       pmove.waterjumptime = 0;
  658.     return;
  659.   }
  660.  
  661.   if (waterlevel >= 2)
  662.   { // swimming, not jumping
  663.     onground = -1;
  664.  
  665.     if (watertype == CONTENTS_WATER)
  666.       pmove.velocity[2] = 100;
  667.     else if (watertype == CONTENTS_SLIME)
  668.       pmove.velocity[2] = 80;
  669.     else
  670.       pmove.velocity[2] = 50;
  671.     return;
  672.   }
  673.  
  674.   if (onground == -1)
  675.     return;   // in air, so no effect
  676.  
  677.   if ( pmove.oldbuttons & BUTTON_JUMP )
  678.     return;   // don't pogo stick
  679.  
  680.   onground = -1;
  681.   pmove.velocity[2] += 270;
  682.  
  683.   pmove.oldbuttons |= BUTTON_JUMP;  // don't jump again until released
  684. }
  685.  
  686. /*
  687. =============
  688. CheckWaterJump
  689. =============
  690. */
  691. void CheckWaterJump (void)
  692. {
  693.   vec3_t  spot;
  694.   int   cont;
  695.   vec3_t  flatforward;
  696.  
  697.   if (pmove.waterjumptime)
  698.     return;
  699.  
  700.   // ZOID, don't hop out if we just jumped in
  701.   if (pmove.velocity[2] < -180)
  702.     return; // only hop out if we are moving up
  703.  
  704.   // see if near an edge
  705.   flatforward[0] = forward[0];
  706.   flatforward[1] = forward[1];
  707.   flatforward[2] = 0;
  708.   VectorNormalize (flatforward);
  709.  
  710.   VectorMA (pmove.origin, 24, flatforward, spot);
  711.   spot[2] += 8;
  712.   cont = PM_PointContents (spot);
  713.   if (cont != CONTENTS_SOLID)
  714.     return;
  715.   spot[2] += 24;
  716.   cont = PM_PointContents (spot);
  717.   if (cont != CONTENTS_EMPTY)
  718.     return;
  719.   // jump out of water
  720.   VectorScale (flatforward, 50, pmove.velocity);
  721.   pmove.velocity[2] = 310;
  722.   pmove.waterjumptime = 2;  // safety net
  723.   pmove.oldbuttons |= BUTTON_JUMP;  // don't jump again until released
  724. }
  725.  
  726. /*
  727. =================
  728. NudgePosition
  729.  
  730. If pmove.origin is in a solid position,
  731. try nudging slightly on all axis to
  732. allow for the cut precision of the net coordinates
  733. =================
  734. */
  735. void NudgePosition (void)
  736. {
  737.   vec3_t  base;
  738.   int   x, y, z;
  739.   int   i;
  740.   static int    sign[3] = {0, -1, 1};
  741.  
  742.   VectorCopy (pmove.origin, base);
  743.  
  744.   for (i=0 ; i<3 ; i++)
  745.     pmove.origin[i] = ((int)(pmove.origin[i]*8)) * 0.125;
  746. //  pmove.origin[2] += 0.124;
  747.  
  748. //  if (pmove.dead)
  749. //    return;   // might be a squished point, so don'y bother
  750. //  if (PM_TestPlayerPosition (pmove.origin) )
  751. //    return;
  752.  
  753.   for (z=0 ; z<=2 ; z++)
  754.   {
  755.     for (x=0 ; x<=2 ; x++)
  756.     {
  757.       for (y=0 ; y<=2 ; y++)
  758.       {
  759.         pmove.origin[0] = base[0] + (sign[x] * 1.0/8);
  760.         pmove.origin[1] = base[1] + (sign[y] * 1.0/8);
  761.         pmove.origin[2] = base[2] + (sign[z] * 1.0/8);
  762.         if (PM_TestPlayerPosition (pmove.origin))
  763.           return;
  764.       }
  765.     }
  766.   }
  767.   VectorCopy (base, pmove.origin);
  768. //  Con_DPrintf ("NudgePosition: stuck\n");
  769. }
  770.  
  771. /*
  772. ===============
  773. SpectatorMove
  774. ===============
  775. */
  776. void SpectatorMove (void)
  777. {
  778.   float speed, drop, friction, control, newspeed, accel;
  779.   float currentspeed, addspeed, accelspeed;
  780.   int     i;
  781.   vec3_t    wishvel;
  782.   float   fmove, smove;
  783.   vec3_t    wishdir;
  784.   float   wishspeed;
  785. #ifndef SERVERONLY
  786.   extern float  server_version; // version of server we connected to
  787. #endif
  788.  
  789.   // friction
  790.  
  791.   speed = Length (pmove.velocity);
  792.   if (speed < 1)
  793.   {
  794.     VectorCopy (vec3_origin, pmove.velocity)
  795.   }
  796.   else
  797.   {
  798.     drop = 0;
  799.  
  800.     friction = movevars.friction*1.5; // extra friction
  801.     control = speed < movevars.stopspeed ? movevars.stopspeed : speed;
  802.     drop += control*friction*frametime;
  803.  
  804.     // scale the velocity
  805.     newspeed = speed - drop;
  806.     if (newspeed < 0)
  807.       newspeed = 0;
  808.     newspeed /= speed;
  809.  
  810.     VectorScale (pmove.velocity, newspeed, pmove.velocity);
  811.   }
  812.  
  813.   // accelerate
  814.   fmove = pmove.cmd.forwardmove;
  815.   smove = pmove.cmd.sidemove;
  816.   
  817.   VectorNormalize (forward);
  818.   VectorNormalize (right);
  819.  
  820.   for (i=0 ; i<3 ; i++)
  821.     wishvel[i] = forward[i]*fmove + right[i]*smove;
  822.   wishvel[2] += pmove.cmd.upmove;
  823.  
  824.   VectorCopy (wishvel, wishdir);
  825.   wishspeed = VectorNormalize(wishdir);
  826.  
  827.   //
  828.   // clamp to server defined max speed
  829.   //
  830.   if (wishspeed > movevars.spectatormaxspeed)
  831.   {
  832.     VectorScale (wishvel, movevars.spectatormaxspeed/wishspeed, wishvel);
  833.     wishspeed = movevars.spectatormaxspeed;
  834.   }
  835.  
  836.   currentspeed = DotProduct(pmove.velocity, wishdir);
  837.   addspeed = wishspeed - currentspeed;
  838.   if (addspeed <= 0)
  839.     return;
  840.   accelspeed = movevars.accelerate*frametime*wishspeed;
  841.   if (accelspeed > addspeed)
  842.     accelspeed = addspeed;
  843.   
  844.   for (i=0 ; i<3 ; i++)
  845.     pmove.velocity[i] += accelspeed*wishdir[i]; 
  846.  
  847.  
  848.   // move
  849.   VectorMA (pmove.origin, frametime, pmove.velocity, pmove.origin);
  850. }
  851.  
  852. /*
  853. =============
  854. PlayerMove
  855.  
  856. Returns with origin, angles, and velocity modified in place.
  857.  
  858. Numtouch and touchindex[] will be set if any of the physents
  859. were contacted during the move.
  860. =============
  861. */
  862. void PlayerMove (void)
  863. {
  864.   frametime = pmove.cmd.msec * 0.001;
  865.   pmove.numtouch = 0;
  866.  
  867.   AngleVectors (pmove.angles, forward, right, up);
  868.  
  869.   if (pmove.spectator)
  870.   {
  871.     SpectatorMove ();
  872.     return;
  873.   }
  874.  
  875.   NudgePosition ();
  876.  
  877.   // take angles directly from command
  878.   VectorCopy (pmove.cmd.angles, pmove.angles);
  879.  
  880.   // set onground, watertype, and waterlevel
  881.   PM_CatagorizePosition ();
  882.  
  883.   if (waterlevel == 2)
  884.     CheckWaterJump ();
  885.  
  886.   if (pmove.velocity[2] < 0)
  887.     pmove.waterjumptime = 0;
  888.  
  889.   if (pmove.cmd.buttons & BUTTON_JUMP)
  890.     JumpButton ();
  891.   else
  892.     pmove.oldbuttons &= ~BUTTON_JUMP;
  893.  
  894.   PM_Friction ();
  895.  
  896.   if (waterlevel >= 2)
  897.     PM_WaterMove ();
  898.   else
  899.     PM_AirMove ();
  900.  
  901.   // set onground, watertype, and waterlevel for final spot
  902.   PM_CatagorizePosition ();
  903. }
  904.  
  905.