Annotation of quake2/game/g_misc.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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