home *** CD-ROM | disk | FTP | other *** search
/ Gambler 19 / GAMBLERCD19.BIN / UTILS / 3D / BRONIE / DUAL_LAU.ZIP / src / g_phys.c < prev    next >
C/C++ Source or Header  |  1997-11-25  |  21KB  |  932 lines

  1. // g_phys.c
  2.  
  3. #include "g_local.h"
  4.  
  5. /*
  6.  
  7.  
  8. pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
  9.  
  10. onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects 
  11.  
  12. doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
  13. bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
  14. corpses are SOLID_NOT and MOVETYPE_TOSS
  15. crates are SOLID_BBOX and MOVETYPE_TOSS
  16. walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
  17. flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
  18.  
  19. solid_edge items only clip against bsp models.
  20.  
  21. */
  22.  
  23.  
  24. /*
  25. ============
  26. SV_TestEntityPosition
  27.  
  28. ============
  29. */
  30. edict_t    *SV_TestEntityPosition (edict_t *ent)
  31. {
  32.     trace_t    trace;
  33.  
  34.     trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, MASK_SOLID);
  35.     
  36.     if (trace.startsolid)
  37.         return g_edicts;
  38.         
  39.     return NULL;
  40. }
  41.  
  42.  
  43. /*
  44. ================
  45. SV_CheckVelocity
  46. ================
  47. */
  48. void SV_CheckVelocity (edict_t *ent)
  49. {
  50.     int        i;
  51.  
  52. //
  53. // bound velocity
  54. //
  55.     for (i=0 ; i<3 ; i++)
  56.     {
  57.         if (ent->velocity[i] > sv_maxvelocity->value)
  58.             ent->velocity[i] = sv_maxvelocity->value;
  59.         else if (ent->velocity[i] < -sv_maxvelocity->value)
  60.             ent->velocity[i] = -sv_maxvelocity->value;
  61.     }
  62. }
  63.  
  64. /*
  65. =============
  66. SV_RunThink
  67.  
  68. Runs thinking code for this frame if necessary
  69. =============
  70. */
  71. qboolean SV_RunThink (edict_t *ent)
  72. {
  73.     float    thinktime;
  74.  
  75.     thinktime = ent->nextthink;
  76.     if (thinktime <= 0)
  77.         return true;
  78.     if (thinktime > level.time+0.001)
  79.         return true;
  80.     
  81.     ent->nextthink = 0;
  82.     if (!ent->think)
  83.         gi.error ("NULL ent->think");
  84.     ent->think (ent);
  85.  
  86.     return false;
  87. }
  88.  
  89. /*
  90. ==================
  91. SV_Impact
  92.  
  93. Two entities have touched, so run their touch functions
  94. ==================
  95. */
  96. void SV_Impact (edict_t *e1, trace_t *trace)
  97. {
  98.     edict_t        *e2;
  99. //    cplane_t    backplane;
  100.  
  101.     e2 = trace->ent;
  102.  
  103.     if (e1->touch && e1->solid != SOLID_NOT)
  104.         e1->touch (e1, e2, &trace->plane, trace->surface);
  105.     
  106.     if (e2->touch && e2->solid != SOLID_NOT)
  107.         e2->touch (e2, e1, NULL, NULL);
  108. }
  109.  
  110.  
  111. /*
  112. ==================
  113. ClipVelocity
  114.  
  115. Slide off of the impacting object
  116. returns the blocked flags (1 = floor, 2 = step / wall)
  117. ==================
  118. */
  119. #define    STOP_EPSILON    0.1
  120.  
  121. int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
  122. {
  123.     float    backoff;
  124.     float    change;
  125.     int        i, blocked;
  126.     
  127.     blocked = 0;
  128.     if (normal[2] > 0)
  129.         blocked |= 1;        // floor
  130.     if (!normal[2])
  131.         blocked |= 2;        // step
  132.     
  133.     backoff = DotProduct (in, normal) * overbounce;
  134.  
  135.     for (i=0 ; i<3 ; i++)
  136.     {
  137.         change = normal[i]*backoff;
  138.         out[i] = in[i] - change;
  139.         if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
  140.             out[i] = 0;
  141.     }
  142.     
  143.     return blocked;
  144. }
  145.  
  146.  
  147. /*
  148. ============
  149. SV_FlyMove
  150.  
  151. The basic solid body movement clip that slides along multiple planes
  152. Returns the clipflags if the velocity was modified (hit something solid)
  153. 1 = floor
  154. 2 = wall / step
  155. 4 = dead stop
  156. ============
  157. */
  158. #define    MAX_CLIP_PLANES    5
  159. int SV_FlyMove (edict_t *ent, float time, int mask)
  160. {
  161.     edict_t        *hit;
  162.     int            bumpcount, numbumps;
  163.     vec3_t        dir;
  164.     float        d;
  165.     int            numplanes;
  166.     vec3_t        planes[MAX_CLIP_PLANES];
  167.     vec3_t        primal_velocity, original_velocity, new_velocity;
  168.     int            i, j;
  169.     trace_t        trace;
  170.     vec3_t        end;
  171.     float        time_left;
  172.     int            blocked;
  173.     
  174.     numbumps = 4;
  175.     
  176.     blocked = 0;
  177.     VectorCopy (ent->velocity, original_velocity);
  178.     VectorCopy (ent->velocity, primal_velocity);
  179.     numplanes = 0;
  180.     
  181.     time_left = time;
  182.  
  183.     ent->groundentity = NULL;
  184.     for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
  185.     {
  186.         for (i=0 ; i<3 ; i++)
  187.             end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
  188.  
  189.         trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
  190.  
  191.         if (trace.allsolid)
  192.         {    // entity is trapped in another solid
  193.             VectorCopy (vec3_origin, ent->velocity);
  194.             return 3;
  195.         }
  196.  
  197.         if (trace.fraction > 0)
  198.         {    // actually covered some distance
  199.             VectorCopy (trace.endpos, ent->s.origin);
  200.             VectorCopy (ent->velocity, original_velocity);
  201.             numplanes = 0;
  202.         }
  203.  
  204.         if (trace.fraction == 1)
  205.              break;        // moved the entire distance
  206.  
  207.         hit = trace.ent;
  208.  
  209.         if (trace.plane.normal[2] > 0.7)
  210.         {
  211.             blocked |= 1;        // floor
  212.             if ( hit->solid == SOLID_BSP)
  213.             {
  214.                 ent->groundentity = hit;
  215.                 ent->groundentity_linkcount = hit->linkcount;
  216.             }
  217.         }
  218.         if (!trace.plane.normal[2])
  219.         {
  220.             blocked |= 2;        // step
  221.         }
  222.  
  223. //
  224. // run the impact function
  225. //
  226.         SV_Impact (ent, &trace);
  227.         if (!ent->inuse)
  228.             break;        // removed by the impact function
  229.  
  230.         
  231.         time_left -= time_left * trace.fraction;
  232.         
  233.     // cliped to another plane
  234.         if (numplanes >= MAX_CLIP_PLANES)
  235.         {    // this shouldn't really happen
  236.             VectorCopy (vec3_origin, ent->velocity);
  237.             return 3;
  238.         }
  239.  
  240.         VectorCopy (trace.plane.normal, planes[numplanes]);
  241.         numplanes++;
  242.  
  243. //
  244. // modify original_velocity so it parallels all of the clip planes
  245. //
  246.         for (i=0 ; i<numplanes ; i++)
  247.         {
  248.             ClipVelocity (original_velocity, planes[i], new_velocity, 1);
  249.             for (j=0 ; j<numplanes ; j++)
  250.                 if (j != i)
  251.                 {
  252.                     if (DotProduct (new_velocity, planes[j]) < 0)
  253.                         break;    // not ok
  254.                 }
  255.             if (j == numplanes)
  256.                 break;
  257.         }
  258.         
  259.         if (i != numplanes)
  260.         {    // go along this plane
  261.             VectorCopy (new_velocity, ent->velocity);
  262.         }
  263.         else
  264.         {    // go along the crease
  265.             if (numplanes != 2)
  266.             {
  267. //                gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
  268.                 VectorCopy (vec3_origin, ent->velocity);
  269.                 return 7;
  270.             }
  271.             CrossProduct (planes[0], planes[1], dir);
  272.             d = DotProduct (dir, ent->velocity);
  273.             VectorScale (dir, d, ent->velocity);
  274.         }
  275.  
  276. //
  277. // if original velocity is against the original velocity, stop dead
  278. // to avoid tiny occilations in sloping corners
  279. //
  280.         if (DotProduct (ent->velocity, primal_velocity) <= 0)
  281.         {
  282.             VectorCopy (vec3_origin, ent->velocity);
  283.             return blocked;
  284.         }
  285.     }
  286.  
  287.     return blocked;
  288. }
  289.  
  290.  
  291. /*
  292. ============
  293. SV_AddGravity
  294.  
  295. ============
  296. */
  297. void SV_AddGravity (edict_t *ent)
  298. {
  299.     ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
  300. }
  301.  
  302. /*
  303. ===============================================================================
  304.  
  305. PUSHMOVE
  306.  
  307. ===============================================================================
  308. */
  309.  
  310. /*
  311. ============
  312. SV_PushEntity
  313.  
  314. Does not change the entities velocity at all
  315. ============
  316. */
  317. trace_t SV_PushEntity (edict_t *ent, vec3_t push)
  318. {
  319.     trace_t    trace;
  320.     vec3_t    start;
  321.     vec3_t    end;
  322.     int        mask;
  323.  
  324.     VectorCopy (ent->s.origin, start);
  325.     VectorAdd (start, push, end);
  326.  
  327. retry:
  328.     if (ent->clipmask)
  329.         mask = ent->clipmask;
  330.     else
  331.         mask = MASK_SOLID;
  332.  
  333.     trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
  334.     
  335.     VectorCopy (trace.endpos, ent->s.origin);
  336.     gi.linkentity (ent);
  337.  
  338.     if (trace.fraction != 1.0)
  339.     {
  340.         SV_Impact (ent, &trace);
  341.  
  342.         // if the pushed entity went away and the pusher is still there
  343.         if (!trace.ent->inuse && ent->inuse)
  344.         {
  345.             // move the pusher back and try again
  346.             VectorCopy (start, ent->s.origin);
  347.             gi.linkentity (ent);
  348.             goto retry;
  349.         }
  350.     }
  351.  
  352.     if (ent->inuse)
  353.         G_TouchTriggers (ent);
  354.  
  355.     return trace;
  356. }                    
  357.  
  358.  
  359. typedef struct
  360. {
  361.     edict_t    *ent;
  362.     vec3_t    origin;
  363.     vec3_t    angles;
  364.     float    deltayaw;
  365. } pushed_t;
  366. pushed_t    pushed[MAX_EDICTS], *pushed_p;
  367.  
  368. edict_t    *obstacle;
  369.  
  370. /*
  371. ============
  372. SV_Push
  373.  
  374. Objects need to be moved back on a failed push,
  375. otherwise riders would continue to slide.
  376. ============
  377. */
  378. qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
  379. {
  380.     int            i, e;
  381.     edict_t        *check, *block;
  382.     vec3_t        mins, maxs;
  383.     pushed_t    *p;
  384.     vec3_t        org, org2, move2, forward, right, up;
  385.  
  386.     // clamp the move to 1/8 units, so the position will
  387.     // be accurate for client side prediction
  388.     for (i=0 ; i<3 ; i++)
  389.     {
  390.         float    temp;
  391.         temp = move[i]*8.0;
  392.         if (temp > 0.0)
  393.             temp += 0.5;
  394.         else
  395.             temp -= 0.5;
  396.         move[i] = 0.125 * (int)temp;
  397.     }
  398.  
  399.     // find the bounding box
  400.     for (i=0 ; i<3 ; i++)
  401.     {
  402.         mins[i] = pusher->absmin[i] + move[i];
  403.         maxs[i] = pusher->absmax[i] + move[i];
  404.     }
  405.  
  406. // we need this for pushing things later
  407.     VectorSubtract (vec3_origin, amove, org);
  408.     AngleVectors (org, forward, right, up);
  409.  
  410. // save the pusher's original position
  411.     pushed_p->ent = pusher;
  412.     VectorCopy (pusher->s.origin, pushed_p->origin);
  413.     VectorCopy (pusher->s.angles, pushed_p->angles);
  414.     if (pusher->client)
  415.         pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
  416.     pushed_p++;
  417.  
  418. // move the pusher to it's final position
  419.     VectorAdd (pusher->s.origin, move, pusher->s.origin);
  420.     VectorAdd (pusher->s.angles, amove, pusher->s.angles);
  421.     gi.linkentity (pusher);
  422.  
  423. // see if any solid entities are inside the final position
  424.     check = g_edicts+1;
  425.     for (e = 1; e < globals.num_edicts; e++, check++)
  426.     {
  427.         if (!check->inuse)
  428.             continue;
  429.         if (check->movetype == MOVETYPE_PUSH
  430.         || check->movetype == MOVETYPE_STOP
  431.         || check->movetype == MOVETYPE_NONE
  432.         || check->movetype == MOVETYPE_NOCLIP)
  433.             continue;
  434.  
  435.     // if the entity is standing on the pusher, it will definitely be moved
  436.         if (check->groundentity != pusher)
  437.         {
  438.             // see if the ent needs to be tested
  439.             if ( check->absmin[0] >= maxs[0]
  440.             || check->absmin[1] >= maxs[1]
  441.             || check->absmin[2] >= maxs[2]
  442.             || check->absmax[0] <= mins[0]
  443.             || check->absmax[1] <= mins[1]
  444.             || check->absmax[2] <= mins[2] )
  445.                 continue;
  446.  
  447.             // see if the ent's bbox is inside the pusher's final position
  448.             if (!SV_TestEntityPosition (check))
  449.                 continue;
  450.         }
  451.  
  452.         if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
  453.         {
  454.             // move this entity
  455.             pushed_p->ent = check;
  456.             VectorCopy (check->s.origin, pushed_p->origin);
  457.             VectorCopy (check->s.angles, pushed_p->angles);
  458.             pushed_p++;
  459.  
  460.             // try moving the contacted entity 
  461.             VectorAdd (check->s.origin, move, check->s.origin);
  462.             if (check->client)
  463.             {    // FIXME: doesn't rotate monsters?
  464.                 check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
  465.             }
  466.  
  467.             // figure movement due to the pusher's amove
  468.             VectorSubtract (check->s.origin, pusher->s.origin, org);
  469.             org2[0] = DotProduct (org, forward);
  470.             org2[1] = -DotProduct (org, right);
  471.             org2[2] = DotProduct (org, up);
  472.             VectorSubtract (org2, org, move2);
  473.             VectorAdd (check->s.origin, move2, check->s.origin);
  474.  
  475.             // may have pushed them off an edge
  476.             if (check->groundentity != pusher)
  477.                 check->groundentity = NULL;
  478.  
  479.             block = SV_TestEntityPosition (check);
  480.             if (!block)
  481.             {    // pushed ok
  482.                 gi.linkentity (check);
  483.                 // impact?
  484.                 continue;
  485.             }
  486.  
  487.             // if it is ok to leave in the old position, do it
  488.             // this is only relevent for riding entities, not pushed
  489.             // FIXME: this doesn't acount for rotation
  490.             VectorSubtract (check->s.origin, move, check->s.origin);
  491.             block = SV_TestEntityPosition (check);
  492.             if (!block)
  493.             {
  494.                 pushed_p--;
  495.                 continue;
  496.             }
  497.         }
  498.         
  499.         // save off the obstacle so we can call the block function
  500.         obstacle = check;
  501.  
  502.         // move back any entities we already moved
  503.         // go backwards, so if the same entity was pushed
  504.         // twice, it goes back to the original position
  505.         for (p=pushed_p-1 ; p>=pushed ; p--)
  506.         {
  507.             VectorCopy (p->origin, p->ent->s.origin);
  508.             VectorCopy (p->angles, p->ent->s.angles);
  509.             if (p->ent->client)
  510.             {
  511.                 p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
  512.             }
  513.             gi.linkentity (p->ent);
  514.         }
  515.         return false;
  516.     }
  517.  
  518. //FIXME: is there a better way to handle this?
  519.     // see if anything we moved has touched a trigger
  520.     for (p=pushed_p-1 ; p>=pushed ; p--)
  521.         G_TouchTriggers (p->ent);
  522.  
  523.     return true;
  524. }
  525.  
  526. /*
  527. ================
  528. SV_Physics_Pusher
  529.  
  530. Bmodel objects don't interact with each other, but
  531. push all box objects
  532. ================
  533. */
  534. void SV_Physics_Pusher (edict_t *ent)
  535. {
  536.     vec3_t        move, amove;
  537.     edict_t        *part, *mv;
  538.  
  539.     // if not a team captain, so movement will be handled elsewhere
  540.     if ( ent->flags & FL_TEAMSLAVE)
  541.         return;
  542.  
  543.     // make sure all team slaves can move before commiting
  544.     // any moves or calling any think functions
  545.     // if the move is blocked, all moved objects will be backed out
  546. //retry:
  547.     pushed_p = pushed;
  548.     for (part = ent ; part ; part=part->teamchain)
  549.     {
  550.         if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
  551.             part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
  552.             )
  553.         {    // object is moving
  554.             VectorScale (part->velocity, FRAMETIME, move);
  555.             VectorScale (part->avelocity, FRAMETIME, amove);
  556.  
  557.             if (!SV_Push (part, move, amove))
  558.                 break;    // move was blocked
  559.         }
  560.     }
  561.     if (pushed_p > &pushed[MAX_EDICTS])
  562.         gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
  563.  
  564.     if (part)
  565.     {
  566.         // the move failed, bump all nextthink times and back out moves
  567.         for (mv = ent ; mv ; mv=mv->teamchain)
  568.         {
  569.             if (mv->nextthink > 0)
  570.                 mv->nextthink += FRAMETIME;
  571.         }
  572.  
  573.         // if the pusher has a "blocked" function, call it
  574.         // otherwise, just stay in place until the obstacle is gone
  575.         if (part->blocked)
  576.             part->blocked (part, obstacle);
  577. #if 0
  578.         // if the pushed entity went away and the pusher is still there
  579.         if (!obstacle->inuse && part->inuse)
  580.             goto retry;
  581. #endif
  582.     }
  583.     else
  584.     {
  585.         // the move succeeded, so call all think functions
  586.         for (part = ent ; part ; part=part->teamchain)
  587.         {
  588.             SV_RunThink (part);
  589.         }
  590.     }
  591. }
  592.  
  593. //==================================================================
  594.  
  595. /*
  596. =============
  597. SV_Physics_None
  598.  
  599. Non moving objects can only think
  600. =============
  601. */
  602. void SV_Physics_None (edict_t *ent)
  603. {
  604. // regular thinking
  605.     SV_RunThink (ent);
  606. }
  607.  
  608. /*
  609. =============
  610. SV_Physics_Noclip
  611.  
  612. A moving object that doesn't obey physics
  613. =============
  614. */
  615. void SV_Physics_Noclip (edict_t *ent)
  616. {
  617. // regular thinking
  618.     if (!SV_RunThink (ent))
  619.         return;
  620.     
  621.     VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
  622.     VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
  623.  
  624.     gi.linkentity (ent);
  625. }
  626.  
  627. /*
  628. ==============================================================================
  629.  
  630. TOSS / BOUNCE
  631.  
  632. ==============================================================================
  633. */
  634.  
  635. /*
  636. =============
  637. SV_Physics_Toss
  638.  
  639. Toss, bounce, and fly movement.  When onground, do nothing.
  640. =============
  641. */
  642. void SV_Physics_Toss (edict_t *ent)
  643. {
  644.     trace_t        trace;
  645.     vec3_t        move;
  646.     float        backoff;
  647.     edict_t        *slave;
  648.     qboolean    wasinwater;
  649.     qboolean    isinwater;
  650.     vec3_t        old_origin;
  651.  
  652. // regular thinking
  653.     SV_RunThink (ent);
  654.  
  655.     // if not a team captain, so movement will be handled elsewhere
  656.     if ( ent->flags & FL_TEAMSLAVE)
  657.         return;
  658.  
  659.     if (ent->velocity[2] > 0)
  660.         ent->groundentity = NULL;
  661.  
  662. // check for the groundentity going away
  663.     if (ent->groundentity)
  664.         if (!ent->groundentity->inuse)
  665.             ent->groundentity = NULL;
  666.  
  667. // if onground, return without moving
  668.     if ( ent->groundentity )
  669.         return;
  670.  
  671.     VectorCopy (ent->s.origin, old_origin);
  672.  
  673.     SV_CheckVelocity (ent);
  674.  
  675. // add gravity
  676.     if (ent->movetype != MOVETYPE_FLY
  677.     && ent->movetype != MOVETYPE_FLYMISSILE)
  678.         SV_AddGravity (ent);
  679.  
  680. // move angles
  681.     VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
  682.  
  683. // move origin
  684.     VectorScale (ent->velocity, FRAMETIME, move);
  685.     trace = SV_PushEntity (ent, move);
  686.     if (!ent->inuse)
  687.         return;
  688.  
  689.     if (trace.fraction < 1)
  690.     {
  691.         if (ent->movetype == MOVETYPE_BOUNCE)
  692.             backoff = 1.5;
  693.         else
  694.             backoff = 1;
  695.  
  696.         ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
  697.  
  698.     // stop if on ground
  699.         if (trace.plane.normal[2] > 0.7)
  700.         {        
  701.             if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
  702.             {
  703.                 ent->groundentity = trace.ent;
  704.                 ent->groundentity_linkcount = trace.ent->linkcount;
  705.                 VectorCopy (vec3_origin, ent->velocity);
  706.                 VectorCopy (vec3_origin, ent->avelocity);
  707.             }
  708.         }
  709.  
  710. //        if (ent->touch)
  711. //            ent->touch (ent, trace.ent, &trace.plane, trace.surface);
  712.     }
  713.     
  714. // check for water transition
  715.     wasinwater = (ent->watertype & MASK_WATER);
  716.     ent->watertype = gi.pointcontents (ent->s.origin);
  717.     isinwater = ent->watertype & MASK_WATER;
  718.  
  719.     if (isinwater)
  720.         ent->waterlevel = 1;
  721.     else
  722.         ent->waterlevel = 0;
  723.  
  724.     if (!wasinwater && isinwater)
  725.         gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
  726.     else if (wasinwater && !isinwater)
  727.         gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
  728.  
  729. // move teamslaves
  730.     for (slave = ent->teamchain; slave; slave = slave->teamchain)
  731.     {
  732.         VectorCopy (ent->s.origin, slave->s.origin);
  733.         gi.linkentity (slave);
  734.     }
  735. }
  736.  
  737. /*
  738. ===============================================================================
  739.  
  740. STEPPING MOVEMENT
  741.  
  742. ===============================================================================
  743. */
  744.  
  745. /*
  746. =============
  747. SV_Physics_Step
  748.  
  749. Monsters freefall when they don't have a ground entity, otherwise
  750. all movement is done with discrete steps.
  751.  
  752. This is also used for objects that have become still on the ground, but
  753. will fall if the floor is pulled out from under them.
  754. FIXME: is this true?
  755. =============
  756. */
  757.  
  758. //FIXME: hacked in for E3 demo
  759. #define    sv_stopspeed        100
  760. #define sv_friction            6
  761. #define sv_waterfriction    1
  762.  
  763. void SV_AddRotationalFriction (edict_t *ent)
  764. {
  765.     int        n;
  766.     float    adjustment;
  767.  
  768.     VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
  769.     adjustment = FRAMETIME * sv_stopspeed * sv_friction;
  770.     for (n = 0; n < 3; n++)
  771.     {
  772.         if (ent->avelocity[n] > 0)
  773.         {
  774.             ent->avelocity[n] -= adjustment;
  775.             if (ent->avelocity[n] < 0)
  776.                 ent->avelocity[n] = 0;
  777.         }
  778.         else
  779.         {
  780.             ent->avelocity[n] += adjustment;
  781.             if (ent->avelocity[n] > 0)
  782.                 ent->avelocity[n] = 0;
  783.         }
  784.     }
  785. }
  786.  
  787. void SV_Physics_Step (edict_t *ent)
  788. {
  789.     qboolean    wasonground;
  790.     qboolean    hitsound = false;
  791.     float        *vel;
  792.     float        speed, newspeed, control;
  793.     float        friction;
  794.     edict_t        *groundentity;
  795.     int            mask;
  796.  
  797.     // airborn monsters should always check for ground
  798.     if (!ent->groundentity)
  799.         M_CheckGround (ent);
  800.  
  801.     groundentity = ent->groundentity;
  802.  
  803.     SV_CheckVelocity (ent);
  804.  
  805.     if (groundentity)
  806.         wasonground = true;
  807.     else
  808.         wasonground = false;
  809.         
  810.     if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
  811.         SV_AddRotationalFriction (ent);
  812.  
  813.     // add gravity except:
  814.     //   flying monsters
  815.     //   swimming monsters who are in the water
  816.     if (! wasonground)
  817.         if (!(ent->flags & FL_FLY))
  818.             if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
  819.             {
  820.                 if (ent->velocity[2] < sv_gravity->value*-0.1)
  821.                     hitsound = true;
  822.                 if (ent->waterlevel == 0)
  823.                     SV_AddGravity (ent);
  824.             }
  825.  
  826.     // friction for flying monsters that have been given vertical velocity
  827.     if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
  828.     {
  829.         speed = fabs(ent->velocity[2]);
  830.         control = speed < sv_stopspeed ? sv_stopspeed : speed;
  831.         friction = sv_friction/3;
  832.         newspeed = speed - (FRAMETIME * control * friction);
  833.         if (newspeed < 0)
  834.             newspeed = 0;
  835.         newspeed /= speed;
  836.         ent->velocity[2] *= newspeed;
  837.     }
  838.  
  839.     // friction for flying monsters that have been given vertical velocity
  840.     if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
  841.     {
  842.         speed = fabs(ent->velocity[2]);
  843.         control = speed < sv_stopspeed ? sv_stopspeed : speed;
  844.         newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
  845.         if (newspeed < 0)
  846.             newspeed = 0;
  847.         newspeed /= speed;
  848.         ent->velocity[2] *= newspeed;
  849.     }
  850.  
  851.     if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
  852.     {
  853.         // apply friction
  854.         // let dead monsters who aren't completely onground slide
  855.         if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
  856.             if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
  857.             {
  858.                 vel = ent->velocity;
  859.                 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
  860.                 if (speed)
  861.                 {
  862.                     friction = sv_friction;
  863.  
  864.                     control = speed < sv_stopspeed ? sv_stopspeed : speed;
  865.                     newspeed = speed - FRAMETIME*control*friction;
  866.  
  867.                     if (newspeed < 0)
  868.                         newspeed = 0;
  869.                     newspeed /= speed;
  870.  
  871.                     vel[0] *= newspeed;
  872.                     vel[1] *= newspeed;
  873.                 }
  874.             }
  875.  
  876.         if (ent->svflags & SVF_MONSTER)
  877.             mask = MASK_MONSTERSOLID;
  878.         else
  879.             mask = MASK_SOLID;
  880.         SV_FlyMove (ent, FRAMETIME, mask);
  881.  
  882.         gi.linkentity (ent);
  883.         G_TouchTriggers (ent);
  884.  
  885.         if (ent->groundentity)
  886.             if (!wasonground)
  887.                 if (hitsound)
  888.                     gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
  889.     }
  890.  
  891. // regular thinking
  892.     SV_RunThink (ent);
  893. }
  894.  
  895. //============================================================================
  896. /*
  897. ================
  898. G_RunEntity
  899.  
  900. ================
  901. */
  902. void G_RunEntity (edict_t *ent)
  903. {
  904.     if (ent->prethink)
  905.         ent->prethink (ent);
  906.  
  907.     switch ( (int)ent->movetype)
  908.     {
  909.     case MOVETYPE_PUSH:
  910.     case MOVETYPE_STOP:
  911.         SV_Physics_Pusher (ent);
  912.         break;
  913.     case MOVETYPE_NONE:
  914.         SV_Physics_None (ent);
  915.         break;
  916.     case MOVETYPE_NOCLIP:
  917.         SV_Physics_Noclip (ent);
  918.         break;
  919.     case MOVETYPE_STEP:
  920.         SV_Physics_Step (ent);
  921.         break;
  922.     case MOVETYPE_TOSS:
  923.     case MOVETYPE_BOUNCE:
  924.     case MOVETYPE_FLY:
  925.     case MOVETYPE_FLYMISSILE:
  926.         SV_Physics_Toss (ent);
  927.         break;
  928.     default:
  929.         gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);            
  930.     }
  931. }
  932.