Annotation of quake2/client/cl_view.c, revision 1.1.1.4

1.1.1.4 ! root        1: /*
        !             2: Copyright (C) 1997-2001 Id Software, Inc.
        !             3: 
        !             4: This program is free software; you can redistribute it and/or
        !             5: modify it under the terms of the GNU General Public License
        !             6: as published by the Free Software Foundation; either version 2
        !             7: of the License, or (at your option) any later version.
        !             8: 
        !             9: This program is distributed in the hope that it will be useful,
        !            10: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
        !            12: 
        !            13: See the GNU General Public License for more details.
        !            14: 
        !            15: You should have received a copy of the GNU General Public License
        !            16: along with this program; if not, write to the Free Software
        !            17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
        !            18: 
        !            19: */
1.1       root       20: // cl_view.c -- player rendering positioning
1.1.1.2   root       21: 
1.1       root       22: #include "client.h"
1.1.1.2   root       23: 
1.1       root       24: //=============
                     25: //
                     26: // development tools for weapons
                     27: //
                     28: int                    gun_frame;
                     29: struct model_s *gun_model;
1.1.1.2   root       30: 
1.1       root       31: //=============
1.1.1.2   root       32: 
1.1       root       33: cvar_t         *crosshair;
                     34: cvar_t         *cl_testparticles;
                     35: cvar_t         *cl_testentities;
                     36: cvar_t         *cl_testlights;
                     37: cvar_t         *cl_testblend;
1.1.1.2   root       38: 
1.1       root       39: cvar_t         *cl_stats;
1.1.1.2   root       40: 
                     41: 
1.1       root       42: int                    r_numdlights;
                     43: dlight_t       r_dlights[MAX_DLIGHTS];
1.1.1.2   root       44: 
1.1       root       45: int                    r_numentities;
                     46: entity_t       r_entities[MAX_ENTITIES];
1.1.1.2   root       47: 
1.1       root       48: int                    r_numparticles;
                     49: particle_t     r_particles[MAX_PARTICLES];
1.1.1.2   root       50: 
1.1       root       51: lightstyle_t   r_lightstyles[MAX_LIGHTSTYLES];
1.1.1.2   root       52: 
                     53: char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
                     54: int num_cl_weaponmodels;
                     55: 
1.1       root       56: /*
                     57: ====================
                     58: V_ClearScene
1.1.1.2   root       59: 
1.1       root       60: Specifies the model that will be used as the world
                     61: ====================
                     62: */
                     63: void V_ClearScene (void)
                     64: {
                     65:        r_numdlights = 0;
                     66:        r_numentities = 0;
                     67:        r_numparticles = 0;
                     68: }
1.1.1.2   root       69: 
                     70: 
1.1       root       71: /*
                     72: =====================
                     73: V_AddEntity
1.1.1.2   root       74: 
1.1       root       75: =====================
                     76: */
                     77: void V_AddEntity (entity_t *ent)
                     78: {
                     79:        if (r_numentities >= MAX_ENTITIES)
                     80:                return;
                     81:        r_entities[r_numentities++] = *ent;
                     82: }
1.1.1.2   root       83: 
                     84: 
1.1       root       85: /*
                     86: =====================
                     87: V_AddParticle
1.1.1.2   root       88: 
1.1       root       89: =====================
                     90: */
                     91: void V_AddParticle (vec3_t org, int color, float alpha)
                     92: {
                     93:        particle_t      *p;
1.1.1.2   root       94: 
1.1       root       95:        if (r_numparticles >= MAX_PARTICLES)
                     96:                return;
                     97:        p = &r_particles[r_numparticles++];
                     98:        VectorCopy (org, p->origin);
                     99:        p->color = color;
                    100:        p->alpha = alpha;
                    101: }
1.1.1.2   root      102: 
1.1       root      103: /*
                    104: =====================
                    105: V_AddLight
1.1.1.2   root      106: 
1.1       root      107: =====================
                    108: */
                    109: void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
                    110: {
                    111:        dlight_t        *dl;
1.1.1.2   root      112: 
1.1       root      113:        if (r_numdlights >= MAX_DLIGHTS)
                    114:                return;
                    115:        dl = &r_dlights[r_numdlights++];
                    116:        VectorCopy (org, dl->origin);
                    117:        dl->intensity = intensity;
                    118:        dl->color[0] = r;
                    119:        dl->color[1] = g;
                    120:        dl->color[2] = b;
                    121: }
