Annotation of quake2/xatrix/g_misc.c, revision 1.1.1.1

1.1       root        1: // g_misc.c
                      2: 
                      3: #include "g_local.h"
                      4: 
                      5: 
                      6: /*QUAKED func_group (0 0 0) ?
                      7: Used to group brushes together just for editor convenience.
                      8: */
                      9: 
                     10: //=====================================================
                     11: 
                     12: void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
                     13: {
                     14:        ent->count ^= 1;                // toggle state
                     15: //     gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
                     16:        gi.SetAreaPortalState (ent->style, ent->count);
                     17: }
                     18: 
                     19: /*QUAKED func_areaportal (0 0 0) ?
                     20: 
                     21: This is a non-visible object that divides the world into
                     22: areas that are seperated when this portal is not activated.
                     23: Usually enclosed in the middle of a door.
                     24: */
                     25: void SP_func_areaportal (edict_t *ent)
                     26: {
                     27:        ent->use = Use_Areaportal;
                     28:        ent->count = 0;         // always start closed;
                     29: }
                     30: 
                     31: //=====================================================
                     32: 
                     33: 
                     34: /*
                     35: =================
                     36: Misc functions
                     37: =================
                     38: */
                     39: void VelocityForDamage (int damage, vec3_t v)
                     40: {
                     41:        v[0] = 100.0 * crandom();
                     42:        v[1] = 100.0 * crandom();
                     43:        v[2] = 200.0 + 100.0 * random();
                     44: 
                     45:        if (damage < 50)
                     46:                VectorScale (v, 0.7, v);
                     47:        else 
                     48:                VectorScale (v, 1.2, v);
                     49: }
                     50: 
                     51: void ClipGibVelocity (edict_t *ent)
                     52: {
                     53:        if (ent->velocity[0] < -300)
                     54:                ent->velocity[0] = -300;
                     55:        else if (ent->velocity[0] > 300)
                     56:                ent->velocity[0] = 300;
                     57:        if (ent->velocity[1] < -300)
                     58:                ent->velocity[1] = -300;
                     59:        else if (ent->velocity[1] > 300)
                     60:                ent->velocity[1] = 300;
                     61:        if (ent->velocity[2] < 200)
                     62:                ent->velocity[2] = 200; // always some upwards
                     63:        else if (ent->velocity[2] > 500)
                     64:                ent->velocity[2] = 500;
                     65: }
                     66: 
                     67: 
                     68: /*
                     69: =================
                     70: gibs
                     71: =================
                     72: */
                     73: void gib_think (edict_t *self)
                     74: {
                     75:        self->s.frame++;
                     76:        self->nextthink = level.time + FRAMETIME;
                     77: 
                     78:        if (self->s.frame == 10)
                     79:        {
                     80:                self->think = G_FreeEdict;
                     81:                self->nextthink = level.time + 8 + random()*10;
                     82:        }
                     83: }
                     84: 
                     85: void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                     86: {
                     87:        vec3_t  normal_angles, right;
                     88: 
                     89:        if (!self->groundentity)
                     90:                return;
                     91: 
                     92:        self->touch = NULL;
                     93: 
                     94:        if (plane)
                     95:        {
                     96:                gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
                     97: 
                     98:                vectoangles (plane->normal, normal_angles);
                     99:                AngleVectors (normal_angles, NULL, right, NULL);
                    100:                vectoangles (right, self->s.angles);
                    101: 
                    102:                if (self->s.modelindex == sm_meat_index)
                    103:                {
                    104:                        self->s.frame++;
                    105:                        self->think = gib_think;
                    106:                        self->nextthink = level.time + FRAMETIME;
                    107:                }
                    108:        }
                    109: }
                    110: 
                    111: // RAFAEL 24-APR-98
                    112: // removed acid damage
                    113: #if 0
                    114: // RAFAEL
                    115: void gib_touchacid (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    116: {
                    117:        vec3_t normal_angles, right;
                    118: 
                    119:        if (other->takedamage)
                    120:        {
                    121:                T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
                    122:                G_FreeEdict (self);
                    123:        }
                    124: 
                    125:        if (!self->groundentity)
                    126:                return;
                    127: 
                    128:        if (plane)
                    129:        {
                    130:                gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
                    131: 
                    132:                vectoangles (plane->normal, normal_angles);
                    133:                AngleVectors (normal_angles, NULL, right, NULL);
                    134:                vectoangles (right, self->s.angles);
                    135: 
                    136:                if (self->s.modelindex == sm_meat_index)
                    137:                {
                    138:                        self->s.frame++;
                    139:                        self->think = gib_think;
                    140:                        self->nextthink = level.time + FRAMETIME;
                    141:                }
                    142:        }
                    143: }
                    144: #endif
                    145: 
                    146: void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    147: {
                    148:        G_FreeEdict (self);
                    149: }
                    150: 
                    151: void ThrowGib (edict_t *self, char *gibname, int damage, int type)
                    152: {
                    153:        edict_t *gib;
                    154:        vec3_t  vd;
                    155:        vec3_t  origin;
                    156:        vec3_t  size;
                    157:        float   vscale;
                    158: 
                    159:        gib = G_Spawn();
                    160: 
                    161:        VectorScale (self->size, 0.5, size);
                    162:        VectorAdd (self->absmin, size, origin);
                    163:        gib->s.origin[0] = origin[0] + crandom() * size[0];
                    164:        gib->s.origin[1] = origin[1] + crandom() * size[1];
                    165:        gib->s.origin[2] = origin[2] + crandom() * size[2];
                    166: 
                    167:        gi.setmodel (gib, gibname);
                    168:        gib->solid = SOLID_NOT;
                    169:        gib->s.effects |= EF_GIB;
                    170:        gib->flags |= FL_NO_KNOCKBACK;
                    171:        gib->takedamage = DAMAGE_YES;
                    172:        gib->die = gib_die;
                    173: 
                    174:        if (type == GIB_ORGANIC)
                    175:        {
                    176:                gib->movetype = MOVETYPE_TOSS;
                    177:                gib->touch = gib_touch;
                    178:                vscale = 0.5;
                    179:        }
                    180:        else
                    181:        {
                    182:                gib->movetype = MOVETYPE_BOUNCE;
                    183:                vscale = 1.0;
                    184:        }
                    185: 
                    186:        VelocityForDamage (damage, vd);
                    187:        VectorMA (self->velocity, vscale, vd, gib->velocity);
                    188:        ClipGibVelocity (gib);
                    189:        gib->avelocity[0] = random()*600;
                    190:        gib->avelocity[1] = random()*600;
                    191:        gib->avelocity[2] = random()*600;
                    192: 
                    193:        gib->think = G_FreeEdict;
                    194:        gib->nextthink = level.time + 10 + random()*10;
                    195: 
                    196:        gi.linkentity (gib);
                    197: }
                    198: 
                    199: 
                    200: 
                    201: void ThrowHead (edict_t *self, char *gibname, int damage, int type)
                    202: {
                    203:        vec3_t  vd;
                    204:        float   vscale;
                    205: 
                    206:        self->s.skinnum = 0;
                    207:        self->s.frame = 0;
                    208:        VectorClear (self->mins);
                    209:        VectorClear (self->maxs);
                    210: 
                    211:        self->s.modelindex2 = 0;
                    212:        gi.setmodel (self, gibname);
                    213:        self->solid = SOLID_NOT;
                    214:        self->s.effects |= EF_GIB;
                    215:        self->s.effects &= ~EF_FLIES;
                    216:        self->s.sound = 0;
                    217:        self->flags |= FL_NO_KNOCKBACK;
                    218:        self->svflags &= ~SVF_MONSTER;
                    219:        self->takedamage = DAMAGE_YES;
                    220:        self->die = gib_die;
                    221: 
                    222:        if (type == GIB_ORGANIC)
                    223:        {
                    224:                self->movetype = MOVETYPE_TOSS;
                    225:                self->touch = gib_touch;
                    226:                vscale = 0.5;
                    227:        }
                    228:        else
                    229:        {
                    230:                self->movetype = MOVETYPE_BOUNCE;
                    231:                vscale = 1.0;
                    232:        }
                    233: 
                    234:        VelocityForDamage (damage, vd);
                    235:        VectorMA (self->velocity, vscale, vd, self->velocity);
                    236:        ClipGibVelocity (self);
                    237: 
                    238:        self->avelocity[YAW] = crandom()*600;
                    239: 
                    240:        self->think = G_FreeEdict;
                    241:        self->nextthink = level.time + 10 + random()*10;
                    242: 
                    243:        gi.linkentity (self);
                    244: }
                    245: 
                    246: 
                    247: // RAFAEL
                    248: void ThrowGibACID (edict_t *self, char *gibname, int damage, int type)
                    249: {
                    250:        edict_t *gib;
                    251:        vec3_t vd;
                    252:        vec3_t origin;
                    253:        vec3_t size;
                    254:        float vscale;
                    255: 
                    256:        gib = G_Spawn();
                    257: 
                    258:        VectorScale (self->size, 0.5, size);
                    259:        VectorAdd (self->absmin, size, origin);
                    260:        gib->s.origin[0] = origin[0] + crandom() * size[0];
                    261:        gib->s.origin[1] = origin[1] + crandom() * size[1];
                    262:        gib->s.origin[2] = origin[2] + crandom() * size[2];
                    263: 
                    264:        // gi.setmodel (gib, gibname);
                    265:        gib->s.modelindex = gi.modelindex (gibname);
                    266: 
                    267:        gib->clipmask = MASK_SHOT;
                    268:        gib->solid = SOLID_BBOX;
                    269:  
                    270:        gib->s.effects |= EF_GREENGIB;
                    271:        // note to self check this
                    272:        gib->s.renderfx |= RF_FULLBRIGHT;
                    273:        gib->flags |= FL_NO_KNOCKBACK;
                    274:        gib->takedamage = DAMAGE_YES;
                    275:        gib->die = gib_die;
                    276:        gib->dmg = 2;
                    277: 
                    278:        if (type == GIB_ORGANIC)
                    279:        {
                    280:                gib->movetype = MOVETYPE_TOSS;
                    281:                // RAFAEL 24-APR-98
                    282:                // removed acid damage
                    283:                //gib->touch = gib_touchacid;
                    284:                vscale = 3.0;
                    285:        }
                    286:        else
                    287:        {
                    288:                gib->movetype = MOVETYPE_BOUNCE;
                    289:                vscale = 1.0;
                    290:        }
                    291: 
                    292:        VelocityForDamage (damage, vd);
                    293:        VectorMA (self->velocity, vscale, vd, gib->velocity);
                    294:        ClipGibVelocity (gib);
                    295:        gib->avelocity[0] = random()*600;
                    296:        gib->avelocity[1] = random()*600;
                    297:        gib->avelocity[2] = random()*600;
                    298: 
                    299:        gib->think = G_FreeEdict;
                    300:        gib->nextthink = level.time + 10 + random()*10;
                    301: 
                    302:        gi.linkentity (gib);
                    303: }
                    304: 
                    305: // RAFAEL
                    306: void ThrowHeadACID (edict_t *self, char *gibname, int damage, int type)
                    307: {
                    308:        vec3_t vd;
                    309:        float vscale;
                    310: 
                    311:        self->s.skinnum = 0;
                    312:        self->s.frame = 0;
                    313:        VectorClear (self->mins);
                    314:        VectorClear (self->maxs);
                    315: 
                    316:        self->s.modelindex2 = 0;
                    317:        gi.setmodel (self, gibname);
                    318:  
                    319:        self->clipmask = MASK_SHOT;
                    320:        self->solid = SOLID_BBOX;
                    321:   
                    322:        self->s.effects |= EF_GREENGIB;
                    323:        self->s.effects &= ~EF_FLIES;
                    324:        self->s.effects |= RF_FULLBRIGHT;
                    325:        self->s.sound = 0;
                    326:        self->flags |= FL_NO_KNOCKBACK;
                    327:        self->svflags &= ~SVF_MONSTER;
                    328:        self->takedamage = DAMAGE_YES;
                    329:        self->die = gib_die;
                    330:        self->dmg = 2;
                    331: 
                    332:        if (type == GIB_ORGANIC)
                    333:        {
                    334:                self->movetype = MOVETYPE_TOSS;
                    335:                // RAFAEL 24-APR-98
                    336:                // removed acid damage
                    337:                // self->touch = gib_touchacid;
                    338:                vscale = 0.5;
                    339:        }
                    340:        else
                    341:        {
                    342:                self->movetype = MOVETYPE_BOUNCE;
                    343:                vscale = 1.0;
                    344:        }
                    345: 
                    346:        VelocityForDamage (damage, vd);
                    347:        VectorMA (self->velocity, vscale, vd, self->velocity);
                    348:        ClipGibVelocity (self);
                    349: 
                    350:        self->avelocity[YAW] = crandom()*600;
                    351: 
                    352:        self->think = G_FreeEdict;
                    353:        self->nextthink = level.time + 10 + random()*10;
                    354: 
                    355:        gi.linkentity (self);
                    356: }
                    357: 
                    358: 
                    359: void ThrowClientHead (edict_t *self, int damage)
                    360: {
                    361:        vec3_t  vd;
                    362:        char    *gibname;
                    363: 
                    364:        if (rand()&1)
                    365:        {
                    366:                gibname = "models/objects/gibs/head2/tris.md2";
                    367:                self->s.skinnum = 1;            // second skin is player
                    368:        }
                    369:        else
                    370:        {
                    371:                gibname = "models/objects/gibs/skull/tris.md2";
                    372:                self->s.skinnum = 0;
                    373:        }
                    374: 
                    375:        self->s.origin[2] += 32;
                    376:        self->s.frame = 0;
                    377:        gi.setmodel (self, gibname);
                    378:        VectorSet (self->mins, -16, -16, 0);
                    379:        VectorSet (self->maxs, 16, 16, 16);
                    380: 
                    381:        self->takedamage = DAMAGE_NO;
                    382:        self->solid = SOLID_NOT;
                    383:        self->s.effects = EF_GIB;
                    384:        self->s.sound = 0;
                    385:        self->flags |= FL_NO_KNOCKBACK;
                    386: 
                    387:        self->movetype = MOVETYPE_BOUNCE;
                    388:        VelocityForDamage (damage, vd);
                    389:        VectorAdd (self->velocity, vd, self->velocity);
                    390: 
                    391:        if (self->client)       // bodies in the queue don't have a client anymore
                    392:        {
                    393:                self->client->anim_priority = ANIM_DEATH;
                    394:                self->client->anim_end = self->s.frame;
                    395:        }
                    396:        else
                    397:        {
                    398:                self->think = NULL;
                    399:                self->nextthink = 0;
                    400:        }
                    401: 
                    402:        gi.linkentity (self);
                    403: }
                    404: 
                    405: 
                    406: /*
                    407: =================
                    408: debris
                    409: =================
                    410: */
                    411: void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    412: {
                    413:        G_FreeEdict (self);
                    414: }
                    415: 
                    416: void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
                    417: {
                    418:        edict_t *chunk;
                    419:        vec3_t  v;
                    420: 
                    421:        chunk = G_Spawn();
                    422:        VectorCopy (origin, chunk->s.origin);
                    423:        gi.setmodel (chunk, modelname);
                    424:        v[0] = 100 * crandom();
                    425:        v[1] = 100 * crandom();
                    426:        v[2] = 100 + 100 * crandom();
                    427:        VectorMA (self->velocity, speed, v, chunk->velocity);
                    428:        chunk->movetype = MOVETYPE_BOUNCE;
                    429:        chunk->solid = SOLID_NOT;
                    430:        chunk->avelocity[0] = random()*600;
                    431:        chunk->avelocity[1] = random()*600;
                    432:        chunk->avelocity[2] = random()*600;
                    433:        chunk->think = G_FreeEdict;
                    434:        chunk->nextthink = level.time + 5 + random()*5;
                    435:        chunk->s.frame = 0;
                    436:        chunk->flags = 0;
                    437:        chunk->classname = "debris";
                    438:        chunk->takedamage = DAMAGE_YES;
                    439:        chunk->die = debris_die;
                    440:        gi.linkentity (chunk);
                    441: }
                    442: 
                    443: 
                    444: void BecomeExplosion1 (edict_t *self)
                    445: {
                    446:        gi.WriteByte (svc_temp_entity);
                    447:        gi.WriteByte (TE_EXPLOSION1);
                    448:        gi.WritePosition (self->s.origin);
                    449:        gi.multicast (self->s.origin, MULTICAST_PVS);
                    450: 
                    451:        G_FreeEdict (self);
                    452: }
                    453: 
                    454: 
                    455: void BecomeExplosion2 (edict_t *self)
                    456: {
                    457:        gi.WriteByte (svc_temp_entity);
                    458:        gi.WriteByte (TE_EXPLOSION2);
                    459:        gi.WritePosition (self->s.origin);
                    460:        gi.multicast (self->s.origin, MULTICAST_PVS);
                    461: 
                    462:        G_FreeEdict (self);
                    463: }
                    464: 
                    465: 
                    466: /*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
                    467: Target: next path corner
                    468: Pathtarget: gets used when an entity that has
                    469:        this path_corner targeted touches it
                    470: */
                    471: 
                    472: void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    473: {
                    474:        vec3_t          v;
                    475:        edict_t         *next;
                    476: 
                    477:        if (other->movetarget != self)
                    478:                return;
                    479:        
                    480:        if (other->enemy)
                    481:                return;
                    482: 
                    483:        if (self->pathtarget)
                    484:        {
                    485:                char *savetarget;
                    486: 
                    487:                savetarget = self->target;
                    488:                self->target = self->pathtarget;
                    489:                G_UseTargets (self, other);
                    490:                self->target = savetarget;
                    491:        }
                    492: 
                    493:        if (self->target)
                    494:                next = G_PickTarget(self->target);
                    495:        else
                    496:                next = NULL;
                    497: 
                    498:        if ((next) && (next->spawnflags & 1))
                    499:        {
                    500:                VectorCopy (next->s.origin, v);
                    501:                v[2] += next->mins[2];
                    502:                v[2] -= other->mins[2];
                    503:                VectorCopy (v, other->s.origin);
                    504:                next = G_PickTarget(next->target);
                    505:                other->s.event = EV_OTHER_TELEPORT;
                    506:        }
                    507: 
                    508:        other->goalentity = other->movetarget = next;
                    509: 
                    510:        if (self->wait)
                    511:        {
                    512:                other->monsterinfo.pausetime = level.time + self->wait;
                    513:                other->monsterinfo.stand (other);
                    514:                return;
                    515:        }
                    516: 
                    517:        if (!other->movetarget)
                    518:        {
                    519:                other->monsterinfo.pausetime = level.time + 100000000;
                    520:                other->monsterinfo.stand (other);
                    521:        }
                    522:        else
                    523:        {
                    524:                VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
                    525:                other->ideal_yaw = vectoyaw (v);
                    526:        }
                    527: }
                    528: 
                    529: void SP_path_corner (edict_t *self)
                    530: {
                    531:        if (!self->targetname)
                    532:        {
                    533:                gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
                    534:                G_FreeEdict (self);
                    535:                return;
                    536:        }
                    537: 
                    538:        self->solid = SOLID_TRIGGER;
                    539:        self->touch = path_corner_touch;
                    540:        VectorSet (self->mins, -8, -8, -8);
                    541:        VectorSet (self->maxs, 8, 8, 8);
                    542:        self->svflags |= SVF_NOCLIENT;
                    543:        gi.linkentity (self);
                    544: }
                    545: 
                    546: 
                    547: /*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
                    548: Makes this the target of a monster and it will head here
                    549: when first activated before going after the activator.  If
                    550: hold is selected, it will stay here.
                    551: */
                    552: void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    553: {
                    554:        edict_t *activator;
                    555: 
                    556:        if (other->movetarget != self)
                    557:                return;
                    558: 
                    559:        if (self->target)
                    560:        {
                    561:                other->target = self->target;
                    562:                other->goalentity = other->movetarget = G_PickTarget(other->target);
                    563:                if (!other->goalentity)
                    564:                {
                    565:                        gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
                    566:                        other->movetarget = self;
                    567:                }
                    568:                self->target = NULL;
                    569:        }
                    570:        else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY)))
                    571:        {
                    572:                other->monsterinfo.pausetime = level.time + 100000000;
                    573:                other->monsterinfo.aiflags |= AI_STAND_GROUND;
                    574:                other->monsterinfo.stand (other);
                    575:        }
                    576: 
                    577:        if (other->movetarget == self)
                    578:        {
                    579:                other->target = NULL;
                    580:                other->movetarget = NULL;
                    581:                other->goalentity = other->enemy;
                    582:                other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
                    583:        }
                    584: 
                    585:        if (self->pathtarget)
                    586:        {
                    587:                char *savetarget;
                    588: 
                    589:                savetarget = self->target;
                    590:                self->target = self->pathtarget;
                    591:                if (other->enemy && other->enemy->client)
                    592:                        activator = other->enemy;
                    593:                else if (other->oldenemy && other->oldenemy->client)
                    594:                        activator = other->oldenemy;
                    595:                else if (other->activator && other->activator->client)
                    596:                        activator = other->activator;
                    597:                else
                    598:                        activator = other;
                    599:                G_UseTargets (self, activator);
                    600:                self->target = savetarget;
                    601:        }
                    602: }
                    603: 
                    604: void SP_point_combat (edict_t *self)
                    605: {
                    606:        if (deathmatch->value)
                    607:        {
                    608:                G_FreeEdict (self);
                    609:                return;
                    610:        }
                    611:        self->solid = SOLID_TRIGGER;
                    612:        self->touch = point_combat_touch;
                    613:        VectorSet (self->mins, -8, -8, -16);
                    614:        VectorSet (self->maxs, 8, 8, 16);
                    615:        self->svflags = SVF_NOCLIENT;
                    616:        gi.linkentity (self);
                    617: };
                    618: 
                    619: 
                    620: /*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
                    621: Just for the debugging level.  Don't use
                    622: */
                    623: void TH_viewthing(edict_t *ent)
                    624: {
                    625:        ent->s.frame = (ent->s.frame + 1) % 7;
                    626:        ent->nextthink = level.time + FRAMETIME;
                    627: }
                    628: 
                    629: void SP_viewthing(edict_t *ent)
                    630: {
                    631:        gi.dprintf ("viewthing spawned\n");
                    632: 
                    633:        ent->movetype = MOVETYPE_NONE;
                    634:        ent->solid = SOLID_BBOX;
                    635:        ent->s.renderfx = RF_FRAMELERP;
                    636:        VectorSet (ent->mins, -16, -16, -24);
                    637:        VectorSet (ent->maxs, 16, 16, 32);
                    638:        ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
                    639:        gi.linkentity (ent);
                    640:        ent->nextthink = level.time + 0.5;
                    641:        ent->think = TH_viewthing;
                    642:        return;
                    643: }
                    644: 
                    645: 
                    646: /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
                    647: Used as a positional target for spotlights, etc.
                    648: */
                    649: void SP_info_null (edict_t *self)
                    650: {
                    651:        G_FreeEdict (self);
                    652: };
                    653: 
                    654: 
                    655: /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
                    656: Used as a positional target for lightning.
                    657: */
                    658: void SP_info_notnull (edict_t *self)
                    659: {
                    660:        VectorCopy (self->s.origin, self->absmin);
                    661:        VectorCopy (self->s.origin, self->absmax);
                    662: };
                    663: 
                    664: 
                    665: /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
                    666: Non-displayed light.
                    667: Default light value is 300.
                    668: Default style is 0.
                    669: If targeted, will toggle between on and off.
                    670: Default _cone value is 10 (used to set size of light for spotlights)
                    671: */
                    672: 
                    673: #define START_OFF      1
                    674: 
                    675: static void light_use (edict_t *self, edict_t *other, edict_t *activator)
                    676: {
                    677:        if (self->spawnflags & START_OFF)
                    678:        {
                    679:                gi.configstring (CS_LIGHTS+self->style, "m");
                    680:                self->spawnflags &= ~START_OFF;
                    681:        }
                    682:        else
                    683:        {
                    684:                gi.configstring (CS_LIGHTS+self->style, "a");
                    685:                self->spawnflags |= START_OFF;
                    686:        }
                    687: }
                    688: 
                    689: void SP_light (edict_t *self)
                    690: {
                    691:        // no targeted lights in deathmatch, because they cause global messages
                    692:        if (!self->targetname || deathmatch->value)
                    693:        {
                    694:                G_FreeEdict (self);
                    695:                return;
                    696:        }
                    697: 
                    698:        if (self->style >= 32)
                    699:        {
                    700:                self->use = light_use;
                    701:                if (self->spawnflags & START_OFF)
                    702:                        gi.configstring (CS_LIGHTS+self->style, "a");
                    703:                else
                    704:                        gi.configstring (CS_LIGHTS+self->style, "m");
                    705:        }
                    706: }
                    707: 
                    708: 
                    709: /*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
                    710: This is just a solid wall if not inhibited
                    711: 
                    712: TRIGGER_SPAWN  the wall will not be present until triggered
                    713:                                it will then blink in to existance; it will
                    714:                                kill anything that was in it's way
                    715: 
                    716: TOGGLE                 only valid for TRIGGER_SPAWN walls
                    717:                                this allows the wall to be turned on and off
                    718: 
                    719: START_ON               only valid for TRIGGER_SPAWN walls
                    720:                                the wall will initially be present
                    721: */
                    722: 
                    723: void func_wall_use (edict_t *self, edict_t *other, edict_t *activator)
                    724: {
                    725:        if (self->solid == SOLID_NOT)
                    726:        {
                    727:                self->solid = SOLID_BSP;
                    728:                self->svflags &= ~SVF_NOCLIENT;
                    729:                KillBox (self);
                    730:        }
                    731:        else
                    732:        {
                    733:                self->solid = SOLID_NOT;
                    734:                self->svflags |= SVF_NOCLIENT;
                    735:        }
                    736:        gi.linkentity (self);
                    737: 
                    738:        if (!(self->spawnflags & 2))
                    739:                self->use = NULL;
                    740: }
                    741: 
                    742: void SP_func_wall (edict_t *self)
                    743: {
                    744:        self->movetype = MOVETYPE_PUSH;
                    745:        gi.setmodel (self, self->model);
                    746: 
                    747:        if (self->spawnflags & 8)
                    748:                self->s.effects |= EF_ANIM_ALL;
                    749:        if (self->spawnflags & 16)
                    750:                self->s.effects |= EF_ANIM_ALLFAST;
                    751: 
                    752:        // just a wall
                    753:        if ((self->spawnflags & 7) == 0)
                    754:        {
                    755:                self->solid = SOLID_BSP;
                    756:                gi.linkentity (self);
                    757:                return;
                    758:        }
                    759: 
                    760:        // it must be TRIGGER_SPAWN
                    761:        if (!(self->spawnflags & 1))
                    762:        {
                    763: //             gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
                    764:                self->spawnflags |= 1;
                    765:        }
                    766: 
                    767:        // yell if the spawnflags are odd
                    768:        if (self->spawnflags & 4)
                    769:        {
                    770:                if (!(self->spawnflags & 2))
                    771:                {
                    772:                        gi.dprintf("func_wall START_ON without TOGGLE\n");
                    773:                        self->spawnflags |= 2;
                    774:                }
                    775:        }
                    776: 
                    777:        self->use = func_wall_use;
                    778:        if (self->spawnflags & 4)
                    779:        {
                    780:                self->solid = SOLID_BSP;
                    781:        }
                    782:        else
                    783:        {
                    784:                self->solid = SOLID_NOT;
                    785:                self->svflags |= SVF_NOCLIENT;
                    786:        }
                    787:        gi.linkentity (self);
                    788: }
                    789: 
                    790: 
                    791: /*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
                    792: This is solid bmodel that will fall if it's support it removed.
                    793: */
                    794: 
                    795: void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                    796: {
                    797:        // only squash thing we fall on top of
                    798:        if (!plane)
                    799:                return;
                    800:        if (plane->normal[2] < 1.0)
                    801:                return;
                    802:        if (other->takedamage == DAMAGE_NO)
                    803:                return;
                    804:        T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
                    805: }
                    806: 
                    807: void func_object_release (edict_t *self)
                    808: {
                    809:        self->movetype = MOVETYPE_TOSS;
                    810:        self->touch = func_object_touch;
                    811: }
                    812: 
                    813: void func_object_use (edict_t *self, edict_t *other, edict_t *activator)
                    814: {
                    815:        self->solid = SOLID_BSP;
                    816:        self->svflags &= ~SVF_NOCLIENT;
                    817:        self->use = NULL;
                    818:        KillBox (self);
                    819:        func_object_release (self);
                    820: }
                    821: 
                    822: void SP_func_object (edict_t *self)
                    823: {
                    824:        gi.setmodel (self, self->model);
                    825: 
                    826:        self->mins[0] += 1;
                    827:        self->mins[1] += 1;
                    828:        self->mins[2] += 1;
                    829:        self->maxs[0] -= 1;
                    830:        self->maxs[1] -= 1;
                    831:        self->maxs[2] -= 1;
                    832: 
                    833:        if (!self->dmg)
                    834:                self->dmg = 100;
                    835: 
                    836:        if (self->spawnflags == 0)
                    837:        {
                    838:                self->solid = SOLID_BSP;
                    839:                self->movetype = MOVETYPE_PUSH;
                    840:                self->think = func_object_release;
                    841:                self->nextthink = level.time + 2 * FRAMETIME;
                    842:        }
                    843:        else
                    844:        {
                    845:                self->solid = SOLID_NOT;
                    846:                self->movetype = MOVETYPE_PUSH;
                    847:                self->use = func_object_use;
                    848:                self->svflags |= SVF_NOCLIENT;
                    849:        }
                    850: 
                    851:        if (self->spawnflags & 2)
                    852:                self->s.effects |= EF_ANIM_ALL;
                    853:        if (self->spawnflags & 4)
                    854:                self->s.effects |= EF_ANIM_ALLFAST;
                    855: 
                    856:        self->clipmask = MASK_MONSTERSOLID;
                    857: 
                    858:        gi.linkentity (self);
                    859: }
                    860: 
                    861: 
                    862: /*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
                    863: Any brush that you want to explode or break apart.  If you want an
                    864: ex0plosion, set dmg and it will do a radius explosion of that amount
                    865: at the center of the bursh.
                    866: 
                    867: If targeted it will not be shootable.
                    868: 
                    869: health defaults to 100.
                    870: 
                    871: mass defaults to 75.  This determines how much debris is emitted when
                    872: it explodes.  You get one large chunk per 100 of mass (up to 8) and
                    873: one small chunk per 25 of mass (up to 16).  So 800 gives the most.
                    874: */
                    875: void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    876: {
                    877:        vec3_t  origin;
                    878:        vec3_t  chunkorigin;
                    879:        vec3_t  size;
                    880:        int             count;
                    881:        int             mass;
                    882: 
                    883:        // bmodel origins are (0 0 0), we need to adjust that here
                    884:        VectorScale (self->size, 0.5, size);
                    885:        VectorAdd (self->absmin, size, origin);
                    886:        VectorCopy (origin, self->s.origin);
                    887: 
                    888:        self->takedamage = DAMAGE_NO;
                    889: 
                    890:        if (self->dmg)
                    891:                T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
                    892: 
                    893:        VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
                    894:        VectorNormalize (self->velocity);
                    895:        VectorScale (self->velocity, 150, self->velocity);
                    896: 
                    897:        // start chunks towards the center
                    898:        VectorScale (size, 0.5, size);
                    899: 
                    900:        mass = self->mass;
                    901:        if (!mass)
                    902:                mass = 75;
                    903: 
                    904:        // big chunks
                    905:        if (mass >= 100)
                    906:        {
                    907:                count = mass / 100;
                    908:                if (count > 8)
                    909:                        count = 8;
                    910:                while(count--)
                    911:                {
                    912:                        chunkorigin[0] = origin[0] + crandom() * size[0];
                    913:                        chunkorigin[1] = origin[1] + crandom() * size[1];
                    914:                        chunkorigin[2] = origin[2] + crandom() * size[2];
                    915:                        ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
                    916:                }
                    917:        }
                    918: 
                    919:        // small chunks
                    920:        count = mass / 25;
                    921:        if (count > 16)
                    922:                count = 16;
                    923:        while(count--)
                    924:        {
                    925:                chunkorigin[0] = origin[0] + crandom() * size[0];
                    926:                chunkorigin[1] = origin[1] + crandom() * size[1];
                    927:                chunkorigin[2] = origin[2] + crandom() * size[2];
                    928:                ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
                    929:        }
                    930: 
                    931:        G_UseTargets (self, attacker);
                    932: 
                    933:        if (self->dmg)
                    934:                BecomeExplosion1 (self);
                    935:        else
                    936:                G_FreeEdict (self);
                    937: }
                    938: 
                    939: void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
                    940: {
                    941:        func_explosive_explode (self, self, other, self->health, vec3_origin);
                    942: }
                    943: 
                    944: void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
                    945: {
                    946:        self->solid = SOLID_BSP;
                    947:        self->svflags &= ~SVF_NOCLIENT;
                    948:        self->use = NULL;
                    949:        KillBox (self);
                    950:        gi.linkentity (self);
                    951: }
                    952: 
                    953: void SP_func_explosive (edict_t *self)
                    954: {
                    955:        if (deathmatch->value)
                    956:        {       // auto-remove for deathmatch
                    957:                G_FreeEdict (self);
                    958:                return;
                    959:        }
                    960: 
                    961:        self->movetype = MOVETYPE_PUSH;
                    962: 
                    963:        gi.modelindex ("models/objects/debris1/tris.md2");
                    964:        gi.modelindex ("models/objects/debris2/tris.md2");
                    965: 
                    966:        gi.setmodel (self, self->model);
                    967: 
                    968:        if (self->spawnflags & 1)
                    969:        {
                    970:                self->svflags |= SVF_NOCLIENT;
                    971:                self->solid = SOLID_NOT;
                    972:                self->use = func_explosive_spawn;
                    973:        }
                    974:        else
                    975:        {
                    976:                self->solid = SOLID_BSP;
                    977:                if (self->targetname)
                    978:                        self->use = func_explosive_use;
                    979:        }
                    980: 
                    981:        if (self->spawnflags & 2)
                    982:                self->s.effects |= EF_ANIM_ALL;
                    983:        if (self->spawnflags & 4)
                    984:                self->s.effects |= EF_ANIM_ALLFAST;
                    985: 
                    986:        if (self->use != func_explosive_use)
                    987:        {
                    988:                if (!self->health)
                    989:                        self->health = 100;
                    990:                self->die = func_explosive_explode;
                    991:                self->takedamage = DAMAGE_YES;
                    992:        }
                    993: 
                    994:        gi.linkentity (self);
                    995: }
                    996: 
                    997: 
                    998: /*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
                    999: Large exploding box.  You can override its mass (100),
                   1000: health (80), and dmg (150).
                   1001: */
                   1002: 
                   1003: void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                   1004: 
                   1005: {
                   1006:        float   ratio;
                   1007:        vec3_t  v;
                   1008: 
                   1009:        if ((!other->groundentity) || (other->groundentity == self))
                   1010:                return;
                   1011: 
                   1012:        ratio = (float)other->mass / (float)self->mass;
                   1013:        VectorSubtract (self->s.origin, other->s.origin, v);
                   1014:        M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME);
                   1015: }
                   1016: 
                   1017: void barrel_explode (edict_t *self)
                   1018: {
                   1019:        vec3_t  org;
                   1020:        float   spd;
                   1021:        vec3_t  save;
                   1022: 
                   1023:        T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL);
                   1024: 
                   1025:        VectorCopy (self->s.origin, save);
                   1026:        VectorMA (self->absmin, 0.5, self->size, self->s.origin);
                   1027: 
                   1028:        // a few big chunks
                   1029:        spd = 1.5 * (float)self->dmg / 200.0;
                   1030:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1031:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1032:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1033:        ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
                   1034:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1035:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1036:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1037:        ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
                   1038: 
                   1039:        // bottom corners
                   1040:        spd = 1.75 * (float)self->dmg / 200.0;
                   1041:        VectorCopy (self->absmin, org);
                   1042:        ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
                   1043:        VectorCopy (self->absmin, org);
                   1044:        org[0] += self->size[0];
                   1045:        ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
                   1046:        VectorCopy (self->absmin, org);
                   1047:        org[1] += self->size[1];
                   1048:        ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
                   1049:        VectorCopy (self->absmin, org);
                   1050:        org[0] += self->size[0];
                   1051:        org[1] += self->size[1];
                   1052:        ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
                   1053: 
                   1054:        // a bunch of little chunks
                   1055:        spd = 2 * self->dmg / 200;
                   1056:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1057:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1058:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1059:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1060:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1061:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1062:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1063:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1064:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1065:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1066:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1067:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1068:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1069:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1070:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1071:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1072:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1073:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1074:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1075:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1076:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1077:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1078:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1079:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1080:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1081:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1082:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1083:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1084:        org[0] = self->s.origin[0] + crandom() * self->size[0];
                   1085:        org[1] = self->s.origin[1] + crandom() * self->size[1];
                   1086:        org[2] = self->s.origin[2] + crandom() * self->size[2];
                   1087:        ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
                   1088: 
                   1089:        VectorCopy (save, self->s.origin);
                   1090:        if (self->groundentity)
                   1091:                BecomeExplosion2 (self);
                   1092:        else
                   1093:                BecomeExplosion1 (self);
                   1094: }
                   1095: 
                   1096: void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                   1097: {
                   1098:        self->takedamage = DAMAGE_NO;
                   1099:        self->nextthink = level.time + 2 * FRAMETIME;
                   1100:        self->think = barrel_explode;
                   1101:        self->activator = attacker;
                   1102: }
                   1103: 
                   1104: void SP_misc_explobox (edict_t *self)
                   1105: {
                   1106:        if (deathmatch->value)
                   1107:        {       // auto-remove for deathmatch
                   1108:                G_FreeEdict (self);
                   1109:                return;
                   1110:        }
                   1111: 
                   1112:        gi.modelindex ("models/objects/debris1/tris.md2");
                   1113:        gi.modelindex ("models/objects/debris2/tris.md2");
                   1114:        gi.modelindex ("models/objects/debris3/tris.md2");
                   1115: 
                   1116:        self->solid = SOLID_BBOX;
                   1117:        self->movetype = MOVETYPE_STEP;
                   1118: 
                   1119:        self->model = "models/objects/barrels/tris.md2";
                   1120:        self->s.modelindex = gi.modelindex (self->model);
                   1121:        VectorSet (self->mins, -16, -16, 0);
                   1122:        VectorSet (self->maxs, 16, 16, 40);
                   1123: 
                   1124:        if (!self->mass)
                   1125:                self->mass = 400;
                   1126:        if (!self->health)
                   1127:                self->health = 10;
                   1128:        if (!self->dmg)
                   1129:                self->dmg = 150;
                   1130: 
                   1131:        self->die = barrel_delay;
                   1132:        self->takedamage = DAMAGE_YES;
                   1133:        self->monsterinfo.aiflags = AI_NOSTEP;
                   1134: 
                   1135:        self->touch = barrel_touch;
                   1136: 
                   1137:        self->think = M_droptofloor;
                   1138:        self->nextthink = level.time + 2 * FRAMETIME;
                   1139: 
                   1140:        gi.linkentity (self);
                   1141: }
                   1142: 
                   1143: 
                   1144: //
                   1145: // miscellaneous specialty items
                   1146: //
                   1147: 
                   1148: /*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
                   1149: */
                   1150: 
                   1151: void misc_blackhole_use (edict_t *ent, edict_t *other, edict_t *activator)
                   1152: {
                   1153:        /*
                   1154:        gi.WriteByte (svc_temp_entity);
                   1155:        gi.WriteByte (TE_BOSSTPORT);
                   1156:        gi.WritePosition (ent->s.origin);
                   1157:        gi.multicast (ent->s.origin, MULTICAST_PVS);
                   1158:        */
                   1159:        G_FreeEdict (ent);
                   1160: }
                   1161: 
                   1162: void misc_blackhole_think (edict_t *self)
                   1163: {
                   1164:        if (++self->s.frame < 19)
                   1165:                self->nextthink = level.time + FRAMETIME;
                   1166:        else
                   1167:        {               
                   1168:                self->s.frame = 0;
                   1169:                self->nextthink = level.time + FRAMETIME;
                   1170:        }
                   1171: }
                   1172: 
                   1173: void SP_misc_blackhole (edict_t *ent)
                   1174: {
                   1175:        ent->movetype = MOVETYPE_NONE;
                   1176:        ent->solid = SOLID_NOT;
                   1177:        VectorSet (ent->mins, -64, -64, 0);
                   1178:        VectorSet (ent->maxs, 64, 64, 8);
                   1179:        ent->s.modelindex = gi.modelindex ("models/objects/black/tris.md2");
                   1180:        ent->s.renderfx = RF_TRANSLUCENT;
                   1181:        ent->use = misc_blackhole_use;
                   1182:        ent->think = misc_blackhole_think;
                   1183:        ent->nextthink = level.time + 2 * FRAMETIME;
                   1184:        gi.linkentity (ent);
                   1185: }
                   1186: 
                   1187: /*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
                   1188: */
                   1189: 
                   1190: void misc_eastertank_think (edict_t *self)
                   1191: {
                   1192:        if (++self->s.frame < 293)
                   1193:                self->nextthink = level.time + FRAMETIME;
                   1194:        else
                   1195:        {               
                   1196:                self->s.frame = 254;
                   1197:                self->nextthink = level.time + FRAMETIME;
                   1198:        }
                   1199: }
                   1200: 
                   1201: void SP_misc_eastertank (edict_t *ent)
                   1202: {
                   1203:        ent->movetype = MOVETYPE_NONE;
                   1204:        ent->solid = SOLID_BBOX;
                   1205:        VectorSet (ent->mins, -32, -32, -16);
                   1206:        VectorSet (ent->maxs, 32, 32, 32);
                   1207:        ent->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
                   1208:        ent->s.frame = 254;
                   1209:        ent->think = misc_eastertank_think;
                   1210:        ent->nextthink = level.time + 2 * FRAMETIME;
                   1211:        gi.linkentity (ent);
                   1212: }
                   1213: 
                   1214: /*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
                   1215: */
                   1216: 
                   1217: 
                   1218: void misc_easterchick_think (edict_t *self)
                   1219: {
                   1220:        if (++self->s.frame < 247)
                   1221:                self->nextthink = level.time + FRAMETIME;
                   1222:        else
                   1223:        {               
                   1224:                self->s.frame = 208;
                   1225:                self->nextthink = level.time + FRAMETIME;
                   1226:        }
                   1227: }
                   1228: 
                   1229: void SP_misc_easterchick (edict_t *ent)
                   1230: {
                   1231:        ent->movetype = MOVETYPE_NONE;
                   1232:        ent->solid = SOLID_BBOX;
                   1233:        VectorSet (ent->mins, -32, -32, 0);
                   1234:        VectorSet (ent->maxs, 32, 32, 32);
                   1235:        ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
                   1236:        ent->s.frame = 208;
                   1237:        ent->think = misc_easterchick_think;
                   1238:        ent->nextthink = level.time + 2 * FRAMETIME;
                   1239:        gi.linkentity (ent);
                   1240: }
                   1241: 
                   1242: /*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
                   1243: */
                   1244: 
                   1245: 
                   1246: void misc_easterchick2_think (edict_t *self)
                   1247: {
                   1248:        if (++self->s.frame < 287)
                   1249:                self->nextthink = level.time + FRAMETIME;
                   1250:        else
                   1251:        {               
                   1252:                self->s.frame = 248;
                   1253:                self->nextthink = level.time + FRAMETIME;
                   1254:        }
                   1255: }
                   1256: 
                   1257: void SP_misc_easterchick2 (edict_t *ent)
                   1258: {
                   1259:        ent->movetype = MOVETYPE_NONE;
                   1260:        ent->solid = SOLID_BBOX;
                   1261:        VectorSet (ent->mins, -32, -32, 0);
                   1262:        VectorSet (ent->maxs, 32, 32, 32);
                   1263:        ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
                   1264:        ent->s.frame = 248;
                   1265:        ent->think = misc_easterchick2_think;
                   1266:        ent->nextthink = level.time + 2 * FRAMETIME;
                   1267:        gi.linkentity (ent);
                   1268: }
                   1269: 
                   1270: 
                   1271: /*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
                   1272: Not really a monster, this is the Tank Commander's decapitated body.
                   1273: There should be a item_commander_head that has this as it's target.
                   1274: */
                   1275: 
                   1276: void commander_body_think (edict_t *self)
                   1277: {
                   1278:        if (++self->s.frame < 24)
                   1279:                self->nextthink = level.time + FRAMETIME;
                   1280:        else
                   1281:                self->nextthink = 0;
                   1282: 
                   1283:        if (self->s.frame == 22)
                   1284:                gi.sound (self, CHAN_BODY, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0);
                   1285: }
                   1286: 
                   1287: void commander_body_use (edict_t *self, edict_t *other, edict_t *activator)
                   1288: {
                   1289:        self->think = commander_body_think;
                   1290:        self->nextthink = level.time + FRAMETIME;
                   1291:        gi.sound (self, CHAN_BODY, gi.soundindex ("tank/pain.wav"), 1, ATTN_NORM, 0);
                   1292: }
                   1293: 
                   1294: void commander_body_drop (edict_t *self)
                   1295: {
                   1296:        self->movetype = MOVETYPE_TOSS;
                   1297:        self->s.origin[2] += 2;
                   1298: }
                   1299: 
                   1300: void SP_monster_commander_body (edict_t *self)
                   1301: {
                   1302:        self->movetype = MOVETYPE_NONE;
                   1303:        self->solid = SOLID_BBOX;
                   1304:        self->model = "models/monsters/commandr/tris.md2";
                   1305:        self->s.modelindex = gi.modelindex (self->model);
                   1306:        VectorSet (self->mins, -32, -32, 0);
                   1307:        VectorSet (self->maxs, 32, 32, 48);
                   1308:        self->use = commander_body_use;
                   1309:        self->takedamage = DAMAGE_YES;
                   1310:        self->flags = FL_GODMODE;
                   1311:        self->s.renderfx |= RF_FRAMELERP;
                   1312:        gi.linkentity (self);
                   1313: 
                   1314:        gi.soundindex ("tank/thud.wav");
                   1315:        gi.soundindex ("tank/pain.wav");
                   1316: 
                   1317:        self->think = commander_body_drop;
                   1318:        self->nextthink = level.time + 5 * FRAMETIME;
                   1319: }
                   1320: 
                   1321: 
                   1322: /*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
                   1323: The origin is the bottom of the banner.
                   1324: The banner is 128 tall.
                   1325: */
                   1326: void misc_banner_think (edict_t *ent)
                   1327: {
                   1328:        ent->s.frame = (ent->s.frame + 1) % 16;
                   1329:        ent->nextthink = level.time + FRAMETIME;
                   1330: }
                   1331: 
                   1332: void SP_misc_banner (edict_t *ent)
                   1333: {
                   1334:        ent->movetype = MOVETYPE_NONE;
                   1335:        ent->solid = SOLID_NOT;
                   1336:        ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
                   1337:        ent->s.frame = rand() % 16;
                   1338:        gi.linkentity (ent);
                   1339: 
                   1340:        ent->think = misc_banner_think;
                   1341:        ent->nextthink = level.time + FRAMETIME;
                   1342: }
                   1343: 
                   1344: /*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
                   1345: This is the dead player model. Comes in 6 exciting different poses!
                   1346: */
                   1347: void misc_deadsoldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                   1348: {
                   1349:        int             n;
                   1350: 
                   1351:        if (self->health > -80)
                   1352:                return;
                   1353: 
                   1354:        gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
                   1355:        for (n= 0; n < 4; n++)
                   1356:                ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
                   1357:        ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
                   1358: }
                   1359: 
                   1360: void SP_misc_deadsoldier (edict_t *ent)
                   1361: {
                   1362:        if (deathmatch->value)
                   1363:        {       // auto-remove for deathmatch
                   1364:                G_FreeEdict (ent);
                   1365:                return;
                   1366:        }
                   1367: 
                   1368:        ent->movetype = MOVETYPE_NONE;
                   1369:        ent->solid = SOLID_BBOX;
                   1370:        ent->s.modelindex=gi.modelindex ("models/deadbods/dude/tris.md2");
                   1371: 
                   1372:        // Defaults to frame 0
                   1373:        if (ent->spawnflags & 2)
                   1374:                ent->s.frame = 1;
                   1375:        else if (ent->spawnflags & 4)
                   1376:                ent->s.frame = 2;
                   1377:        else if (ent->spawnflags & 8)
                   1378:                ent->s.frame = 3;
                   1379:        else if (ent->spawnflags & 16)
                   1380:                ent->s.frame = 4;
                   1381:        else if (ent->spawnflags & 32)
                   1382:                ent->s.frame = 5;
                   1383:        else
                   1384:                ent->s.frame = 0;
                   1385: 
                   1386:        VectorSet (ent->mins, -16, -16, 0);
                   1387:        VectorSet (ent->maxs, 16, 16, 16);
                   1388:        ent->deadflag = DEAD_DEAD;
                   1389:        ent->takedamage = DAMAGE_YES;
                   1390:        ent->svflags |= SVF_MONSTER|SVF_DEADMONSTER;
                   1391:        ent->die = misc_deadsoldier_die;
                   1392:        ent->monsterinfo.aiflags |= AI_GOOD_GUY;
                   1393: 
                   1394:        gi.linkentity (ent);
                   1395: }
                   1396: 
                   1397: /*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
                   1398: This is the Viper for the flyby bombing.
                   1399: It is trigger_spawned, so you must have something use it for it to show up.
                   1400: There must be a path for it to follow once it is activated.
                   1401: 
                   1402: "speed"                How fast the Viper should fly
                   1403: */
                   1404: 
                   1405: extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
                   1406: extern void func_train_find (edict_t *self);
                   1407: 
                   1408: void misc_viper_use  (edict_t *self, edict_t *other, edict_t *activator)
                   1409: {
                   1410:        self->svflags &= ~SVF_NOCLIENT;
                   1411:        self->use = train_use;
                   1412:        train_use (self, other, activator);
                   1413: }
                   1414: 
                   1415: void SP_misc_viper (edict_t *ent)
                   1416: {
                   1417:        if (!ent->target)
                   1418:        {
                   1419:                gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin));
                   1420:                G_FreeEdict (ent);
                   1421:                return;
                   1422:        }
                   1423: 
                   1424:        if (!ent->speed)
                   1425:                ent->speed = 300;
                   1426: 
                   1427:        ent->movetype = MOVETYPE_PUSH;
                   1428:        ent->solid = SOLID_NOT;
                   1429:        ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
                   1430:        VectorSet (ent->mins, -16, -16, 0);
                   1431:        VectorSet (ent->maxs, 16, 16, 32);
                   1432: 
                   1433:        ent->think = func_train_find;
                   1434:        ent->nextthink = level.time + FRAMETIME;
                   1435:        ent->use = misc_viper_use;
                   1436:        ent->svflags |= SVF_NOCLIENT;
                   1437:        ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
                   1438: 
                   1439:        gi.linkentity (ent);
                   1440: }
                   1441: 
                   1442: /*QUAKED misc_crashviper (1 .5 0) (-176 -120 -24) (176 120 72) 
                   1443: This is a large viper about to crash
                   1444: */
                   1445: void SP_misc_crashviper (edict_t *ent)
                   1446: {
                   1447:        if (!ent->target)
                   1448:        {
                   1449:                gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin));
                   1450:                G_FreeEdict (ent);
                   1451:                return;
                   1452:        }
                   1453: 
                   1454:        if (!ent->speed)
                   1455:                ent->speed = 300;
                   1456: 
                   1457:        ent->movetype = MOVETYPE_PUSH;
                   1458:        ent->solid = SOLID_NOT;
                   1459:        ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
                   1460:        VectorSet (ent->mins, -16, -16, 0);
                   1461:        VectorSet (ent->maxs, 16, 16, 32);
                   1462: 
                   1463: 
                   1464:        ent->think = func_train_find;
                   1465:        ent->nextthink = level.time + FRAMETIME;
                   1466:        ent->use = misc_viper_use;
                   1467:        ent->svflags |= SVF_NOCLIENT;
                   1468:        ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
                   1469: 
                   1470:        gi.linkentity (ent);
                   1471: }
                   1472: 
                   1473: 
                   1474: /*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72) 
                   1475: This is a large stationary viper as seen in Paul's intro
                   1476: */
                   1477: void SP_misc_bigviper (edict_t *ent)
                   1478: {
                   1479:        ent->movetype = MOVETYPE_NONE;
                   1480:        ent->solid = SOLID_BBOX;
                   1481:        VectorSet (ent->mins, -176, -120, -24);
                   1482:        VectorSet (ent->maxs, 176, 120, 72);
                   1483:        ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
                   1484:        gi.linkentity (ent);
                   1485: }
                   1486: 
                   1487: 
                   1488: /*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
                   1489: "dmg"  how much boom should the bomb make?
                   1490: */
                   1491: void misc_viper_bomb_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                   1492: {
                   1493:        G_UseTargets (self, self->activator);
                   1494: 
                   1495:        self->s.origin[2] = self->absmin[2] + 1;
                   1496:        T_RadiusDamage (self, self, self->dmg, NULL, self->dmg+40, MOD_BOMB);
                   1497:        BecomeExplosion2 (self);
                   1498: }
                   1499: 
                   1500: void misc_viper_bomb_prethink (edict_t *self)
                   1501: {
                   1502:        vec3_t  v;
                   1503:        float   diff;
                   1504: 
                   1505:        self->groundentity = NULL;
                   1506: 
                   1507:        diff = self->timestamp - level.time;
                   1508:        if (diff < -1.0)
                   1509:                diff = -1.0;
                   1510: 
                   1511:        VectorScale (self->moveinfo.dir, 1.0 + diff, v);
                   1512:        v[2] = diff;
                   1513: 
                   1514:        diff = self->s.angles[2];
                   1515:        vectoangles (v, self->s.angles);
                   1516:        self->s.angles[2] = diff + 10;
                   1517: }
                   1518: 
                   1519: void misc_viper_bomb_use (edict_t *self, edict_t *other, edict_t *activator)
                   1520: {
                   1521:        edict_t *viper;
                   1522: 
                   1523:        self->solid = SOLID_BBOX;
                   1524:        self->svflags &= ~SVF_NOCLIENT;
                   1525:        self->s.effects |= EF_ROCKET;
                   1526:        self->use = NULL;
                   1527:        self->movetype = MOVETYPE_TOSS;
                   1528:        self->prethink = misc_viper_bomb_prethink;
                   1529:        self->touch = misc_viper_bomb_touch;
                   1530:        self->activator = activator;
                   1531: 
                   1532:        viper = G_Find (NULL, FOFS(classname), "misc_viper");
                   1533:        VectorScale (viper->moveinfo.dir, viper->moveinfo.speed, self->velocity);
                   1534: 
                   1535:        self->timestamp = level.time;
                   1536:        VectorCopy (viper->moveinfo.dir, self->moveinfo.dir);
                   1537: }
                   1538: 
                   1539: 
                   1540: void SP_misc_viper_bomb (edict_t *self)
                   1541: {
                   1542:        self->movetype = MOVETYPE_NONE;
                   1543:        self->solid = SOLID_NOT;
                   1544:        VectorSet (self->mins, -8, -8, -8);
                   1545:        VectorSet (self->maxs, 8, 8, 8);
                   1546: 
                   1547:        self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2");
                   1548: 
                   1549:        if (!self->dmg)
                   1550:                self->dmg = 1000;
                   1551: 
                   1552:        self->use = misc_viper_bomb_use;
                   1553:        self->svflags |= SVF_NOCLIENT;
                   1554: 
                   1555:        gi.linkentity (self);
                   1556: }
                   1557: 
                   1558: 
                   1559: // RAFAEL
                   1560: /*QUAKED misc_viper_missile (1 0 0) (-8 -8 -8) (8 8 8)
                   1561: "dmg"  how much boom should the bomb make? the default value is 250
                   1562: */
                   1563: 
                   1564: void misc_viper_missile_use (edict_t *self, edict_t *other, edict_t *activator)
                   1565: {
                   1566:        
                   1567:        vec3_t  forward, right, up;
                   1568:        vec3_t  start, dir;
                   1569:        vec3_t  vec;
                   1570:        
                   1571:        AngleVectors (self->s.angles, forward, right, up);
                   1572:        
                   1573:        self->enemy = G_Find (NULL, FOFS(targetname), self->target);
                   1574:        
                   1575:        VectorCopy (self->enemy->s.origin, vec);
                   1576:        vec[2] + 16;
                   1577:        
                   1578:        VectorCopy (self->s.origin, start);
                   1579:        VectorSubtract (vec, start, dir);
                   1580:        VectorNormalize (dir);
                   1581:        
                   1582:        monster_fire_rocket (self, start, dir, self->dmg, 500, MZ2_CHICK_ROCKET_1);
                   1583:        
                   1584:        self->nextthink = level.time + 0.1;
                   1585:        self->think = G_FreeEdict;
                   1586: 
                   1587:        
                   1588: }
                   1589: 
                   1590: 
                   1591: void SP_misc_viper_missile (edict_t *self)
                   1592: {
                   1593:        self->movetype = MOVETYPE_NONE;
                   1594:        self->solid = SOLID_NOT;
                   1595:        VectorSet (self->mins, -8, -8, -8);
                   1596:        VectorSet (self->maxs, 8, 8, 8);
                   1597: 
                   1598:        if (!self->dmg)
                   1599:                self->dmg = 250;
                   1600: 
                   1601:        self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2");
                   1602: 
                   1603:        self->use = misc_viper_missile_use;
                   1604:        self->svflags |= SVF_NOCLIENT;
                   1605: 
                   1606:        gi.linkentity (self);
                   1607: }
                   1608: 
                   1609: 
                   1610: /*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
                   1611: This is a Storgg ship for the flybys.
                   1612: It is trigger_spawned, so you must have something use it for it to show up.
                   1613: There must be a path for it to follow once it is activated.
                   1614: 
                   1615: "speed"                How fast it should fly
                   1616: */
                   1617: 
                   1618: extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
                   1619: extern void func_train_find (edict_t *self);
                   1620: 
                   1621: void misc_strogg_ship_use  (edict_t *self, edict_t *other, edict_t *activator)
                   1622: {
                   1623:        self->svflags &= ~SVF_NOCLIENT;
                   1624:        self->use = train_use;
                   1625:        train_use (self, other, activator);
                   1626: }
                   1627: 
                   1628: void SP_misc_strogg_ship (edict_t *ent)
                   1629: {
                   1630:        if (!ent->target)
                   1631:        {
                   1632:                gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
                   1633:                G_FreeEdict (ent);
                   1634:                return;
                   1635:        }
                   1636: 
                   1637:        if (!ent->speed)
                   1638:                ent->speed = 300;
                   1639: 
                   1640:        ent->movetype = MOVETYPE_PUSH;
                   1641:        ent->solid = SOLID_NOT;
                   1642:        ent->s.modelindex = gi.modelindex ("models/ships/strogg1/tris.md2");
                   1643:        VectorSet (ent->mins, -16, -16, 0);
                   1644:        VectorSet (ent->maxs, 16, 16, 32);
                   1645: 
                   1646:        ent->think = func_train_find;
                   1647:        ent->nextthink = level.time + FRAMETIME;
                   1648:        ent->use = misc_strogg_ship_use;
                   1649:        ent->svflags |= SVF_NOCLIENT;
                   1650:        ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
                   1651: 
                   1652:        gi.linkentity (ent);
                   1653: }
                   1654: 
                   1655: 
                   1656: // RAFAEL 17-APR-98
                   1657: /*QUAKED misc_transport (1 0 0) (-8 -8 -8) (8 8 8) TRIGGER_SPAWN
                   1658: Maxx's transport at end of game
                   1659: */
                   1660: void SP_misc_transport (edict_t *ent)
                   1661: {
                   1662:        
                   1663:        if (!ent->target)
                   1664:        {
                   1665:                gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
                   1666:                G_FreeEdict (ent);
                   1667:                return;
                   1668:        }
                   1669: 
                   1670:        if (!ent->speed)
                   1671:                ent->speed = 300;
                   1672: 
                   1673:        ent->movetype = MOVETYPE_PUSH;
                   1674:        ent->solid = SOLID_NOT;
                   1675:        ent->s.modelindex = gi.modelindex ("models/objects/ship/tris.md2");
                   1676: 
                   1677:        VectorSet (ent->mins, -16, -16, 0);
                   1678:        VectorSet (ent->maxs, 16, 16, 32);
                   1679: 
                   1680:        ent->think = func_train_find;
                   1681:        ent->nextthink = level.time + FRAMETIME;
                   1682:        ent->use = misc_strogg_ship_use;
                   1683:        ent->svflags |= SVF_NOCLIENT;
                   1684:        ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
                   1685: 
                   1686:        if (!(ent->spawnflags & 1))
                   1687:        {
                   1688:                ent->spawnflags |= 1;
                   1689:        }
                   1690:        
                   1691:        gi.linkentity (ent);
                   1692: }
                   1693: // END 17-APR-98
                   1694: 
                   1695: 
                   1696: /*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
                   1697: */
                   1698: void misc_satellite_dish_think (edict_t *self)
                   1699: {
                   1700:        self->s.frame++;
                   1701:        if (self->s.frame < 38)
                   1702:                self->nextthink = level.time + FRAMETIME;
                   1703: }
                   1704: 
                   1705: void misc_satellite_dish_use (edict_t *self, edict_t *other, edict_t *activator)
                   1706: {
                   1707:        self->s.frame = 0;
                   1708:        self->think = misc_satellite_dish_think;
                   1709:        self->nextthink = level.time + FRAMETIME;
                   1710: }
                   1711: 
                   1712: void SP_misc_satellite_dish (edict_t *ent)
                   1713: {
                   1714:        ent->movetype = MOVETYPE_NONE;
                   1715:        ent->solid = SOLID_BBOX;
                   1716:        VectorSet (ent->mins, -64, -64, 0);
                   1717:        VectorSet (ent->maxs, 64, 64, 128);
                   1718:        ent->s.modelindex = gi.modelindex ("models/objects/satellite/tris.md2");
                   1719:        ent->use = misc_satellite_dish_use;
                   1720:        gi.linkentity (ent);
                   1721: }
                   1722: 
                   1723: 
                   1724: /*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
                   1725: */
                   1726: void SP_light_mine1 (edict_t *ent)
                   1727: {
                   1728:        ent->movetype = MOVETYPE_NONE;
                   1729:        ent->solid = SOLID_BBOX;
                   1730:        ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2");
                   1731:        gi.linkentity (ent);
                   1732: }
                   1733: 
                   1734: 
                   1735: /*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
                   1736: */
                   1737: void SP_light_mine2 (edict_t *ent)
                   1738: {
                   1739:        ent->movetype = MOVETYPE_NONE;
                   1740:        ent->solid = SOLID_BBOX;
                   1741:        ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2");
                   1742:        gi.linkentity (ent);
                   1743: }
                   1744: 
                   1745: 
                   1746: /*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
                   1747: Intended for use with the target_spawner
                   1748: */
                   1749: void SP_misc_gib_arm (edict_t *ent)
                   1750: {
                   1751:        gi.setmodel (ent, "models/objects/gibs/arm/tris.md2");
                   1752:        ent->solid = SOLID_NOT;
                   1753:        ent->s.effects |= EF_GIB;
                   1754:        ent->takedamage = DAMAGE_YES;
                   1755:        ent->die = gib_die;
                   1756:        ent->movetype = MOVETYPE_TOSS;
                   1757:        ent->svflags |= SVF_MONSTER;
                   1758:        ent->deadflag = DEAD_DEAD;
                   1759:        ent->avelocity[0] = random()*200;
                   1760:        ent->avelocity[1] = random()*200;
                   1761:        ent->avelocity[2] = random()*200;
                   1762:        ent->think = G_FreeEdict;
                   1763:        ent->nextthink = level.time + 30;
                   1764:        gi.linkentity (ent);
                   1765: }
                   1766: 
                   1767: /*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
                   1768: Intended for use with the target_spawner
                   1769: */
                   1770: void SP_misc_gib_leg (edict_t *ent)
                   1771: {
                   1772:        gi.setmodel (ent, "models/objects/gibs/leg/tris.md2");
                   1773:        ent->solid = SOLID_NOT;
                   1774:        ent->s.effects |= EF_GIB;
                   1775:        ent->takedamage = DAMAGE_YES;
                   1776:        ent->die = gib_die;
                   1777:        ent->movetype = MOVETYPE_TOSS;
                   1778:        ent->svflags |= SVF_MONSTER;
                   1779:        ent->deadflag = DEAD_DEAD;
                   1780:        ent->avelocity[0] = random()*200;
                   1781:        ent->avelocity[1] = random()*200;
                   1782:        ent->avelocity[2] = random()*200;
                   1783:        ent->think = G_FreeEdict;
                   1784:        ent->nextthink = level.time + 30;
                   1785:        gi.linkentity (ent);
                   1786: }
                   1787: 
                   1788: /*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
                   1789: Intended for use with the target_spawner
                   1790: */
                   1791: void SP_misc_gib_head (edict_t *ent)
                   1792: {
                   1793:        gi.setmodel (ent, "models/objects/gibs/head/tris.md2");
                   1794:        ent->solid = SOLID_NOT;
                   1795:        ent->s.effects |= EF_GIB;
                   1796:        ent->takedamage = DAMAGE_YES;
                   1797:        ent->die = gib_die;
                   1798:        ent->movetype = MOVETYPE_TOSS;
                   1799:        ent->svflags |= SVF_MONSTER;
                   1800:        ent->deadflag = DEAD_DEAD;
                   1801:        ent->avelocity[0] = random()*200;
                   1802:        ent->avelocity[1] = random()*200;
                   1803:        ent->avelocity[2] = random()*200;
                   1804:        ent->think = G_FreeEdict;
                   1805:        ent->nextthink = level.time + 30;
                   1806:        gi.linkentity (ent);
                   1807: }
                   1808: 
                   1809: //=====================================================
                   1810: 
                   1811: /*QUAKED target_character (0 0 1) ?
                   1812: used with target_string (must be on same "team")
                   1813: "count" is position in the string (starts at 1)
                   1814: */
                   1815: 
                   1816: void SP_target_character (edict_t *self)
                   1817: {
                   1818:        self->movetype = MOVETYPE_PUSH;
                   1819:        gi.setmodel (self, self->model);
                   1820:        self->solid = SOLID_BSP;
                   1821:        self->s.frame = 12;
                   1822:        gi.linkentity (self);
                   1823:        return;
                   1824: }
                   1825: 
                   1826: 
                   1827: /*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
                   1828: */
                   1829: 
                   1830: void target_string_use (edict_t *self, edict_t *other, edict_t *activator)
                   1831: {
                   1832:        edict_t *e;
                   1833:        int             n, l;
                   1834:        char    c;
                   1835: 
                   1836:        l = strlen(self->message);
                   1837:        for (e = self->teammaster; e; e = e->teamchain)
                   1838:        {
                   1839:                if (!e->count)
                   1840:                        continue;
                   1841:                n = e->count - 1;
                   1842:                if (n > l)
                   1843:                {
                   1844:                        e->s.frame = 12;
                   1845:                        continue;
                   1846:                }
                   1847: 
                   1848:                c = self->message[n];
                   1849:                if (c >= '0' && c <= '9')
                   1850:                        e->s.frame = c - '0';
                   1851:                else if (c == '-')
                   1852:                        e->s.frame = 10;
                   1853:                else if (c == ':')
                   1854:                        e->s.frame = 11;
                   1855:                else
                   1856:                        e->s.frame = 12;
                   1857:        }
                   1858: }
                   1859: 
                   1860: void SP_target_string (edict_t *self)
                   1861: {
                   1862:        if (!self->message)
                   1863:                self->message = "";
                   1864:        self->use = target_string_use;
                   1865: }
                   1866: 
                   1867: 
                   1868: /*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
                   1869: target a target_string with this
                   1870: 
                   1871: The default is to be a time of day clock
                   1872: 
                   1873: TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
                   1874: If START_OFF, this entity must be used before it starts
                   1875: 
                   1876: "style"                0 "xx"
                   1877:                        1 "xx:xx"
                   1878:                        2 "xx:xx:xx"
                   1879: */
                   1880: 
                   1881: #define        CLOCK_MESSAGE_SIZE      16
                   1882: 
                   1883: // don't let field width of any clock messages change, or it
                   1884: // could cause an overwrite after a game load
                   1885: 
                   1886: static void func_clock_reset (edict_t *self)
                   1887: {
                   1888:        self->activator = NULL;
                   1889:        if (self->spawnflags & 1)
                   1890:        {
                   1891:                self->health = 0;
                   1892:                self->wait = self->count;
                   1893:        }
                   1894:        else if (self->spawnflags & 2)
                   1895:        {
                   1896:                self->health = self->count;
                   1897:                self->wait = 0;
                   1898:        }
                   1899: }
                   1900: 
                   1901: static void func_clock_format_countdown (edict_t *self)
                   1902: {
                   1903:        if (self->style == 0)
                   1904:        {
                   1905:                Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
                   1906:                return;
                   1907:        }
                   1908: 
                   1909:        if (self->style == 1)
                   1910:        {
                   1911:                Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
                   1912:                if (self->message[3] == ' ')
                   1913:                        self->message[3] = '0';
                   1914:                return;
                   1915:        }
                   1916: 
                   1917:        if (self->style == 2)
                   1918:        {
                   1919:                Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
                   1920:                if (self->message[3] == ' ')
                   1921:                        self->message[3] = '0';
                   1922:                if (self->message[6] == ' ')
                   1923:                        self->message[6] = '0';
                   1924:                return;
                   1925:        }
                   1926: }
                   1927: 
                   1928: void func_clock_think (edict_t *self)
                   1929: {
                   1930:        if (!self->enemy)
                   1931:        {
                   1932:                self->enemy = G_Find (NULL, FOFS(targetname), self->target);
                   1933:                if (!self->enemy)
                   1934:                        return;
                   1935:        }
                   1936: 
                   1937:        if (self->spawnflags & 1)
                   1938:        {
                   1939:                func_clock_format_countdown (self);
                   1940:                self->health++;
                   1941:        }
                   1942:        else if (self->spawnflags & 2)
                   1943:        {
                   1944:                func_clock_format_countdown (self);
                   1945:                self->health--;
                   1946:        }
                   1947:        else
                   1948:        {
                   1949:                struct tm       *ltime;
                   1950:                time_t          gmtime;
                   1951: 
                   1952:                time(&gmtime);
                   1953:                ltime = localtime(&gmtime);
                   1954:                Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
                   1955:                if (self->message[3] == ' ')
                   1956:                        self->message[3] = '0';
                   1957:                if (self->message[6] == ' ')
                   1958:                        self->message[6] = '0';
                   1959:        }
                   1960: 
                   1961:        self->enemy->message = self->message;
                   1962:        self->enemy->use (self->enemy, self, self);
                   1963: 
                   1964:        if (((self->spawnflags & 1) && (self->health > self->wait)) ||
                   1965:                ((self->spawnflags & 2) && (self->health < self->wait)))
                   1966:        {
                   1967:                if (self->pathtarget)
                   1968:                {
                   1969:                        char *savetarget;
                   1970:                        char *savemessage;
                   1971: 
                   1972:                        savetarget = self->target;
                   1973:                        savemessage = self->message;
                   1974:                        self->target = self->pathtarget;
                   1975:                        self->message = NULL;
                   1976:                        G_UseTargets (self, self->activator);
                   1977:                        self->target = savetarget;
                   1978:                        self->message = savemessage;
                   1979:                }
                   1980: 
                   1981:                if (!(self->spawnflags & 8))
                   1982:                        return;
                   1983: 
                   1984:                func_clock_reset (self);
                   1985: 
                   1986:                if (self->spawnflags & 4)
                   1987:                        return;
                   1988:        }
                   1989: 
                   1990:        self->nextthink = level.time + 1;
                   1991: }
                   1992: 
                   1993: void func_clock_use (edict_t *self, edict_t *other, edict_t *activator)
                   1994: {
                   1995:        if (!(self->spawnflags & 8))
                   1996:                self->use = NULL;
                   1997:        if (self->activator)
                   1998:                return;
                   1999:        self->activator = activator;
                   2000:        self->think (self);
                   2001: }
                   2002: 
                   2003: void SP_func_clock (edict_t *self)
                   2004: {
                   2005:        if (!self->target)
                   2006:        {
                   2007:                gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
                   2008:                G_FreeEdict (self);
                   2009:                return;
                   2010:        }
                   2011: 
                   2012:        if ((self->spawnflags & 2) && (!self->count))
                   2013:        {
                   2014:                gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
                   2015:                G_FreeEdict (self);
                   2016:                return;
                   2017:        }
                   2018: 
                   2019:        if ((self->spawnflags & 1) && (!self->count))
                   2020:                self->count = 60*60;;
                   2021: 
                   2022:        func_clock_reset (self);
                   2023: 
                   2024:        self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL);
                   2025: 
                   2026:        self->think = func_clock_think;
                   2027: 
                   2028:        if (self->spawnflags & 4)
                   2029:                self->use = func_clock_use;
                   2030:        else
                   2031:                self->nextthink = level.time + 1;
                   2032: }
                   2033: 
                   2034: //=================================================================================
                   2035: 
                   2036: void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
                   2037: {
                   2038:        edict_t         *dest;
                   2039:        int                     i;
                   2040: 
                   2041:        if (!other->client)
                   2042:                return;
                   2043:        dest = G_Find (NULL, FOFS(targetname), self->target);
                   2044:        if (!dest)
                   2045:        {
                   2046:                gi.dprintf ("Couldn't find destination\n");
                   2047:                return;
                   2048:        }
                   2049: 
                   2050:        // unlink to make sure it can't possibly interfere with KillBox
                   2051:        gi.unlinkentity (other);
                   2052: 
                   2053:        VectorCopy (dest->s.origin, other->s.origin);
                   2054:        VectorCopy (dest->s.origin, other->s.old_origin);
                   2055:        other->s.origin[2] += 10;
                   2056: 
                   2057:        // clear the velocity and hold them in place briefly
                   2058:        VectorClear (other->velocity);
                   2059:        other->client->ps.pmove.pm_time = 160>>3;               // hold time
                   2060:        other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
                   2061: 
                   2062:        // draw the teleport splash at source and on the player
                   2063:        self->owner->s.event = EV_PLAYER_TELEPORT;
                   2064:        other->s.event = EV_PLAYER_TELEPORT;
                   2065: 
                   2066:        // set angles
                   2067:        for (i=0 ; i<3 ; i++)
                   2068:                other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
                   2069: 
                   2070:        VectorClear (other->s.angles);
                   2071:        VectorClear (other->client->ps.viewangles);
                   2072:        VectorClear (other->client->v_angle);
                   2073: 
                   2074:        // kill anything at the destination
                   2075:        KillBox (other);
                   2076: 
                   2077:        gi.linkentity (other);
                   2078: }
                   2079: 
                   2080: /*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
                   2081: Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
                   2082: */
                   2083: void SP_misc_teleporter (edict_t *ent)
                   2084: {
                   2085:        edict_t         *trig;
                   2086: 
                   2087:        if (!ent->target)
                   2088:        {
                   2089:                gi.dprintf ("teleporter without a target.\n");
                   2090:                G_FreeEdict (ent);
                   2091:                return;
                   2092:        }
                   2093: 
                   2094:        gi.setmodel (ent, "models/objects/dmspot/tris.md2");
                   2095:        ent->s.skinnum = 1;
                   2096:        ent->s.effects = EF_TELEPORTER;
                   2097:        ent->s.sound = gi.soundindex ("world/amb10.wav");
                   2098:        ent->solid = SOLID_BBOX;
                   2099: 
                   2100:        VectorSet (ent->mins, -32, -32, -24);
                   2101:        VectorSet (ent->maxs, 32, 32, -16);
                   2102:        gi.linkentity (ent);
                   2103: 
                   2104:        trig = G_Spawn ();
                   2105:        trig->touch = teleporter_touch;
                   2106:        trig->solid = SOLID_TRIGGER;
                   2107:        trig->target = ent->target;
                   2108:        trig->owner = ent;
                   2109:        VectorCopy (ent->s.origin, trig->s.origin);
                   2110:        VectorSet (trig->mins, -8, -8, 8);
                   2111:        VectorSet (trig->maxs, 8, 8, 24);
                   2112:        gi.linkentity (trig);
                   2113:        
                   2114: }
                   2115: 
                   2116: /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
                   2117: Point teleporters at these.
                   2118: */
                   2119: void SP_misc_teleporter_dest (edict_t *ent)
                   2120: {
                   2121:        gi.setmodel (ent, "models/objects/dmspot/tris.md2");
                   2122:        ent->s.skinnum = 0;
                   2123:        ent->solid = SOLID_BBOX;
                   2124: //     ent->s.effects |= EF_FLIES;
                   2125:        VectorSet (ent->mins, -32, -32, -24);
                   2126:        VectorSet (ent->maxs, 32, 32, -16);
                   2127:        gi.linkentity (ent);
                   2128: }
                   2129: 
                   2130: 
                   2131: /*QUAKED misc_amb4 (1 0 0) (-16 -16 -16) (16 16 16)
                   2132: Mal's amb4 loop entity
                   2133: */
                   2134: static int amb4sound;
                   2135: 
                   2136: void amb4_think (edict_t *ent)
                   2137: {
                   2138:        ent->nextthink = level.time + 2.7;
                   2139:        gi.sound(ent, CHAN_VOICE, amb4sound, 1, ATTN_NONE, 0);
                   2140: }
                   2141: 
                   2142: void SP_misc_amb4 (edict_t *ent)
                   2143: {
                   2144:        ent->think = amb4_think;
                   2145:        ent->nextthink = level.time + 1;
                   2146:        amb4sound = gi.soundindex ("world/amb4.wav");
                   2147:        gi.linkentity (ent);
                   2148: }
                   2149: 
                   2150: /*QUAKED misc_nuke (1 0 0) (-16 -16 -16) (16 16 16)
                   2151: */
                   2152: 
                   2153: void use_nuke (edict_t *self, edict_t *other, edict_t *activator)
                   2154: {
                   2155:        edict_t *from = g_edicts;
                   2156: 
                   2157:        for ( ; from < &g_edicts[globals.num_edicts]; from++)
                   2158:        {
                   2159:                if (from == self)
                   2160:                        continue;
                   2161:                if (from->client)
                   2162:                {
                   2163:                        T_Damage (from, self, self, vec3_origin, from->s.origin, vec3_origin, 100000, 1, 0, MOD_TRAP);
                   2164:                }
                   2165:                else if (from->svflags & SVF_MONSTER)
                   2166:                {
                   2167:                        G_FreeEdict (from);
                   2168:                }
                   2169:        }
                   2170: 
                   2171:        self->use = NULL;
                   2172: }
                   2173: 
                   2174: void SP_misc_nuke (edict_t *ent)
                   2175: {
                   2176:        ent->use = use_nuke;
                   2177: }

unix.superglobalmegacorp.com

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