Annotation of quake2/xatrix/g_misc.c, revision 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.