1.1.1.2   root      122: 
                    123: 
1.1       root      124: /*
                    125: =====================
                    126: V_AddLightStyle
1.1.1.2   root      127: 
1.1       root      128: =====================
                    129: */
                    130: void V_AddLightStyle (int style, float r, float g, float b)
                    131: {
                    132:        lightstyle_t    *ls;
1.1.1.2   root      133: 
1.1       root      134:        if (style < 0 || style > MAX_LIGHTSTYLES)
                    135:                Com_Error (ERR_DROP, "Bad light style %i", style);
                    136:        ls = &r_lightstyles[style];
1.1.1.2   root      137: 
1.1       root      138:        ls->white = r+g+b;
                    139:        ls->rgb[0] = r;
                    140:        ls->rgb[1] = g;
                    141:        ls->rgb[2] = b;
                    142: }
1.1.1.2   root      143: 
1.1       root      144: /*
                    145: ================
                    146: V_TestParticles
1.1.1.2   root      147: 
1.1       root      148: If cl_testparticles is set, create 4096 particles in the view
                    149: ================
                    150: */
                    151: void V_TestParticles (void)
                    152: {
                    153:        particle_t      *p;
                    154:        int                     i, j;
                    155:        float           d, r, u;
1.1.1.2   root      156: 
1.1       root      157:        r_numparticles = MAX_PARTICLES;
                    158:        for (i=0 ; i<r_numparticles ; i++)
                    159:        {
                    160:                d = i*0.25;
                    161:                r = 4*((i&7)-3.5);
                    162:                u = 4*(((i>>3)&7)-3.5);
                    163:                p = &r_particles[i];
1.1.1.2   root      164: 
1.1       root      165:                for (j=0 ; j<3 ; j++)
                    166:                        p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
                    167:                        cl.v_right[j]*r + cl.v_up[j]*u;
1.1.1.2   root      168: 
1.1       root      169:                p->color = 8;
                    170:                p->alpha = cl_testparticles->value;
                    171:        }
                    172: }
1.1.1.2   root      173: 
1.1       root      174: /*
                    175: ================
                    176: V_TestEntities
                    177: 
                    178: If cl_testentities is set, create 32 player models
                    179: ================
                    180: */
                    181: void V_TestEntities (void)
                    182: {
                    183:        int                     i, j;
                    184:        float           f, r;
                    185:        entity_t        *ent;
                    186: 
                    187:        r_numentities = 32;
                    188:        memset (r_entities, 0, sizeof(r_entities));
                    189: 
                    190:        for (i=0 ; i<r_numentities ; i++)
                    191:        {
                    192:                ent = &r_entities[i];
                    193: 
                    194:                r = 64 * ( (i%4) - 1.5 );
                    195:                f = 64 * (i/4) + 128;
                    196: 
                    197:                for (j=0 ; j<3 ; j++)
                    198:                        ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
                    199:                        cl.v_right[j]*r;
                    200: 
                    201:                ent->model = cl.baseclientinfo.model;
                    202:                ent->skin = cl.baseclientinfo.skin;
                    203:        }
                    204: }
                    205: 
                    206: /*
                    207: ================
                    208: V_TestLights
                    209: 
                    210: If cl_testlights is set, create 32 lights models
                    211: ================
                    212: */
                    213: void V_TestLights (void)
                    214: {
                    215:        int                     i, j;
                    216:        float           f, r;
                    217:        dlight_t        *dl;
                    218: 
                    219:        r_numdlights = 32;
                    220:        memset (r_dlights, 0, sizeof(r_dlights));
                    221: 
                    222:        for (i=0 ; i<r_numdlights ; i++)
                    223:        {
                    224:                dl = &r_dlights[i];
                    225: 
                    226:                r = 64 * ( (i%4) - 1.5 );
                    227:                f = 64 * (i/4) + 128;
                    228: 
                    229:                for (j=0 ; j<3 ; j++)
                    230:                        dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
                    231:                        cl.v_right[j]*r;
                    232:                dl->color[0] = ((i%6)+1) & 1;
                    233:                dl->color[1] = (((i%6)+1) & 2)>>1;
                    234:                dl->color[2] = (((i%6)+1) & 4)>>2;
                    235:                dl->intensity = 200;
                    236:        }
                    237: }
                    238: 
                    239: //===================================================================
