Annotation of quake2/ctf/g_misc.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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