Annotation of quake2/rogue/g_misc.c, revision 1.1

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

unix.superglobalmegacorp.com

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