1.1.1.2   root      240: 
1.1       root      241: /*
                    242: =================
                    243: CL_PrepRefresh
1.1.1.2   root      244: 
1.1       root      245: Call before entering a new level, or after changing dlls
                    246: =================
                    247: */
                    248: void CL_PrepRefresh (void)
                    249: {
                    250:        char            mapname[32];
                    251:        int                     i;
                    252:        char            name[MAX_QPATH];
                    253:        float           rotate;
                    254:        vec3_t          axis;
1.1.1.2   root      255: 
1.1       root      256:        if (!cl.configstrings[CS_MODELS+1][0])
                    257:                return;         // no map loaded
1.1.1.2   root      258: 
1.1       root      259:        SCR_AddDirtyPoint (0, 0);
                    260:        SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
1.1.1.2   root      261: 
1.1       root      262:        // let the render dll load the map
                    263:        strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5);    // skip "maps/"
                    264:        mapname[strlen(mapname)-4] = 0;         // cut off ".bsp"
1.1.1.2   root      265: 
1.1       root      266:        // register models, pics, and skins
                    267:        Com_Printf ("Map: %s\r", mapname); 
                    268:        SCR_UpdateScreen ();
                    269:        re.BeginRegistration (mapname);
                    270:        Com_Printf ("                                     \r");
1.1.1.2   root      271: 
1.1       root      272:        // precache status bar pics
                    273:        Com_Printf ("pics\r"); 
                    274:        SCR_UpdateScreen ();
                    275:        SCR_TouchPics ();
                    276:        Com_Printf ("                                     \r");
                    277: 
                    278:        CL_RegisterTEntModels ();
1.1.1.2   root      279: 
                    280:        num_cl_weaponmodels = 1;
                    281:        strcpy(cl_weaponmodels[0], "weapon.md2");
                    282: 
1.1       root      283:        for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
                    284:        {
                    285:                strcpy (name, cl.configstrings[CS_MODELS+i]);
                    286:                name[37] = 0;   // never go beyond one line
                    287:                if (name[0] != '*')
                    288:                        Com_Printf ("%s\r", name); 
                    289:                SCR_UpdateScreen ();
                    290:                Sys_SendKeyEvents ();   // pump message loop
1.1.1.3   root      291:                if (name[0] == '#')
                    292:                {
1.1.1.2   root      293:                        // special player weapon model
1.1.1.3   root      294:                        if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
                    295:                        {
1.1.1.2   root      296:                                strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
                    297:                                        sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
                    298:                                num_cl_weaponmodels++;
                    299:                        }
1.1.1.3   root      300:                } 
                    301:                else
                    302:                {
1.1.1.2   root      303:                        cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
                    304:                        if (name[0] == '*')
                    305:                                cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
                    306:                        else
                    307:                                cl.model_clip[i] = NULL;
                    308:                }
1.1       root      309:                if (name[0] != '*')
                    310:                        Com_Printf ("                                     \r");
                    311:        }
1.1.1.3   root      312: 
1.1       root      313:        Com_Printf ("images\r", i); 
                    314:        SCR_UpdateScreen ();
                    315:        for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
                    316:        {
                    317:                cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
                    318:                Sys_SendKeyEvents ();   // pump message loop
                    319:        }
1.1.1.3   root      320:        
1.1       root      321:        Com_Printf ("                                     \r");
                    322:        for (i=0 ; i<MAX_CLIENTS ; i++)
                    323:        {
                    324:                if (!cl.configstrings[CS_PLAYERSKINS+i][0])
                    325:                        continue;
                    326:                Com_Printf ("client %i\r", i); 
                    327:                SCR_UpdateScreen ();
                    328:                Sys_SendKeyEvents ();   // pump message loop
                    329:                CL_ParseClientinfo (i);
                    330:                Com_Printf ("                                     \r");
                    331:        }
1.1.1.2   root      332: 
1.1       root      333:        CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
1.1.1.2   root      334: 
1.1       root      335:        // set sky textures and speed
                    336:        Com_Printf ("sky\r", i); 
                    337:        SCR_UpdateScreen ();
                    338:        rotate = atof (cl.configstrings[CS_SKYROTATE]);
                    339:        sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f", 
                    340:                &axis[0], &axis[1], &axis[2]);
                    341:        re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
                    342:        Com_Printf ("                                     \r");
1.1.1.2   root      343: 
1.1       root      344:        // the renderer can now free unneeded stuff
                    345:        re.EndRegistration ();
1.1.1.2   root      346: 
1.1       root      347:        // clear any lines of console text
                    348:        Con_ClearNotify ();
