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

1.1       root        1: // g_turret.c
                      2: 
                      3: #include "g_local.h"
                      4: 
                      5: void SpawnTargetingSystem (edict_t *turret);   // PGM
                      6: 
                      7: void AnglesNormalize(vec3_t vec)
                      8: {
                      9:        while(vec[0] > 360)
                     10:                vec[0] -= 360;
                     11:        while(vec[0] < 0)
                     12:                vec[0] += 360;
                     13:        while(vec[1] > 360)
                     14:                vec[1] -= 360;
                     15:        while(vec[1] < 0)
                     16:                vec[1] += 360;
                     17: }
                     18: 
                     19: float SnapToEights(float x)
                     20: {
                     21:        x *= 8.0;
                     22:        if (x > 0.0)
                     23:                x += 0.5;
                     24:        else
                     25:                x -= 0.5;
                     26:        return 0.125 * (int)x;
                     27: }
                     28: 
                     29: 
                     30: void turret_blocked(edict_t *self, edict_t *other)
                     31: {
                     32:        edict_t *attacker;
                     33: 
                     34:        if (other->takedamage)
                     35:        {
                     36:                if (self->teammaster->owner)
                     37:                        attacker = self->teammaster->owner;
                     38:                else
                     39:                        attacker = self->teammaster;
                     40:                T_Damage (other, self, attacker, vec3_origin, other->s.origin, vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
                     41:        }
                     42: }
                     43: 
                     44: /*QUAKED turret_breach (0 0 0) ?
                     45: This portion of the turret can change both pitch and yaw.
                     46: The model  should be made with a flat pitch.
                     47: It (and the associated base) need to be oriented towards 0.
                     48: Use "angle" to set the starting angle.
                     49: 
                     50: "speed"                default 50
                     51: "dmg"          default 10
                     52: "angle"                point this forward
                     53: "target"       point this at an info_notnull at the muzzle tip
                     54: "minpitch"     min acceptable pitch angle : default -30
                     55: "maxpitch"     max acceptable pitch angle : default 30
                     56: "minyaw"       min acceptable yaw angle   : default 0
                     57: "maxyaw"       max acceptable yaw angle   : default 360
                     58: */
                     59: 
                     60: void turret_breach_fire (edict_t *self)
                     61: {
                     62:        vec3_t  f, r, u;
                     63:        vec3_t  start;
                     64:        int             damage;
                     65:        int             speed;
                     66: 
                     67:        AngleVectors (self->s.angles, f, r, u);
                     68:        VectorMA (self->s.origin, self->move_origin[0], f, start);
                     69:        VectorMA (start, self->move_origin[1], r, start);
                     70:        VectorMA (start, self->move_origin[2], u, start);
                     71: 
                     72:        damage = 100 + random() * 50;
                     73:        speed = 550 + 50 * skill->value;
                     74:        fire_rocket (self->teammaster->owner, start, f, damage, speed, 150, damage);
                     75:        gi.positioned_sound (start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
                     76: }
                     77: 
                     78: void turret_breach_think (edict_t *self)
                     79: {
                     80:        edict_t *ent;
                     81:        vec3_t  current_angles;
                     82:        vec3_t  delta;
                     83: 
                     84:        VectorCopy (self->s.angles, current_angles);
                     85:        AnglesNormalize(current_angles);
                     86: 
                     87:        AnglesNormalize(self->move_angles);
                     88:        if (self->move_angles[PITCH] > 180)
                     89:                self->move_angles[PITCH] -= 360;
                     90: 
                     91:        // clamp angles to mins & maxs
                     92:        if (self->move_angles[PITCH] > self->pos1[PITCH])
                     93:                self->move_angles[PITCH] = self->pos1[PITCH];
                     94:        else if (self->move_angles[PITCH] < self->pos2[PITCH])
                     95:                self->move_angles[PITCH] = self->pos2[PITCH];
                     96: 
                     97:        if ((self->move_angles[YAW] < self->pos1[YAW]) || (self->move_angles[YAW] > self->pos2[YAW]))
                     98:        {
                     99:                float   dmin, dmax;
                    100: 
                    101:                dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
                    102:                if (dmin < -180)
                    103:                        dmin += 360;
                    104:                else if (dmin > 180)
                    105:                        dmin -= 360;
                    106:                dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
                    107:                if (dmax < -180)
                    108:                        dmax += 360;
                    109:                else if (dmax > 180)
                    110:                        dmax -= 360;
                    111:                if (fabs(dmin) < fabs(dmax))
                    112:                        self->move_angles[YAW] = self->pos1[YAW];
                    113:                else
                    114:                        self->move_angles[YAW] = self->pos2[YAW];
                    115:        }
                    116: 
                    117:        VectorSubtract (self->move_angles, current_angles, delta);
                    118:        if (delta[0] < -180)
                    119:                delta[0] += 360;
                    120:        else if (delta[0] > 180)
                    121:                delta[0] -= 360;
                    122:        if (delta[1] < -180)
                    123:                delta[1] += 360;
                    124:        else if (delta[1] > 180)
                    125:                delta[1] -= 360;
                    126:        delta[2] = 0;
                    127: 
                    128:        if (delta[0] > self->speed * FRAMETIME)
                    129:                delta[0] = self->speed * FRAMETIME;
                    130:        if (delta[0] < -1 * self->speed * FRAMETIME)
                    131:                delta[0] = -1 * self->speed * FRAMETIME;
                    132:        if (delta[1] > self->speed * FRAMETIME)
                    133:                delta[1] = self->speed * FRAMETIME;
                    134:        if (delta[1] < -1 * self->speed * FRAMETIME)
                    135:                delta[1] = -1 * self->speed * FRAMETIME;
                    136: 
                    137:        VectorScale (delta, 1.0/FRAMETIME, self->avelocity);
                    138: 
                    139:        self->nextthink = level.time + FRAMETIME;
                    140: 
                    141:        for (ent = self->teammaster; ent; ent = ent->teamchain)
                    142:                ent->avelocity[1] = self->avelocity[1];
                    143: 
                    144:        // if we have adriver, adjust his velocities
                    145:        if (self->owner)
                    146:        {
                    147:                float   angle;
                    148:                float   target_z;
                    149:                float   diff;
                    150:                vec3_t  target;
                    151:                vec3_t  dir;
                    152: 
                    153:                // angular is easy, just copy ours
                    154:                self->owner->avelocity[0] = self->avelocity[0];
                    155:                self->owner->avelocity[1] = self->avelocity[1];
                    156: 
                    157:                // x & y
                    158:                angle = self->s.angles[1] + self->owner->move_origin[1];
                    159:                angle *= (M_PI*2 / 360);
                    160:                target[0] = SnapToEights(self->s.origin[0] + cos(angle) * self->owner->move_origin[0]);
                    161:                target[1] = SnapToEights(self->s.origin[1] + sin(angle) * self->owner->move_origin[0]);
                    162:                target[2] = self->owner->s.origin[2];
                    163: 
                    164:                VectorSubtract (target, self->owner->s.origin, dir);
                    165:                self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
                    166:                self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;
                    167: 
                    168:                // z
                    169:                angle = self->s.angles[PITCH] * (M_PI*2 / 360);
                    170:                target_z = SnapToEights(self->s.origin[2] + self->owner->move_origin[0] * tan(angle) + self->owner->move_origin[2]);
                    171: 
                    172:                diff = target_z - self->owner->s.origin[2];
                    173:                self->owner->velocity[2] = diff * 1.0 / FRAMETIME;
                    174: 
                    175:                if (self->spawnflags & 65536)
                    176:                {
                    177:                        turret_breach_fire (self);
                    178:                        self->spawnflags &= ~65536;
                    179:                }
                    180:        }
                    181: }
                    182: 
                    183: void turret_breach_finish_init (edict_t *self)
                    184: {
                    185:        // get and save info for muzzle location
                    186:        if (!self->target)
                    187:        {
                    188:                gi.dprintf("%s at %s needs a target\n", self->classname, vtos(self->s.origin));
                    189:        }
                    190:        else
                    191:        {
                    192:                self->target_ent = G_PickTarget (self->target);
                    193:                if(self->target_ent)
                    194:                {
                    195:                        VectorSubtract (self->target_ent->s.origin, self->s.origin, self->move_origin);
                    196:                        G_FreeEdict(self->target_ent);
                    197:                }
                    198:                else
                    199:                        gi.dprintf("could not find target entity for %s at %s\n", self->classname, vtos(self->s.origin));
                    200:        }
                    201: 
                    202:        self->teammaster->dmg = self->dmg;
                    203:        self->think = turret_breach_think;
                    204:        self->think (self);
                    205: }
                    206: 
                    207: void SP_turret_breach (edict_t *self)
                    208: {
                    209:        self->solid = SOLID_BSP;
                    210:        self->movetype = MOVETYPE_PUSH;
                    211:        gi.setmodel (self, self->model);
                    212: 
                    213:        if (!self->speed)
                    214:                self->speed = 50;
                    215:        if (!self->dmg)
                    216:                self->dmg = 10;
                    217: 
                    218:        if (!st.minpitch)
                    219:                st.minpitch = -30;
                    220:        if (!st.maxpitch)
                    221:                st.maxpitch = 30;
                    222:        if (!st.maxyaw)
                    223:                st.maxyaw = 360;
                    224: 
                    225:        self->pos1[PITCH] = -1 * st.minpitch;
                    226:        self->pos1[YAW]   = st.minyaw;
                    227:        self->pos2[PITCH] = -1 * st.maxpitch;
                    228:        self->pos2[YAW]   = st.maxyaw;
                    229: 
                    230:        self->ideal_yaw = self->s.angles[YAW];
                    231:        self->move_angles[YAW] = self->ideal_yaw;
                    232: 
                    233:        self->blocked = turret_blocked;
                    234: 
                    235:        self->think = turret_breach_finish_init;
                    236:        self->nextthink = level.time + FRAMETIME;
                    237:        gi.linkentity (self);
                    238: }
                    239: 
                    240: 
                    241: /*QUAKED turret_base (0 0 0) ?
                    242: This portion of the turret changes yaw only.
                    243: MUST be teamed with a turret_breach.
                    244: */
                    245: 
                    246: void SP_turret_base (edict_t *self)
                    247: {
                    248:        self->solid = SOLID_BSP;
                    249:        self->movetype = MOVETYPE_PUSH;
                    250:        gi.setmodel (self, self->model);
                    251:        self->blocked = turret_blocked;
                    252:        gi.linkentity (self);
                    253: }
                    254: 
                    255: 
                    256: /*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
                    257: Must NOT be on the team with the rest of the turret parts.
                    258: Instead it must target the turret_breach.
                    259: */
                    260: 
                    261: void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
                    262: void infantry_stand (edict_t *self);
                    263: void monster_use (edict_t *self, edict_t *other, edict_t *activator);
                    264: 
                    265: void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
                    266: {
                    267:        edict_t *ent;
                    268: 
                    269:        // level the gun
                    270:        self->target_ent->move_angles[0] = 0;
                    271: 
                    272:        // remove the driver from the end of them team chain
                    273:        for (ent = self->target_ent->teammaster; ent->teamchain != self; ent = ent->teamchain)
                    274:                ;
                    275:        ent->teamchain = NULL;
                    276:        self->teammaster = NULL;
                    277:        self->flags &= ~FL_TEAMSLAVE;
                    278: 
                    279:        self->target_ent->owner = NULL;
                    280:        self->target_ent->teammaster->owner = NULL;
                    281: 
                    282:        infantry_die (self, inflictor, attacker, damage);
                    283: }
                    284: 
                    285: qboolean FindTarget (edict_t *self);
                    286: 
                    287: void turret_driver_think (edict_t *self)
                    288: {
                    289:        vec3_t  target;
                    290:        vec3_t  dir;
                    291:        float   reaction_time;
                    292: 
                    293:        self->nextthink = level.time + FRAMETIME;
                    294: 
                    295:        if (self->enemy && (!self->enemy->inuse || self->enemy->health <= 0))
                    296:                self->enemy = NULL;
                    297: 
                    298:        if (!self->enemy)
                    299:        {
                    300:                if (!FindTarget (self))
                    301:                        return;
                    302:                self->monsterinfo.trail_time = level.time;
                    303:                self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
                    304:        }
                    305:        else
                    306:        {
                    307:                if (visible (self, self->enemy))
                    308:                {
                    309:                        if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
                    310:                        {
                    311:                                self->monsterinfo.trail_time = level.time;
                    312:                                self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
                    313:                        }
                    314:                }
                    315:                else
                    316:                {
                    317:                        self->monsterinfo.aiflags |= AI_LOST_SIGHT;
                    318:                        return;
                    319:                }
                    320:        }
                    321: 
                    322:        // let the turret know where we want it to aim
                    323:        VectorCopy (self->enemy->s.origin, target);
                    324:        target[2] += self->enemy->viewheight;
                    325:        VectorSubtract (target, self->target_ent->s.origin, dir);
                    326:        vectoangles (dir, self->target_ent->move_angles);
                    327: 
                    328:        // decide if we should shoot
                    329:        if (level.time < self->monsterinfo.attack_finished)
                    330:                return;
                    331: 
                    332:        reaction_time = (3 - skill->value) * 1.0;
                    333:        if ((level.time - self->monsterinfo.trail_time) < reaction_time)
                    334:                return;
                    335: 
                    336:        self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
                    337:        //FIXME how do we really want to pass this along?
                    338:        self->target_ent->spawnflags |= 65536;
                    339: }
                    340: 
                    341: void turret_driver_link (edict_t *self)
                    342: {
                    343:        vec3_t  vec;
                    344:        edict_t *ent;
                    345: 
                    346:        self->think = turret_driver_think;
                    347:        self->nextthink = level.time + FRAMETIME;
                    348: 
                    349:        self->target_ent = G_PickTarget (self->target);
                    350:        self->target_ent->owner = self;
                    351:        self->target_ent->teammaster->owner = self;
                    352:        VectorCopy (self->target_ent->s.angles, self->s.angles);
                    353: 
                    354:        vec[0] = self->target_ent->s.origin[0] - self->s.origin[0];
                    355:        vec[1] = self->target_ent->s.origin[1] - self->s.origin[1];
                    356:        vec[2] = 0;
                    357:        self->move_origin[0] = VectorLength(vec);
                    358: 
                    359:        VectorSubtract (self->s.origin, self->target_ent->s.origin, vec);
                    360:        vectoangles (vec, vec);
                    361:        AnglesNormalize(vec);
                    362:        self->move_origin[1] = vec[1];
                    363: 
                    364:        self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
                    365: 
                    366:        // add the driver to the end of them team chain
                    367:        for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
                    368:                ;
                    369:        ent->teamchain = self;
                    370:        self->teammaster = self->target_ent->teammaster;
                    371:        self->flags |= FL_TEAMSLAVE;
                    372: }
                    373: 
                    374: void SP_turret_driver (edict_t *self)
                    375: {
                    376:        if (deathmatch->value)
                    377:        {
                    378:                G_FreeEdict (self);
                    379:                return;
                    380:        }
                    381: 
                    382:        self->movetype = MOVETYPE_PUSH;
                    383:        self->solid = SOLID_BBOX;
                    384:        self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
                    385:        VectorSet (self->mins, -16, -16, -24);
                    386:        VectorSet (self->maxs, 16, 16, 32);
                    387: 
                    388:        self->health = 100;
                    389:        self->gib_health = 0;
                    390:        self->mass = 200;
                    391:        self->viewheight = 24;
                    392: 
                    393:        self->die = turret_driver_die;
                    394:        self->monsterinfo.stand = infantry_stand;
                    395: 
                    396:        self->flags |= FL_NO_KNOCKBACK;
                    397: 
                    398:        level.total_monsters++;
                    399: 
                    400:        self->svflags |= SVF_MONSTER;
                    401:        self->s.renderfx |= RF_FRAMELERP;
                    402:        self->takedamage = DAMAGE_AIM;
                    403:        self->use = monster_use;
                    404:        self->clipmask = MASK_MONSTERSOLID;
                    405:        VectorCopy (self->s.origin, self->s.old_origin);
                    406:        self->monsterinfo.aiflags |= AI_STAND_GROUND|AI_DUCKED;
                    407: 
                    408:        if (st.item)
                    409:        {
                    410:                self->item = FindItemByClassname (st.item);
                    411:                if (!self->item)
                    412:                        gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
                    413:        }
                    414: 
                    415:        self->think = turret_driver_link;
                    416:        self->nextthink = level.time + FRAMETIME;
                    417: 
                    418:        gi.linkentity (self);
                    419: }
                    420: 
                    421: //============
                    422: // ROGUE
                    423: 
                    424: // invisible turret drivers so we can have unmanned turrets.
                    425: // originally designed to shoot at func_trains and such, so they
                    426: // fire at the center of the bounding box, rather than the entity's
                    427: // origin.
                    428: 
                    429: void turret_brain_think (edict_t *self)
                    430: {
                    431:        vec3_t  target;
                    432:        vec3_t  dir;
                    433:        vec3_t  endpos;
                    434:        float   reaction_time;
                    435:        trace_t trace;
                    436: 
                    437:        self->nextthink = level.time + FRAMETIME;
                    438: 
                    439:        if (self->enemy)
                    440:        {
                    441:                if(!self->enemy->inuse)
                    442:                        self->enemy = NULL;
                    443:                else if(self->enemy->takedamage && self->enemy->health <= 0)
                    444:                        self->enemy = NULL;
                    445:        }
                    446: 
                    447:        if (!self->enemy)
                    448:        {
                    449:                if (!FindTarget (self))
                    450:                        return;
                    451:                self->monsterinfo.trail_time = level.time;
                    452:                self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
                    453:        }
                    454:        else
                    455:        {
                    456:                VectorAdd (self->enemy->absmax, self->enemy->absmin, endpos);
                    457:                VectorScale (endpos, 0.5, endpos);
                    458: 
                    459:                trace = gi.trace (self->target_ent->s.origin, vec3_origin, vec3_origin, endpos, self->target_ent, MASK_SHOT);
                    460:                if(trace.fraction == 1 || trace.ent == self->enemy)
                    461:                {
                    462:                        if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
                    463:                        {
                    464:                                self->monsterinfo.trail_time = level.time;
                    465:                                self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
                    466:                        }
                    467:                }
                    468:                else
                    469:                {
                    470:                        self->monsterinfo.aiflags |= AI_LOST_SIGHT;
                    471:                        return;
                    472:                }
                    473:        }
                    474: 
                    475:        // let the turret know where we want it to aim
                    476:        VectorCopy (endpos, target);
                    477:        VectorSubtract (target, self->target_ent->s.origin, dir);
                    478:        vectoangles (dir, self->target_ent->move_angles);
                    479: 
                    480:        // decide if we should shoot
                    481:        if (level.time < self->monsterinfo.attack_finished)
                    482:                return;
                    483: 
                    484:        if(self->delay)
                    485:                reaction_time = self->delay;
                    486:        else
                    487:                reaction_time = (3 - skill->value) * 1.0;
                    488:        if ((level.time - self->monsterinfo.trail_time) < reaction_time)
                    489:                return;
                    490: 
                    491:        self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
                    492:        //FIXME how do we really want to pass this along?
                    493:        self->target_ent->spawnflags |= 65536;
                    494: }
                    495: 
                    496: // =================
                    497: // =================
                    498: void turret_brain_link (edict_t *self)
                    499: {
                    500:        vec3_t  vec;
                    501:        edict_t *ent;
                    502: 
                    503:        if (self->killtarget)
                    504:        {
                    505:                self->enemy = G_PickTarget (self->killtarget);
                    506:        }
                    507: 
                    508:        self->think = turret_brain_think;
                    509:        self->nextthink = level.time + FRAMETIME;
                    510: 
                    511:        self->target_ent = G_PickTarget (self->target);
                    512:        self->target_ent->owner = self;
                    513:        self->target_ent->teammaster->owner = self;
                    514:        VectorCopy (self->target_ent->s.angles, self->s.angles);
                    515: 
                    516:        vec[0] = self->target_ent->s.origin[0] - self->s.origin[0];
                    517:        vec[1] = self->target_ent->s.origin[1] - self->s.origin[1];
                    518:        vec[2] = 0;
                    519:        self->move_origin[0] = VectorLength(vec);
                    520: 
                    521:        VectorSubtract (self->s.origin, self->target_ent->s.origin, vec);
                    522:        vectoangles (vec, vec);
                    523:        AnglesNormalize(vec);
                    524:        self->move_origin[1] = vec[1];
                    525: 
                    526:        self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
                    527: 
                    528:        // add the driver to the end of them team chain
                    529:        for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
                    530:                ;
                    531:        ent->teamchain = self;
                    532:        self->teammaster = self->target_ent->teammaster;
                    533:        self->flags |= FL_TEAMSLAVE;
                    534: }
                    535: 
                    536: // =================
                    537: // =================
                    538: void turret_brain_deactivate (edict_t *self, edict_t *other, edict_t *activator)
                    539: {
                    540:        self->think = NULL;
                    541:        self->nextthink = 0;
                    542: }
                    543: 
                    544: // =================
                    545: // =================
                    546: void turret_brain_activate (edict_t *self, edict_t *other, edict_t *activator)
                    547: {
                    548:        if (!self->enemy)
                    549:        {
                    550:                self->enemy = activator;
                    551:        }
                    552: 
                    553:        // wait at least 3 seconds to fire.
                    554:        self->monsterinfo.attack_finished = level.time + 3;
                    555:        self->use = turret_brain_deactivate;
                    556: 
                    557:        self->think = turret_brain_link;
                    558:        self->nextthink = level.time + FRAMETIME;
                    559: }
                    560: 
                    561: /*QUAKED turret_invisible_brain (1 .5 0) (-16 -16 -16) (16 16 16)
                    562: Invisible brain to drive the turret.
                    563: 
                    564: Does not search for targets. If targeted, can only be turned on once
                    565: and then off once. After that they are completely disabled.
                    566: 
                    567: "delay" the delay between firing (default ramps for skill level)
                    568: "Target" the turret breach
                    569: "Killtarget" the item you want it to attack.
                    570: Target the brain if you want it activated later, instead of immediately. It will wait 3 seconds
                    571: before firing to acquire the target.
                    572: */
                    573: void SP_turret_invisible_brain (edict_t *self)
                    574: {
                    575:        if (!self->killtarget)
                    576:        {
                    577:                gi.dprintf("turret_invisible_brain with no killtarget!\n");
                    578:                G_FreeEdict (self);
                    579:                return;
                    580:        }
                    581:        if (!self->target)
                    582:        {
                    583:                gi.dprintf("turret_invisible_brain with no target!\n");
                    584:                G_FreeEdict (self);
                    585:                return;
                    586:        }
                    587: 
                    588:        if (self->targetname)
                    589:        {
                    590:                self->use = turret_brain_activate;
                    591:        }
                    592:        else
                    593:        {
                    594:                self->think = turret_brain_link;
                    595:                self->nextthink = level.time + FRAMETIME;
                    596:        }
                    597: 
                    598:        self->movetype = MOVETYPE_PUSH;
                    599:        gi.linkentity (self);
                    600: }
                    601: 
                    602: // ROGUE
                    603: //============

unix.superglobalmegacorp.com

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