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

unix.superglobalmegacorp.com

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