1.1.1.2   root      349: 
1.1       root      350:        SCR_UpdateScreen ();
                    351:        cl.refresh_prepped = true;
                    352:        cl.force_refdef = true; // make sure we have a valid refdef
                    353: 
                    354:        // start the cd track
                    355:        CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
                    356: }
1.1.1.2   root      357: 
1.1       root      358: /*
                    359: ====================
                    360: CalcFov
                    361: ====================
                    362: */
                    363: float CalcFov (float fov_x, float width, float height)
                    364: {
                    365:        float   a;
                    366:        float   x;
1.1.1.2   root      367: 
1.1       root      368:        if (fov_x < 1 || fov_x > 179)
                    369:                Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
1.1.1.2   root      370: 
1.1       root      371:        x = width/tan(fov_x/360*M_PI);
1.1.1.2   root      372: 
1.1       root      373:        a = atan (height/x);
1.1.1.2   root      374: 
1.1       root      375:        a = a*360/M_PI;
1.1.1.2   root      376: 
1.1       root      377:        return a;
                    378: }
1.1.1.2   root      379: 
1.1       root      380: //============================================================================
1.1.1.2   root      381: 
1.1       root      382: // gun frame debugging functions
                    383: void V_Gun_Next_f (void)
                    384: {
                    385:        gun_frame++;
                    386:        Com_Printf ("frame %i\n", gun_frame);
                    387: }
1.1.1.2   root      388: 
1.1       root      389: void V_Gun_Prev_f (void)
                    390: {
                    391:        gun_frame--;
                    392:        if (gun_frame < 0)
                    393:                gun_frame = 0;
                    394:        Com_Printf ("frame %i\n", gun_frame);
                    395: }
1.1.1.2   root      396: 
1.1       root      397: void V_Gun_Model_f (void)
                    398: {
                    399:        char    name[MAX_QPATH];
1.1.1.2   root      400: 
1.1       root      401:        if (Cmd_Argc() != 2)
                    402:        {
                    403:                gun_model = NULL;
                    404:                return;
                    405:        }
                    406:        Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
                    407:        gun_model = re.RegisterModel (name);
                    408: }
1.1.1.2   root      409: 
1.1       root      410: //============================================================================
                    411: 
1.1.1.2   root      412: 
1.1       root      413: /*
                    414: =================
                    415: SCR_DrawCrosshair
                    416: =================
                    417: */
                    418: void SCR_DrawCrosshair (void)
                    419: {
                    420:        if (!crosshair->value)
                    421:                return;
                    422: 
                    423:        if (crosshair->modified)
                    424:        {
                    425:                crosshair->modified = false;
                    426:                SCR_TouchPics ();
                    427:        }
                    428: 
                    429:        if (!crosshair_pic[0])
                    430:                return;
                    431: 
                    432:        re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
                    433:        , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
                    434: }
