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

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

unix.superglobalmegacorp.com

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