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

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

unix.superglobalmegacorp.com

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