1.1.1.2   root      435: 
1.1       root      436: /*
                    437: ==================
                    438: V_RenderView
1.1.1.2   root      439: 
1.1       root      440: ==================
                    441: */
                    442: void V_RenderView( float stereo_separation )
                    443: {
                    444:        extern int entitycmpfnc( const entity_t *, const entity_t * );
                    445: 
                    446:        if (cls.state != ca_active)
                    447:                return;
1.1.1.2   root      448: 
1.1       root      449:        if (!cl.refresh_prepped)
                    450:                return;                 // still loading
                    451: 
                    452:        if (cl_timedemo->value)
                    453:        {
                    454:                if (!cl.timedemo_start)
                    455:                        cl.timedemo_start = Sys_Milliseconds ();
                    456:                cl.timedemo_frames++;
                    457:        }
                    458: 
                    459:        // an invalid frame will just use the exact previous refdef
                    460:        // we can't use the old frame if the video mode has changed, though...
                    461:        if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
                    462:        {
                    463:                cl.force_refdef = false;
1.1.1.2   root      464: 
1.1       root      465:                V_ClearScene ();
                    466: 
                    467:                // build a refresh entity list and calc cl.sim*
                    468:                // this also calls CL_CalcViewValues which loads
                    469:                // v_forward, etc.
                    470:                CL_AddEntities ();
1.1.1.2   root      471: 
1.1       root      472:                if (cl_testparticles->value)
                    473:                        V_TestParticles ();
                    474:                if (cl_testentities->value)
                    475:                        V_TestEntities ();
                    476:                if (cl_testlights->value)
                    477:                        V_TestLights ();
                    478:                if (cl_testblend->value)
                    479:                {
                    480:                        cl.refdef.blend[0] = 1;
                    481:                        cl.refdef.blend[1] = 0.5;
                    482:                        cl.refdef.blend[2] = 0.25;
                    483:                        cl.refdef.blend[3] = 0.5;
                    484:                }
1.1.1.2   root      485: 
1.1       root      486:                // offset vieworg appropriately if we're doing stereo separation
                    487:                if ( stereo_separation != 0 )
                    488:                {
                    489:                        vec3_t tmp;
                    490: 
                    491:                        VectorScale( cl.v_right, stereo_separation, tmp );
                    492:                        VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
                    493:                }
1.1.1.2   root      494: 
1.1       root      495:                // never let it sit exactly on a node line, because a water plane can
                    496:                // dissapear when viewed with the eye exactly on it.
                    497:                // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
                    498:                cl.refdef.vieworg[0] += 1.0/16;
                    499:                cl.refdef.vieworg[1] += 1.0/16;
                    500:                cl.refdef.vieworg[2] += 1.0/16;
                    501: 
                    502:                cl.refdef.x = scr_vrect.x;
                    503:                cl.refdef.y = scr_vrect.y;
                    504:                cl.refdef.width = scr_vrect.width;
                    505:                cl.refdef.height = scr_vrect.height;
                    506:                cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
                    507:                cl.refdef.time = cl.time*0.001;
1.1.1.2   root      508: 
1.1       root      509:                cl.refdef.areabits = cl.frame.areabits;
                    510: 
                    511:                if (!cl_add_entities->value)
                    512:                        r_numentities = 0;
                    513:                if (!cl_add_particles->value)
                    514:                        r_numparticles = 0;
                    515:                if (!cl_add_lights->value)
                    516:                        r_numdlights = 0;
                    517:                if (!cl_add_blend->value)
                    518:                {
                    519:                        VectorClear (cl.refdef.blend);
                    520:                }
1.1.1.2   root      521: 
1.1       root      522:                cl.refdef.num_entities = r_numentities;
                    523:                cl.refdef.entities = r_entities;
                    524:                cl.refdef.num_particles = r_numparticles;
                    525:                cl.refdef.particles = r_particles;
                    526:                cl.refdef.num_dlights = r_numdlights;
                    527:                cl.refdef.dlights = r_dlights;
                    528:                cl.refdef.lightstyles = r_lightstyles;
1.1.1.2   root      529: 
1.1       root      530:                cl.refdef.rdflags = cl.frame.playerstate.rdflags;
1.1.1.2   root      531: 
1.1       root      532:                // sort entities for better cache locality
                    533:         qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
                    534:        }
1.1.1.2   root      535: 
1.1       root      536:        re.RenderFrame (&cl.refdef);
                    537:        if (cl_stats->value)
                    538:                Com_Printf ("ent:%i  lt:%i  part:%i\n", r_numentities, r_numdlights, r_numparticles);
                    539:        if ( log_stats->value && ( log_stats_file != 0 ) )
                    540:                fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
                    541: 
                    542: 
                    543:        SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
                    544:        SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
                    545:                scr_vrect.y+scr_vrect.height-1);
                    546: 
                    547:        SCR_DrawCrosshair ();
                    548: }
                    549: 
1.1.1.2   root      550: 
1.1       root      551: /*
                    552: =============
                    553: V_Viewpos_f
                    554: =============
                    555: */
                    556: void V_Viewpos_f (void)
                    557: {
                    558:        Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
                    559:                (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2], 
                    560:                (int)cl.refdef.viewangles[YAW]);
                    561: }
1.1.1.2   root      562: 
1.1       root      563: /*
                    564: =============
                    565: V_Init
                    566: =============
                    567: */
                    568: void V_Init (void)
                    569: {
                    570:        Cmd_AddCommand ("gun_next", V_Gun_Next_f);
                    571:        Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
                    572:        Cmd_AddCommand ("gun_model", V_Gun_Model_f);
                    573: 
                    574:        Cmd_AddCommand ("viewpos", V_Viewpos_f);
1.1.1.2   root      575: 
1.1       root      576:        crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
1.1.1.2   root      577: 
1.1       root      578:        cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
                    579:        cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
                    580:        cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
                    581:        cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
                    582: 
                    583:        cl_stats = Cvar_Get ("cl_stats", "0", 0);
                    584: }

unix.superglobalmegacorp.com

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