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

unix.superglobalmegacorp.com

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