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

  1. // m_move.c -- monster movement
  2.  
  3. #include "g_local.h"
  4.  
  5. #define    STEPSIZE    18
  6.  
  7. /*
  8. =============
  9. M_CheckBottom
  10.  
  11. Returns false if any part of the bottom of the entity is off an edge that
  12. is not a staircase.
  13.  
  14. =============
  15. */
  16. int c_yes, c_no;
  17.  
  18. qboolean M_CheckBottom (edict_t *ent)
  19. {
  20.     vec3_t    mins, maxs, start, stop;
  21.     trace_t    trace;
  22.     int        x, y;
  23.     float    mid, bottom;
  24.     
  25.     VectorAdd (ent->s.origin, ent->mins, mins);
  26.     VectorAdd (ent->s.origin, ent->maxs, maxs);
  27.  
  28. // if all of the points under the corners are solid world, don't bother
  29. // with the tougher checks
  30. // the corners must be within 16 of the midpoint
  31.     start[2] = mins[2] - 1;
  32.     for    (x=0 ; x<=1 ; x++)
  33.         for    (y=0 ; y<=1 ; y++)
  34.         {
  35.             start[0] = x ? maxs[0] : mins[0];
  36.             start[1] = y ? maxs[1] : mins[1];
  37.             if (gi.pointcontents (start) != CONTENTS_SOLID)
  38.                 goto realcheck;
  39.         }
  40.  
  41.     c_yes++;
  42.     return true;        // we got out easy
  43.  
  44. realcheck:
  45.     c_no++;
  46. //
  47. // check it for real...
  48. //
  49.     start[2] = mins[2];
  50.     
  51. // the midpoint must be within 16 of the bottom
  52.     start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
  53.     start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
  54.     stop[2] = start[2] - 2*STEPSIZE;
  55.     trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  56.  
  57.     if (trace.fraction == 1.0)
  58.         return false;
  59.     mid = bottom = trace.endpos[2];
  60.     
  61. // the corners must be within 16 of the midpoint    
  62.     for    (x=0 ; x<=1 ; x++)
  63.         for    (y=0 ; y<=1 ; y++)
  64.         {
  65.             start[0] = stop[0] = x ? maxs[0] : mins[0];
  66.             start[1] = stop[1] = y ? maxs[1] : mins[1];
  67.             
  68.             trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  69.             
  70.             if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
  71.                 bottom = trace.endpos[2];
  72.             if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
  73.                 return false;
  74.         }
  75.  
  76.     c_yes++;
  77.     return true;
  78. }
  79.  
  80.  
  81. /*
  82. =============
  83. SV_movestep
  84.  
  85. Called by monster program code.
  86. The move will be adjusted for slopes and stairs, but if the move isn't
  87. possible, no move is done, false is returned, and
  88. pr_global_struct->trace_normal is set to the normal of the blocking wall
  89. =============
  90. */
  91. //FIXME since we need to test end position contents here, can we avoid doing
  92. //it again later in catagorize position?
  93. qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
  94. {
  95.     float        dz;
  96.     vec3_t        oldorg, neworg, end;
  97.     trace_t        trace;
  98.     int            i;
  99.     float        stepsize;
  100.     vec3_t        test;
  101.     int            contents;
  102.  
  103. // try the move    
  104.     VectorCopy (ent->s.origin, oldorg);
  105.     VectorAdd (ent->s.origin, move, neworg);
  106.  
  107. // flying monsters don't step up
  108.     if ( ent->flags & (FL_SWIM | FL_FLY) )
  109.     {
  110.     // try one move with vertical motion, then one without
  111.         for (i=0 ; i<2 ; i++)
  112.         {
  113.             VectorAdd (ent->s.origin, move, neworg);
  114.             if (i == 0 && ent->enemy)
  115.             {
  116.                 if (!ent->goalentity)
  117.                     ent->goalentity = ent->enemy;
  118.                 dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
  119.                 if (ent->goalentity->client)
  120.                 {
  121.                     if (dz > 40)
  122.                         neworg[2] -= 8;
  123.                     if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
  124.                         if (dz < 30)
  125.                             neworg[2] += 8;
  126.                 }
  127.                 else
  128.                 {
  129.                     if (dz > 8)
  130.                         neworg[2] -= 8;
  131.                     else if (dz > 0)
  132.                         neworg[2] -= dz;
  133.                     else if (dz < -8)
  134.                         neworg[2] += 8;
  135.                     else
  136.                         neworg[2] += dz;
  137.                 }
  138.             }
  139.             trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
  140.     
  141.             // fly monsters don't enter water voluntarily
  142.             if (ent->flags & FL_FLY)
  143.             {
  144.                 if (!ent->waterlevel)
  145.                 {
  146.                     test[0] = trace.endpos[0];
  147.                     test[1] = trace.endpos[1];
  148.                     test[2] = trace.endpos[2] + ent->mins[2] + 1;
  149.                     contents = gi.pointcontents(test);
  150.                     if (contents & MASK_WATER)
  151.                         return false;
  152.                 }
  153.             }
  154.  
  155.             // swim monsters don't exit water voluntarily
  156.             if (ent->flags & FL_SWIM)
  157.             {
  158.                 if (ent->waterlevel < 2)
  159.                 {
  160.                     test[0] = trace.endpos[0];
  161.                     test[1] = trace.endpos[1];
  162.                     test[2] = trace.endpos[2] + ent->mins[2] + 1;
  163.                     contents = gi.pointcontents(test);
  164.                     if (!(contents & MASK_WATER))
  165.                         return false;
  166.                 }
  167.             }
  168.  
  169.             if (trace.fraction == 1)
  170.             {
  171.                 VectorCopy (trace.endpos, ent->s.origin);
  172.                 if (relink)
  173.                 {
  174.                     gi.linkentity (ent);
  175.                     G_TouchTriggers (ent);
  176.                 }
  177.                 return true;
  178.             }
  179.             
  180.             if (!ent->enemy)
  181.                 break;
  182.         }
  183.         
  184.         return false;
  185.     }
  186.  
  187. // push down from a step height above the wished position
  188.     if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
  189.         stepsize = STEPSIZE;
  190.     else
  191.         stepsize = 1;
  192.  
  193.     neworg[2] += stepsize;
  194.     VectorCopy (neworg, end);
  195.     end[2] -= stepsize*2;
  196.  
  197.     trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  198.  
  199.     if (trace.allsolid)
  200.         return false;
  201.  
  202.     if (trace.startsolid)
  203.     {
  204.         neworg[2] -= stepsize;
  205.         trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  206.         if (trace.allsolid || trace.startsolid)
  207.             return false;
  208.     }
  209.  
  210.  
  211.     // don't go in to water
  212.     if (ent->waterlevel == 0)
  213.     {
  214.         test[0] = trace.endpos[0];
  215.         test[1] = trace.endpos[1];
  216.         test[2] = trace.endpos[2] + ent->mins[2] + 1;    
  217.         contents = gi.pointcontents(test);
  218.  
  219.         if (contents & MASK_WATER)
  220.             return false;
  221.     }
  222.  
  223.     if (trace.fraction == 1)
  224.     {
  225.     // if monster had the ground pulled out, go ahead and fall
  226.         if ( ent->flags & FL_PARTIALGROUND )
  227.         {
  228.             VectorAdd (ent->s.origin, move, ent->s.origin);
  229.             if (relink)
  230.             {
  231.                 gi.linkentity (ent);
  232.                 G_TouchTriggers (ent);
  233.             }
  234.             ent->groundentity = NULL;
  235. //    SV_Printf ("fall down\n"); 
  236.             return true;
  237.         }
  238.     
  239.         return false;        // walked off an edge
  240.     }
  241.  
  242. // check point traces down for dangling corners
  243.     VectorCopy (trace.endpos, ent->s.origin);
  244.     
  245.     if (!M_CheckBottom (ent))
  246.     {
  247.         if ( ent->flags & FL_PARTIALGROUND )
  248.         {    // entity had floor mostly pulled out from underneath it
  249.             // and is trying to correct
  250.             if (relink)
  251.             {
  252.                 gi.linkentity (ent);
  253.                 G_TouchTriggers (ent);
  254.             }
  255.             return true;
  256.         }
  257.         VectorCopy (oldorg, ent->s.origin);
  258.         return false;
  259.     }
  260.  
  261.     if ( ent->flags & FL_PARTIALGROUND )
  262.     {
  263. //        SV_Printf ("back on ground\n"); 
  264.         ent->flags &= ~FL_PARTIALGROUND;
  265.     }
  266.     ent->groundentity = trace.ent;
  267.     ent->groundentity_linkcount = trace.ent->linkcount;
  268.  
  269. // the move is ok
  270.     if (relink)
  271.     {
  272.         gi.linkentity (ent);
  273.         G_TouchTriggers (ent);
  274.     }
  275.     return true;
  276. }
  277.  
  278.  
  279. //============================================================================
  280.  
  281. /*
  282. ===============
  283. M_ChangeYaw
  284.  
  285. ===============
  286. */
  287. void M_ChangeYaw (edict_t *ent)
  288. {
  289.     float    ideal;
  290.     float    current;
  291.     float    move;
  292.     float    speed;
  293.     
  294.     current = anglemod(ent->s.angles[YAW]);
  295.     ideal = ent->ideal_yaw;
  296.  
  297.     if (current == ideal)
  298.         return;
  299.  
  300.     move = ideal - current;
  301.     speed = ent->yaw_speed;
  302.     if (ideal > current)
  303.     {
  304.         if (move >= 180)
  305.             move = move - 360;
  306.     }
  307.     else
  308.     {
  309.         if (move <= -180)
  310.             move = move + 360;
  311.     }
  312.     if (move > 0)
  313.     {
  314.         if (move > speed)
  315.             move = speed;
  316.     }
  317.     else
  318.     {
  319.         if (move < -speed)
  320.             move = -speed;
  321.     }
  322.     
  323.     ent->s.angles[YAW] = anglemod (current + move);
  324. }
  325.  
  326.  
  327. /*
  328. ======================
  329. SV_StepDirection
  330.  
  331. Turns to the movement direction, and walks the current distance if
  332. facing it.
  333.  
  334. ======================
  335. */
  336. qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
  337. {
  338.     vec3_t        move, oldorigin;
  339.     float        delta;
  340.     
  341.     ent->ideal_yaw = yaw;
  342.     M_ChangeYaw (ent);
  343.     
  344.     yaw = yaw*M_PI*2 / 360;
  345.     move[0] = cos(yaw)*dist;
  346.     move[1] = sin(yaw)*dist;
  347.     move[2] = 0;
  348.  
  349.     VectorCopy (ent->s.origin, oldorigin);
  350.     if (SV_movestep (ent, move, false))
  351.     {
  352.         delta = ent->s.angles[YAW] - ent->ideal_yaw;
  353.         if (delta > 45 && delta < 315)
  354.         {        // not turned far enough, so don't take the step
  355.             VectorCopy (oldorigin, ent->s.origin);
  356.         }
  357.         gi.linkentity (ent);
  358.         G_TouchTriggers (ent);
  359.         return true;
  360.     }
  361.     gi.linkentity (ent);
  362.     G_TouchTriggers (ent);
  363.     return false;
  364. }
  365.  
  366. /*
  367. ======================
  368. SV_FixCheckBottom
  369.  
  370. ======================
  371. */
  372. void SV_FixCheckBottom (edict_t *ent)
  373. {
  374. //    SV_Printf ("SV_FixCheckBottom\n");
  375.     
  376.     ent->flags |= FL_PARTIALGROUND;
  377. }
  378.  
  379.  
  380.  
  381. /*
  382. ================
  383. SV_NewChaseDir
  384.  
  385. ================
  386. */
  387. #define    DI_NODIR    -1
  388. void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
  389. {
  390.     float    deltax,deltay;
  391.     float    d[3];
  392.     float    tdir, olddir, turnaround;
  393.  
  394.     //FIXME: how did we get here with no enemy
  395.     if (!enemy)
  396.         return;
  397.  
  398.     olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
  399.     turnaround = anglemod(olddir - 180);
  400.  
  401.     deltax = enemy->s.origin[0] - actor->s.origin[0];
  402.     deltay = enemy->s.origin[1] - actor->s.origin[1];
  403.     if (deltax>10)
  404.         d[1]= 0;
  405.     else if (deltax<-10)
  406.         d[1]= 180;
  407.     else
  408.         d[1]= DI_NODIR;
  409.     if (deltay<-10)
  410.         d[2]= 270;
  411.     else if (deltay>10)
  412.         d[2]= 90;
  413.     else
  414.         d[2]= DI_NODIR;
  415.  
  416. // try direct route
  417.     if (d[1] != DI_NODIR && d[2] != DI_NODIR)
  418.     {
  419.         if (d[1] == 0)
  420.             tdir = d[2] == 90 ? 45 : 315;
  421.         else
  422.             tdir = d[2] == 90 ? 135 : 215;
  423.             
  424.         if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
  425.             return;
  426.     }
  427.  
  428. // try other directions
  429.     if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
  430.     {
  431.         tdir=d[1];
  432.         d[1]=d[2];
  433.         d[2]=tdir;
  434.     }
  435.  
  436.     if (d[1]!=DI_NODIR && d[1]!=turnaround 
  437.     && SV_StepDirection(actor, d[1], dist))
  438.             return;
  439.  
  440.     if (d[2]!=DI_NODIR && d[2]!=turnaround
  441.     && SV_StepDirection(actor, d[2], dist))
  442.             return;
  443.  
  444. /* there is no direct path to the player, so pick another direction */
  445.  
  446.     if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
  447.             return;
  448.  
  449.     if (rand()&1)     /*randomly determine direction of search*/
  450.     {
  451.         for (tdir=0 ; tdir<=315 ; tdir += 45)
  452.             if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  453.                     return;
  454.     }
  455.     else
  456.     {
  457.         for (tdir=315 ; tdir >=0 ; tdir -= 45)
  458.             if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  459.                     return;
  460.     }
  461.  
  462.     if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
  463.             return;
  464.  
  465.     actor->ideal_yaw = olddir;        // can't move
  466.  
  467. // if a bridge was pulled out from underneath a monster, it may not have
  468. // a valid standing position at all
  469.  
  470.     if (!M_CheckBottom (actor))
  471.         SV_FixCheckBottom (actor);
  472. }
  473.  
  474. /*
  475. ======================
  476. SV_CloseEnough
  477.  
  478. ======================
  479. */
  480. qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
  481. {
  482.     int        i;
  483.     
  484.     for (i=0 ; i<3 ; i++)
  485.     {
  486.         if (goal->absmin[i] > ent->absmax[i] + dist)
  487.             return false;
  488.         if (goal->absmax[i] < ent->absmin[i] - dist)
  489.             return false;
  490.     }
  491.     return true;
  492. }
  493.  
  494.  
  495. /*
  496. ======================
  497. M_MoveToGoal
  498. ======================
  499. */
  500. void M_MoveToGoal (edict_t *ent, float dist)
  501. {
  502.     edict_t        *goal;
  503.     
  504.     goal = ent->goalentity;
  505.  
  506.     if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  507.         return;
  508.  
  509. // if the next step hits the enemy, return immediately
  510.     if (ent->enemy &&  SV_CloseEnough (ent, ent->enemy, dist) )
  511.         return;
  512.  
  513. // bump around...
  514.     if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  515.     {
  516.         if (ent->inuse)
  517.             SV_NewChaseDir (ent, goal, dist);
  518.     }
  519. }
  520.  
  521.  
  522. /*
  523. ===============
  524. M_walkmove
  525. ===============
  526. */
  527. qboolean M_walkmove (edict_t *ent, float yaw, float dist)
  528. {
  529.     vec3_t    move;
  530.     
  531.     if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  532.         return false;
  533.  
  534.     yaw = yaw*M_PI*2 / 360;
  535.     
  536.     move[0] = cos(yaw)*dist;
  537.     move[1] = sin(yaw)*dist;
  538.     move[2] = 0;
  539.  
  540.     return SV_movestep(ent, move, true);
  541. }
  542.