Annotation of quake2/rogue/g_utils.c, revision 1.1.1.1

1.1       root        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: void G_ProjectSource2 (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t up, vec3_t result)
                     14: {
                     15:        result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1] + up[0] * distance[2];
                     16:        result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1] + up[1] * distance[2];
                     17:        result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + up[2] * distance[2];
                     18: }
                     19: 
                     20: /*
                     21: =============
                     22: G_Find
                     23: 
                     24: Searches all active entities for the next one that holds
                     25: the matching string at fieldofs (use the FOFS() macro) in the structure.
                     26: 
                     27: Searches beginning at the edict after from, or the beginning if NULL
                     28: NULL will be returned if the end of the list is reached.
                     29: 
                     30: =============
                     31: */
                     32: edict_t *G_Find (edict_t *from, int fieldofs, char *match)
                     33: {
                     34:        char    *s;
                     35: 
                     36:        if (!from)
                     37:                from = g_edicts;
                     38:        else
                     39:                from++;
                     40: 
                     41:        for ( ; from < &g_edicts[globals.num_edicts] ; from++)
                     42:        {
                     43:                if (!from->inuse)
                     44:                        continue;
                     45:                s = *(char **) ((byte *)from + fieldofs);
                     46:                if (!s)
                     47:                        continue;
                     48:                if (!Q_stricmp (s, match))
                     49:                        return from;
                     50:        }
                     51: 
                     52:        return NULL;
                     53: }
                     54: 
                     55: 
                     56: /*
                     57: =================
                     58: findradius
                     59: 
                     60: Returns entities that have origins within a spherical area
                     61: 
                     62: findradius (origin, radius)
                     63: =================
                     64: */
                     65: edict_t *findradius (edict_t *from, vec3_t org, float rad)
                     66: {
                     67:        vec3_t  eorg;
                     68:        int             j;
                     69: 
                     70:        if (!from)
                     71:                from = g_edicts;
                     72:        else
                     73:                from++;
                     74:        for ( ; from < &g_edicts[globals.num_edicts]; from++)
                     75:        {
                     76:                if (!from->inuse)
                     77:                        continue;
                     78:                if (from->solid == SOLID_NOT)
                     79:                        continue;
                     80:                for (j=0 ; j<3 ; j++)
                     81:                        eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
                     82:                if (VectorLength(eorg) > rad)
                     83:                        continue;
                     84:                return from;
                     85:        }
                     86: 
                     87:        return NULL;
                     88: }
                     89: 
                     90: /*
                     91: =================
                     92: findradius2
                     93: 
                     94: Returns entities that have origins within a spherical area
                     95: 
                     96: ROGUE - tweaks for performance for tesla specific code
                     97: only returns entities that can be damaged
                     98: only returns entities that are SVF_DAMAGEABLE
                     99: 
                    100: findradius2 (origin, radius)
                    101: =================
                    102: */
                    103: edict_t *findradius2 (edict_t *from, vec3_t org, float rad)
                    104: {
                    105:        // rad must be positive
                    106:        vec3_t  eorg;
                    107:        int             j;
                    108: 
                    109:        if (!from)
                    110:                from = g_edicts;
                    111:        else
                    112:                from++;
                    113:        for ( ; from < &g_edicts[globals.num_edicts]; from++)
                    114:        {
                    115:                if (!from->inuse)
                    116:                        continue;
                    117:                if (from->solid == SOLID_NOT)
                    118:                        continue;
                    119:                if (!from->takedamage)
                    120:                        continue;
                    121:                if (!(from->svflags & SVF_DAMAGEABLE))
                    122:                        continue;
                    123:                for (j=0 ; j<3 ; j++)
                    124:                        eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
                    125:                if (VectorLength(eorg) > rad)
                    126:                        continue;
                    127:                return from;
                    128:        }
                    129: 
                    130:        return NULL;
                    131: }
                    132: 
                    133: 
                    134: /*
                    135: =============
                    136: G_PickTarget
                    137: 
                    138: Searches all active entities for the next one that holds
                    139: the matching string at fieldofs (use the FOFS() macro) in the structure.
                    140: 
                    141: Searches beginning at the edict after from, or the beginning if NULL
                    142: NULL will be returned if the end of the list is reached.
                    143: 
                    144: =============
                    145: */
                    146: #define MAXCHOICES     8
                    147: 
                    148: edict_t *G_PickTarget (char *targetname)
                    149: {
                    150:        edict_t *ent = NULL;
                    151:        int             num_choices = 0;
                    152:        edict_t *choice[MAXCHOICES];
                    153: 
                    154:        if (!targetname)
                    155:        {
                    156:                gi.dprintf("G_PickTarget called with NULL targetname\n");
                    157:                return NULL;
                    158:        }
                    159: 
                    160:        while(1)
                    161:        {
                    162:                ent = G_Find (ent, FOFS(targetname), targetname);
                    163:                if (!ent)
                    164:                        break;
                    165:                choice[num_choices++] = ent;
                    166:                if (num_choices == MAXCHOICES)
                    167:                        break;
                    168:        }
                    169: 
                    170:        if (!num_choices)
                    171:        {
                    172:                gi.dprintf("G_PickTarget: target %s not found\n", targetname);
                    173:                return NULL;
                    174:        }
                    175: 
                    176:        return choice[rand() % num_choices];
                    177: }
                    178: 
                    179: 
                    180: 
                    181: void Think_Delay (edict_t *ent)
                    182: {
                    183:        G_UseTargets (ent, ent->activator);
                    184:        G_FreeEdict (ent);
                    185: }
                    186: 
                    187: /*
                    188: ==============================
                    189: G_UseTargets
                    190: 
                    191: the global "activator" should be set to the entity that initiated the firing.
                    192: 
                    193: If self.delay is set, a DelayedUse entity will be created that will actually
                    194: do the SUB_UseTargets after that many seconds have passed.
                    195: 
                    196: Centerprints any self.message to the activator.
                    197: 
                    198: Search for (string)targetname in all entities that
                    199: match (string)self.target and call their .use function
                    200: 
                    201: ==============================
                    202: */
                    203: void G_UseTargets (edict_t *ent, edict_t *activator)
                    204: {
                    205:        edict_t         *t;
                    206:        edict_t         *master;
                    207:        qboolean        done = false;
                    208: 
                    209: //
                    210: // check for a delay
                    211: //
                    212:        if (ent->delay)
                    213:        {
                    214:        // create a temp object to fire at a later time
                    215:                t = G_Spawn();
                    216:                t->classname = "DelayedUse";
                    217:                t->nextthink = level.time + ent->delay;
                    218:                t->think = Think_Delay;
                    219:                t->activator = activator;
                    220:                if (!activator)
                    221:                        gi.dprintf ("Think_Delay with no activator\n");
                    222:                t->message = ent->message;
                    223:                t->target = ent->target;
                    224:                t->killtarget = ent->killtarget;
                    225:                return;
                    226:        }
                    227:        
                    228:        
                    229: //
                    230: // print the message
                    231: //
                    232:        if ((ent->message) && !(activator->svflags & SVF_MONSTER))
                    233:        {
                    234:                gi.centerprintf (activator, "%s", ent->message);
                    235:                if (ent->noise_index)
                    236:                        gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
                    237:                else
                    238:                        gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
                    239:        }
                    240: 
                    241: //
                    242: // kill killtargets
                    243: //
                    244:        if (ent->killtarget)
                    245:        {
                    246:                t = NULL;
                    247:                while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
                    248:                {
                    249:                        // PMM - if this entity is part of a train, cleanly remove it
                    250:                        if (t->flags & FL_TEAMSLAVE)
                    251:                        {
                    252:                                if ((g_showlogic) && (g_showlogic->value))
                    253:                                        gi.dprintf ("Removing %s from train!\n", t->classname);
                    254: 
                    255:                                if (t->teammaster)
                    256:                                {
                    257:                                        master = t->teammaster;
                    258:                                        while (!done)
                    259:                                        {
                    260:                                                if (master->teamchain == t)
                    261:                                                {
                    262:                                                        master->teamchain = t->teamchain;
                    263:                                                        done = true;
                    264:                                                }
                    265:                                                master = master->teamchain;
                    266:                                                if (!master)
                    267:                                                {
                    268:                                                        if ((g_showlogic) && (g_showlogic->value))
                    269:                                                                gi.dprintf ("Couldn't find myself in master's chain, ignoring!\n");
                    270:                                                }
                    271:                                        }
                    272:                                }
                    273:                                else
                    274:                                {
                    275:                                        if ((g_showlogic) && (g_showlogic->value))
                    276:                                                gi.dprintf ("No master to free myself from, ignoring!\n");
                    277:                                }
                    278:                        }
                    279:                        // PMM
                    280:                        G_FreeEdict (t);
                    281:                        if (!ent->inuse)
                    282:                        {
                    283:                                gi.dprintf("entity was removed while using killtargets\n");
                    284:                                return;
                    285:                        }
                    286:                }
                    287:        }
                    288: 
                    289: //
                    290: // fire targets
                    291: //
                    292:        if (ent->target)
                    293:        {
                    294:                t = NULL;
                    295:                while ((t = G_Find (t, FOFS(targetname), ent->target)))
                    296:                {
                    297:                        // doors fire area portals in a specific way
                    298:                        if (!Q_stricmp(t->classname, "func_areaportal") &&
                    299:                                (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
                    300:                                continue;
                    301: 
                    302:                        if (t == ent)
                    303:                        {
                    304:                                gi.dprintf ("WARNING: Entity used itself.\n");
                    305:                        }
                    306:                        else
                    307:                        {
                    308:                                if (t->use)
                    309:                                        t->use (t, ent, activator);
                    310:                        }
                    311:                        if (!ent->inuse)
                    312:                        {
                    313:                                gi.dprintf("entity was removed while using targets\n");
                    314:                                return;
                    315:                        }
                    316:                }
                    317:        }
                    318: }
                    319: 
                    320: 
                    321: /*
                    322: =============
                    323: TempVector
                    324: 
                    325: This is just a convenience function
                    326: for making temporary vectors for function calls
                    327: =============
                    328: */
                    329: float  *tv (float x, float y, float z)
                    330: {
                    331:        static  int             index;
                    332:        static  vec3_t  vecs[8];
                    333:        float   *v;
                    334: 
                    335:        // use an array so that multiple tempvectors won't collide
                    336:        // for a while
                    337:        v = vecs[index];
                    338:        index = (index + 1)&7;
                    339: 
                    340:        v[0] = x;
                    341:        v[1] = y;
                    342:        v[2] = z;
                    343: 
                    344:        return v;
                    345: }
                    346: 
                    347: 
                    348: /*
                    349: =============
                    350: VectorToString
                    351: 
                    352: This is just a convenience function
                    353: for printing vectors
                    354: =============
                    355: */
                    356: char   *vtos (vec3_t v)
                    357: {
                    358:        static  int             index;
                    359:        static  char    str[8][32];
                    360:        char    *s;
                    361: 
                    362:        // use an array so that multiple vtos won't collide
                    363:        s = str[index];
                    364:        index = (index + 1)&7;
                    365: 
                    366:        Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
                    367: 
                    368:        return s;
                    369: }
                    370: 
                    371: 
                    372: vec3_t VEC_UP          = {0, -1, 0};
                    373: vec3_t MOVEDIR_UP      = {0, 0, 1};
                    374: vec3_t VEC_DOWN                = {0, -2, 0};
                    375: vec3_t MOVEDIR_DOWN    = {0, 0, -1};
                    376: 
                    377: void G_SetMovedir (vec3_t angles, vec3_t movedir)
                    378: {
                    379:        if (VectorCompare (angles, VEC_UP))
                    380:        {
                    381:                VectorCopy (MOVEDIR_UP, movedir);
                    382:        }
                    383:        else if (VectorCompare (angles, VEC_DOWN))
                    384:        {
                    385:                VectorCopy (MOVEDIR_DOWN, movedir);
                    386:        }
                    387:        else
                    388:        {
                    389:                AngleVectors (angles, movedir, NULL, NULL);
                    390:        }
                    391: 
                    392:        VectorClear (angles);
                    393: }
                    394: 
                    395: 
                    396: float vectoyaw (vec3_t vec)
                    397: {
                    398:        float   yaw;
                    399:        
                    400:        // PMM - fixed to correct for pitch of 0
                    401:        if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
                    402:                if (vec[YAW] == 0)
                    403:                        yaw = 0;
                    404:                else if (vec[YAW] > 0)
                    405:                        yaw = 90;
                    406:                else
                    407:                        yaw = 270;
                    408:        else
                    409:        {
                    410:                yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
                    411:                if (yaw < 0)
                    412:                        yaw += 360;
                    413:        }
                    414: 
                    415:        return yaw;
                    416: }
                    417: 
                    418: float vectoyaw2 (vec3_t vec)
                    419: {
                    420:        float   yaw;
                    421:        
                    422:        // PMM - fixed to correct for pitch of 0
                    423:        if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
                    424:                if (vec[YAW] == 0)
                    425:                        yaw = 0;
                    426:                else if (vec[YAW] > 0)
                    427:                        yaw = 90;
                    428:                else
                    429:                        yaw = 270;
                    430:        else
                    431:        {
                    432:                yaw = (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
                    433:                if (yaw < 0)
                    434:                        yaw += 360;
                    435:        }
                    436: 
                    437:        return yaw;
                    438: }
                    439: 
                    440: 
                    441: void vectoangles (vec3_t value1, vec3_t angles)
                    442: {
                    443:        float   forward;
                    444:        float   yaw, pitch;
                    445:        
                    446:        if (value1[1] == 0 && value1[0] == 0)
                    447:        {
                    448:                yaw = 0;
                    449:                if (value1[2] > 0)
                    450:                        pitch = 90;
                    451:                else
                    452:                        pitch = 270;
                    453:        }
                    454:        else
                    455:        {
                    456:        // PMM - fixed to correct for pitch of 0
                    457:                if (value1[0])
                    458:                        yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
                    459:                else if (value1[1] > 0)
                    460:                        yaw = 90;
                    461:                else
                    462:                        yaw = 270;
                    463:                if (yaw < 0)
                    464:                        yaw += 360;
                    465: 
                    466:                forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
                    467:                pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
                    468:                if (pitch < 0)
                    469:                        pitch += 360;
                    470:        }
                    471: 
                    472:        angles[PITCH] = -pitch;
                    473:        angles[YAW] = yaw;
                    474:        angles[ROLL] = 0;
                    475: }
                    476: 
                    477: void vectoangles2 (vec3_t value1, vec3_t angles)
                    478: {
                    479:        float   forward;
                    480:        float   yaw, pitch;
                    481:        
                    482:        if (value1[1] == 0 && value1[0] == 0)
                    483:        {
                    484:                yaw = 0;
                    485:                if (value1[2] > 0)
                    486:                        pitch = 90;
                    487:                else
                    488:                        pitch = 270;
                    489:        }
                    490:        else
                    491:        {
                    492:        // PMM - fixed to correct for pitch of 0
                    493:                if (value1[0])
                    494:                        yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
                    495:                else if (value1[1] > 0)
                    496:                        yaw = 90;
                    497:                else
                    498:                        yaw = 270;
                    499: 
                    500:                if (yaw < 0)
                    501:                        yaw += 360;
                    502: 
                    503:                forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
                    504:                pitch = (atan2(value1[2], forward) * 180 / M_PI);
                    505:                if (pitch < 0)
                    506:                        pitch += 360;
                    507:        }
                    508: 
                    509:        angles[PITCH] = -pitch;
                    510:        angles[YAW] = yaw;
                    511:        angles[ROLL] = 0;
                    512: }
                    513: 
                    514: char *G_CopyString (char *in)
                    515: {
                    516:        char    *out;
                    517:        
                    518:        out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
                    519:        strcpy (out, in);
                    520:        return out;
                    521: }
                    522: 
                    523: 
                    524: void G_InitEdict (edict_t *e)
                    525: {
                    526:        // ROGUE
                    527:        // FIXME -
                    528:        //   this fixes a bug somewhere that is settling "nextthink" for an entity that has
                    529:        //   already been released.  nextthink is being set to FRAMETIME after level.time, 
                    530:        //   since freetime = nextthink - 0.1
                    531:        if (e->nextthink)
                    532:        {
                    533:                if ((g_showlogic) && (g_showlogic->value))
                    534:                        gi.dprintf ("G_SPAWN:  Fixed bad nextthink time\n");
                    535:                e->nextthink = 0;
                    536:        }
                    537:        // ROGUE
                    538: 
                    539:        e->inuse = true;
                    540:        e->classname = "noclass";
                    541:        e->gravity = 1.0;
                    542:        e->s.number = e - g_edicts;
                    543: 
                    544: //PGM - do this before calling the spawn function so it can be overridden.
                    545: #ifdef ROGUE_GRAVITY
                    546:        e->gravityVector[0] =  0.0;
                    547:        e->gravityVector[1] =  0.0;
                    548:        e->gravityVector[2] = -1.0;
                    549: #endif
                    550: //PGM
                    551: }
                    552: 
                    553: /*
                    554: =================
                    555: G_Spawn
                    556: 
                    557: Either finds a free edict, or allocates a new one.
                    558: Try to avoid reusing an entity that was recently freed, because it
                    559: can cause the client to think the entity morphed into something else
                    560: instead of being removed and recreated, which can cause interpolated
                    561: angles and bad trails.
                    562: =================
                    563: */
                    564: edict_t *G_Spawn (void)
                    565: {
                    566:        int                     i;
                    567:        edict_t         *e;
                    568: 
                    569:        e = &g_edicts[(int)maxclients->value+1];
                    570:        for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
                    571:        {
                    572:                // the first couple seconds of server time can involve a lot of
                    573:                // freeing and allocating, so relax the replacement policy
                    574:                if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
                    575:                {
                    576:                        G_InitEdict (e);
                    577:                        return e;
                    578:                }
                    579:        }
                    580:        
                    581:        if (i == game.maxentities)
                    582:                gi.error ("ED_Alloc: no free edicts");
                    583:                
                    584:        globals.num_edicts++;
                    585:        G_InitEdict (e);
                    586:        return e;
                    587: }
                    588: 
                    589: /*
                    590: =================
                    591: G_FreeEdict
                    592: 
                    593: Marks the edict as free
                    594: =================
                    595: */
                    596: void G_FreeEdict (edict_t *ed)
                    597: {
                    598:        gi.unlinkentity (ed);           // unlink from world
                    599: 
                    600:        if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
                    601:        {
                    602: //             gi.dprintf("tried to free special edict\n");
                    603:                return;
                    604:        }
                    605: 
                    606:        memset (ed, 0, sizeof(*ed));
                    607:        ed->classname = "freed";
                    608:        ed->freetime = level.time;
                    609:        ed->inuse = false;
                    610: }
                    611: 
                    612: 
                    613: /*
                    614: ============
                    615: G_TouchTriggers
                    616: 
                    617: ============
                    618: */
                    619: void   G_TouchTriggers (edict_t *ent)
                    620: {
                    621:        int                     i, num;
                    622:        edict_t         *touch[MAX_EDICTS], *hit;
                    623: 
                    624:        // dead things don't activate triggers!
                    625:        if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
                    626:                return;
                    627: 
                    628:        num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
                    629:                , MAX_EDICTS, AREA_TRIGGERS);
                    630: 
                    631:        // be careful, it is possible to have an entity in this
                    632:        // list removed before we get to it (killtriggered)
                    633:        for (i=0 ; i<num ; i++)
                    634:        {
                    635:                hit = touch[i];
                    636:                if (!hit->inuse)
                    637:                        continue;
                    638:                if (!hit->touch)
                    639:                        continue;
                    640:                hit->touch (hit, ent, NULL, NULL);
                    641:        }
                    642: }
                    643: 
                    644: /*
                    645: ============
                    646: G_TouchSolids
                    647: 
                    648: Call after linking a new trigger in during gameplay
                    649: to force all entities it covers to immediately touch it
                    650: ============
                    651: */
                    652: void   G_TouchSolids (edict_t *ent)
                    653: {
                    654:        int                     i, num;
                    655:        edict_t         *touch[MAX_EDICTS], *hit;
                    656: 
                    657:        num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
                    658:                , MAX_EDICTS, AREA_SOLID);
                    659: 
                    660:        // be careful, it is possible to have an entity in this
                    661:        // list removed before we get to it (killtriggered)
                    662:        for (i=0 ; i<num ; i++)
                    663:        {
                    664:                hit = touch[i];
                    665:                if (!hit->inuse)
                    666:                        continue;
                    667:                if (ent->touch)
                    668:                        ent->touch (hit, ent, NULL, NULL);
                    669:                if (!ent->inuse)
                    670:                        break;
                    671:        }
                    672: }
                    673: 
                    674: 
                    675: 
                    676: 
                    677: /*
                    678: ==============================================================================
                    679: 
                    680: Kill box
                    681: 
                    682: ==============================================================================
                    683: */
                    684: 
                    685: /*
                    686: =================
                    687: KillBox
                    688: 
                    689: Kills all entities that would touch the proposed new positioning
                    690: of ent.  Ent should be unlinked before calling this!
                    691: =================
                    692: */
                    693: qboolean KillBox (edict_t *ent)
                    694: {
                    695:        trace_t         tr;
                    696: 
                    697:        while (1)
                    698:        {
                    699:                tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
                    700:                if (!tr.ent)
                    701:                        break;
                    702: 
                    703:                // nail it
                    704:                T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
                    705: 
                    706:                // if we didn't kill it, fail
                    707:                if (tr.ent->solid)
                    708:                        return false;
                    709:        }
                    710: 
                    711:        return true;            // all clear
                    712: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.