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

  1. // g_utils.c -- misc utility functions for game module
  2.  
  3. #include "g_local.h"
  4.  
  5.  
  6. void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  7. {
  8.     result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
  9.     result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
  10.     result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
  11. }
  12.  
  13.  
  14. /*
  15. =============
  16. G_Find
  17.  
  18. Searches all active entities for the next one that holds
  19. the matching string at fieldofs (use the FOFS() macro) in the structure.
  20.  
  21. Searches beginning at the edict after from, or the beginning if NULL
  22. NULL will be returned if the end of the list is reached.
  23.  
  24. =============
  25. */
  26. edict_t *G_Find (edict_t *from, int fieldofs, char *match)
  27. {
  28.     char    *s;
  29.  
  30.     if (!from)
  31.         from = g_edicts;
  32.     else
  33.         from++;
  34.  
  35.     for ( ; from < &g_edicts[globals.num_edicts] ; from++)
  36.     {
  37.         if (!from->inuse)
  38.             continue;
  39.         s = *(char **) ((byte *)from + fieldofs);
  40.         if (!s)
  41.             continue;
  42.         if (!Q_stricmp (s, match))
  43.             return from;
  44.     }
  45.  
  46.     return NULL;
  47. }
  48.  
  49.  
  50. /*
  51. =================
  52. findradius
  53.  
  54. Returns entities that have origins within a spherical area
  55.  
  56. findradius (origin, radius)
  57. =================
  58. */
  59. edict_t *findradius (edict_t *from, vec3_t org, float rad)
  60. {
  61.     vec3_t    eorg;
  62.     int        j;
  63.  
  64.     if (!from)
  65.         from = g_edicts;
  66.     else
  67.         from++;
  68.     for ( ; from < &g_edicts[globals.num_edicts]; from++)
  69.     {
  70.         if (!from->inuse)
  71.             continue;
  72.         if (from->solid == SOLID_NOT)
  73.             continue;
  74.         for (j=0 ; j<3 ; j++)
  75.             eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
  76.         if (VectorLength(eorg) > rad)
  77.             continue;
  78.         return from;
  79.     }
  80.  
  81.     return NULL;
  82. }
  83.  
  84.  
  85. /*
  86. =============
  87. G_PickTarget
  88.  
  89. Searches all active entities for the next one that holds
  90. the matching string at fieldofs (use the FOFS() macro) in the structure.
  91.  
  92. Searches beginning at the edict after from, or the beginning if NULL
  93. NULL will be returned if the end of the list is reached.
  94.  
  95. =============
  96. */
  97. #define MAXCHOICES    8
  98.  
  99. edict_t *G_PickTarget (char *targetname)
  100. {
  101.     edict_t    *ent = NULL;
  102.     int        num_choices = 0;
  103.     edict_t    *choice[MAXCHOICES];
  104.  
  105.     if (!targetname)
  106.     {
  107.         gi.dprintf("G_PickTarget called with NULL targetname\n");
  108.         return NULL;
  109.     }
  110.  
  111.     while(1)
  112.     {
  113.         ent = G_Find (ent, FOFS(targetname), targetname);
  114.         if (!ent)
  115.             break;
  116.         choice[num_choices++] = ent;
  117.         if (num_choices == MAXCHOICES)
  118.             break;
  119.     }
  120.  
  121.     if (!num_choices)
  122.     {
  123.         gi.dprintf("G_PickTarget: target %s not found\n", targetname);
  124.         return NULL;
  125.     }
  126.  
  127.     return choice[rand() % num_choices];
  128. }
  129.  
  130.  
  131.  
  132. void Think_Delay (edict_t *ent)
  133. {
  134.     G_UseTargets (ent, ent->activator);
  135.     G_FreeEdict (ent);
  136. }
  137.  
  138. /*
  139. ==============================
  140. G_UseTargets
  141.  
  142. the global "activator" should be set to the entity that initiated the firing.
  143.  
  144. If self.delay is set, a DelayedUse entity will be created that will actually
  145. do the SUB_UseTargets after that many seconds have passed.
  146.  
  147. Centerprints any self.message to the activator.
  148.  
  149. Search for (string)targetname in all entities that
  150. match (string)self.target and call their .use function
  151.  
  152. ==============================
  153. */
  154. void G_UseTargets (edict_t *ent, edict_t *activator)
  155. {
  156.     edict_t        *t;
  157.  
  158. //
  159. // check for a delay
  160. //
  161.     if (ent->delay)
  162.     {
  163.     // create a temp object to fire at a later time
  164.         t = G_Spawn();
  165.         t->classname = "DelayedUse";
  166.         t->nextthink = level.time + ent->delay;
  167.         t->think = Think_Delay;
  168.         t->activator = activator;
  169.         if (!activator)
  170.             gi.dprintf ("Think_Delay with no activator\n");
  171.         t->message = ent->message;
  172.         t->target = ent->target;
  173.         t->killtarget = ent->killtarget;
  174.         return;
  175.     }
  176.     
  177.     
  178. //
  179. // print the message
  180. //
  181.     if ((ent->message) && !(activator->svflags & SVF_MONSTER))
  182.     {
  183.         gi.centerprintf (activator, "%s", ent->message);
  184.         if (ent->noise_index)
  185.             gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
  186.         else
  187.             gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  188.     }
  189.  
  190. //
  191. // kill killtargets
  192. //
  193.     if (ent->killtarget)
  194.     {
  195.         t = NULL;
  196.         while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
  197.         {
  198.             G_FreeEdict (t);
  199.             if (!ent->inuse)
  200.             {
  201.                 gi.dprintf("entity was removed while using killtargets\n");
  202.                 return;
  203.             }
  204.         }
  205.     }
  206.  
  207. //
  208. // fire targets
  209. //
  210.     if (ent->target)
  211.     {
  212.         t = NULL;
  213.         while ((t = G_Find (t, FOFS(targetname), ent->target)))
  214.         {
  215.             // doors fire area portals in a specific way
  216.             if (!Q_stricmp(t->classname, "func_areaportal") &&
  217.                 (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
  218.                 continue;
  219.  
  220.             if (t == ent)
  221.             {
  222.                 gi.dprintf ("WARNING: Entity used itself.\n");
  223.             }
  224.             else
  225.             {
  226.                 if (t->use)
  227.                     t->use (t, ent, activator);
  228.             }
  229.             if (!ent->inuse)
  230.             {
  231.                 gi.dprintf("entity was removed while using targets\n");
  232.                 return;
  233.             }
  234.         }
  235.     }
  236. }
  237.  
  238.  
  239. /*
  240. =============
  241. TempVector
  242.  
  243. This is just a convenience function
  244. for making temporary vectors for function calls
  245. =============
  246. */
  247. float    *tv (float x, float y, float z)
  248. {
  249.     static    int        index;
  250.     static    vec3_t    vecs[8];
  251.     float    *v;
  252.  
  253.     // use an array so that multiple tempvectors won't collide
  254.     // for a while
  255.     v = vecs[index];
  256.     index = (index + 1)&7;
  257.  
  258.     v[0] = x;
  259.     v[1] = y;
  260.     v[2] = z;
  261.  
  262.     return v;
  263. }
  264.  
  265.  
  266. /*
  267. =============
  268. VectorToString
  269.  
  270. This is just a convenience function
  271. for printing vectors
  272. =============
  273. */
  274. char    *vtos (vec3_t v)
  275. {
  276.     static    int        index;
  277.     static    char    str[8][32];
  278.     char    *s;
  279.  
  280.     // use an array so that multiple vtos won't collide
  281.     s = str[index];
  282.     index = (index + 1)&7;
  283.  
  284.     Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
  285.  
  286.     return s;
  287. }
  288.  
  289.  
  290. vec3_t VEC_UP        = {0, -1, 0};
  291. vec3_t MOVEDIR_UP    = {0, 0, 1};
  292. vec3_t VEC_DOWN        = {0, -2, 0};
  293. vec3_t MOVEDIR_DOWN    = {0, 0, -1};
  294.  
  295. void G_SetMovedir (vec3_t angles, vec3_t movedir)
  296. {
  297.     if (VectorCompare (angles, VEC_UP))
  298.     {
  299.         VectorCopy (MOVEDIR_UP, movedir);
  300.     }
  301.     else if (VectorCompare (angles, VEC_DOWN))
  302.     {
  303.         VectorCopy (MOVEDIR_DOWN, movedir);
  304.     }
  305.     else
  306.     {
  307.         AngleVectors (angles, movedir, NULL, NULL);
  308.     }
  309.  
  310.     VectorClear (angles);
  311. }
  312.  
  313.  
  314. float vectoyaw (vec3_t vec)
  315. {
  316.     float    yaw;
  317.     
  318.     if (vec[YAW] == 0 && vec[PITCH] == 0)
  319.         yaw = 0;
  320.     else
  321.     {
  322.         yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
  323.         if (yaw < 0)
  324.             yaw += 360;
  325.     }
  326.  
  327.     return yaw;
  328. }
  329.  
  330.  
  331. void vectoangles (vec3_t value1, vec3_t angles)
  332. {
  333.     float    forward;
  334.     float    yaw, pitch;
  335.     
  336.     if (value1[1] == 0 && value1[0] == 0)
  337.     {
  338.         yaw = 0;
  339.         if (value1[2] > 0)
  340.             pitch = 90;
  341.         else
  342.             pitch = 270;
  343.     }
  344.     else
  345.     {
  346.         yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
  347.         if (yaw < 0)
  348.             yaw += 360;
  349.  
  350.         forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
  351.         pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
  352.         if (pitch < 0)
  353.             pitch += 360;
  354.     }
  355.  
  356.     angles[PITCH] = -pitch;
  357.     angles[YAW] = yaw;
  358.     angles[ROLL] = 0;
  359. }
  360.  
  361. char *G_CopyString (char *in)
  362. {
  363.     char    *out;
  364.     
  365.     out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
  366.     strcpy (out, in);
  367.     return out;
  368. }
  369.  
  370.  
  371. void G_InitEdict (edict_t *e)
  372. {
  373.     e->inuse = true;
  374.     e->classname = "noclass";
  375.     e->gravity = 1.0;
  376.     e->s.number = e - g_edicts;
  377. }
  378.  
  379. /*
  380. =================
  381. G_Spawn
  382.  
  383. Either finds a free edict, or allocates a new one.
  384. Try to avoid reusing an entity that was recently freed, because it
  385. can cause the client to think the entity morphed into something else
  386. instead of being removed and recreated, which can cause interpolated
  387. angles and bad trails.
  388. =================
  389. */
  390. edict_t *G_Spawn (void)
  391. {
  392.     int            i;
  393.     edict_t        *e;
  394.  
  395.     e = &g_edicts[(int)maxclients->value+1];
  396.     for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
  397.     {
  398.         // the first couple seconds of server time can involve a lot of
  399.         // freeing and allocating, so relax the replacement policy
  400.         if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
  401.         {
  402.             G_InitEdict (e);
  403.             return e;
  404.         }
  405.     }
  406.     
  407.     if (i == game.maxentities)
  408.         gi.error ("ED_Alloc: no free edicts");
  409.         
  410.     globals.num_edicts++;
  411.     G_InitEdict (e);
  412.     return e;
  413. }
  414.  
  415. /*
  416. =================
  417. G_FreeEdict
  418.  
  419. Marks the edict as free
  420. =================
  421. */
  422. void G_FreeEdict (edict_t *ed)
  423. {
  424.     gi.unlinkentity (ed);        // unlink from world
  425.  
  426.     memset (ed, 0, sizeof(*ed));
  427.     ed->classname = "freed";
  428.     ed->freetime = level.time;
  429.     ed->inuse = false;
  430. }
  431.  
  432.  
  433. /*
  434. ============
  435. G_TouchTriggers
  436.  
  437. ============
  438. */
  439. void    G_TouchTriggers (edict_t *ent)
  440. {
  441.     int            i, num;
  442.     edict_t        *touch[MAX_EDICTS], *hit;
  443.  
  444.     // dead things don't activate triggers!
  445.     if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
  446.         return;
  447.  
  448.     num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  449.         , MAX_EDICTS, AREA_TRIGGERS);
  450.  
  451.     // be careful, it is possible to have an entity in this
  452.     // list removed before we get to it (killtriggered)
  453.     for (i=0 ; i<num ; i++)
  454.     {
  455.         hit = touch[i];
  456.         if (!hit->inuse)
  457.             continue;
  458.         if (!hit->touch)
  459.             continue;
  460.         hit->touch (hit, ent, NULL, NULL);
  461.     }
  462. }
  463.  
  464. /*
  465. ============
  466. G_TouchSolids
  467.  
  468. Call after linking a new trigger in during gameplay
  469. to force all entities it covers to immediately touch it
  470. ============
  471. */
  472. void    G_TouchSolids (edict_t *ent)
  473. {
  474.     int            i, num;
  475.     edict_t        *touch[MAX_EDICTS], *hit;
  476.  
  477.     num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  478.         , MAX_EDICTS, AREA_SOLID);
  479.  
  480.     // be careful, it is possible to have an entity in this
  481.     // list removed before we get to it (killtriggered)
  482.     for (i=0 ; i<num ; i++)
  483.     {
  484.         hit = touch[i];
  485.         if (!hit->inuse)
  486.             continue;
  487.         if (ent->touch)
  488.             ent->touch (hit, ent, NULL, NULL);
  489.         if (!ent->inuse)
  490.             break;
  491.     }
  492. }
  493.  
  494.  
  495.  
  496.  
  497. /*
  498. ==============================================================================
  499.  
  500. Kill box
  501.  
  502. ==============================================================================
  503. */
  504.  
  505. /*
  506. =================
  507. KillBox
  508.  
  509. Kills all entities that would touch the proposed new positioning
  510. of ent.  Ent should be unlinked before calling this!
  511. =================
  512. */
  513. qboolean KillBox (edict_t *ent)
  514. {
  515.     trace_t        tr;
  516.  
  517.     while (1)
  518.     {
  519.         tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
  520.         if (!tr.ent)
  521.             break;
  522.  
  523.         // nail it
  524.         T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION);
  525.  
  526.         // if we didn't kill it, fail
  527.         if (tr.ent->solid)
  528.             return false;
  529.     }
  530.  
  531.     return true;        // all clear
  532. }
  533.