Annotation of quake2/client/cl_scrn.c, revision 1.1

1.1     ! root        1: // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
        !             2: /*
        !             3:   full screen console
        !             4:   put up loading plaque
        !             5:   blanked background with loading plaque
        !             6:   blanked background with menu
        !             7:   cinematics
        !             8:   full screen image for quit and victory
        !             9:   end of unit intermissions
        !            10:   */
        !            11: #include "client.h"
        !            12: float          scr_con_current;        // aproaches scr_conlines at scr_conspeed
        !            13: float          scr_conlines;           // 0.0 to 1.0 lines of console to display
        !            14: qboolean       scr_initialized;                // ready to draw
        !            15: int                    scr_draw_loading;
        !            16: vrect_t                scr_vrect;              // position of render window on screen
        !            17: cvar_t         *scr_viewsize;
        !            18: cvar_t         *scr_conspeed;
        !            19: cvar_t         *scr_centertime;
        !            20: cvar_t         *scr_showturtle;
        !            21: cvar_t         *scr_showpause;
        !            22: cvar_t         *scr_printspeed;
        !            23: cvar_t         *scr_netgraph;
        !            24: cvar_t         *scr_timegraph;
        !            25: cvar_t         *scr_debuggraph;
        !            26: cvar_t         *scr_graphheight;
        !            27: cvar_t         *scr_graphscale;
        !            28: cvar_t         *scr_graphshift;
        !            29: cvar_t         *scr_drawall;
        !            30: typedef struct
        !            31: {
        !            32:        int             x1, y1, x2, y2;
        !            33: } dirty_t;
        !            34: dirty_t                scr_dirty, scr_old_dirty[2];
        !            35: 
        !            36: char           crosshair_pic[MAX_QPATH];
        !            37: int                    crosshair_width, crosshair_height;
        !            38: void SCR_TimeRefresh_f (void);
        !            39: void SCR_Loading_f (void);
        !            40: /*
        !            41: ===============================================================================
        !            42: BAR GRAPHS
        !            43: ===============================================================================
        !            44: */
        !            45: 
        !            46: /*
        !            47: ==============
        !            48: CL_AddNetgraph
        !            49: 
        !            50: A new packet was just parsed
        !            51: ==============
        !            52: */
        !            53: void CL_AddNetgraph (void)
        !            54: {
        !            55:        int             i;
        !            56:        int             in;
        !            57:        int             ping;
        !            58: 
        !            59:        // if using the debuggraph for something else, don't
        !            60:        // add the net lines
        !            61:        if (scr_debuggraph->value || scr_timegraph->value)
        !            62:                return;
        !            63: 
        !            64:        for (i=0 ; i<cls.netchan.dropped ; i++)
        !            65:                SCR_DebugGraph (30, 0x40);
        !            66: 
        !            67:        for (i=0 ; i<cl.surpressCount ; i++)
        !            68:                SCR_DebugGraph (30, 0xdf);
        !            69: 
        !            70:        // see what the latency was on this packet
        !            71:        in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
        !            72:        ping = cls.realtime - cl.cmd_time[in];
        !            73:        ping /= 30;
        !            74:        if (ping > 30)
        !            75:                ping = 30;
        !            76:        SCR_DebugGraph (ping, 0xd0);
        !            77: }
        !            78: typedef struct
        !            79: {
        !            80:        float   value;
        !            81:        int             color;
        !            82: } graphsamp_t;
        !            83: static int                     current;
        !            84: static graphsamp_t     values[1024];
        !            85: /*
        !            86: ==============
        !            87: SCR_DebugGraph
        !            88: ==============
        !            89: */
        !            90: void SCR_DebugGraph (float value, int color)
        !            91: {
        !            92:        values[current&1023].value = value;
        !            93:        values[current&1023].color = color;
        !            94:        current++;
        !            95: }
        !            96: /*
        !            97: ==============
        !            98: SCR_DrawDebugGraph
        !            99: ==============
        !           100: */
        !           101: void SCR_DrawDebugGraph (void)
        !           102: {
        !           103:        int             a, x, y, w, i, h;
        !           104:        float   v;
        !           105:        int             color;
        !           106:        //
        !           107:        // draw the graph
        !           108:        //
        !           109:        w = scr_vrect.width;
        !           110:        x = scr_vrect.x;
        !           111:        y = scr_vrect.y+scr_vrect.height;
        !           112:        re.DrawFill (x, y-scr_graphheight->value,
        !           113:                w, scr_graphheight->value, 8);
        !           114:        for (a=0 ; a<w ; a++)
        !           115:        {
        !           116:                i = (current-1-a+1024) & 1023;
        !           117:                v = values[i].value;
        !           118:                color = values[i].color;
        !           119:                v = v*scr_graphscale->value + scr_graphshift->value;
        !           120:                
        !           121:                if (v < 0)
        !           122:                        v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
        !           123:                h = (int)v % (int)scr_graphheight->value;
        !           124:                re.DrawFill (x+w-1-a, y - h, 1, h, color);
        !           125:        }
        !           126: }
        !           127: /*
        !           128: ===============================================================================
        !           129: CENTER PRINTING
        !           130: ===============================================================================
        !           131: */
        !           132: char           scr_centerstring[1024];
        !           133: float          scr_centertime_start;   // for slow victory printing
        !           134: float          scr_centertime_off;
        !           135: int                    scr_center_lines;
        !           136: int                    scr_erase_center;
        !           137: /*
        !           138: ==============
        !           139: SCR_CenterPrint
        !           140: Called for important messages that should stay in the center of the screen
        !           141: for a few moments
        !           142: ==============
        !           143: */
        !           144: void SCR_CenterPrint (char *str)
        !           145: {
        !           146:        char    *s;
        !           147:        char    line[64];
        !           148:        int             i, j, l;
        !           149:        strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
        !           150:        scr_centertime_off = scr_centertime->value;
        !           151:        scr_centertime_start = cl.time;
        !           152:        // count the number of lines for centering
        !           153:        scr_center_lines = 1;
        !           154:        s = str;
        !           155:        while (*s)
        !           156:        {
        !           157:                if (*s == '\n')
        !           158:                        scr_center_lines++;
        !           159:                s++;
        !           160:        }
        !           161: 
        !           162:        // echo it to the console
        !           163:        Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
        !           164: 
        !           165:        s = str;
        !           166:        do      
        !           167:        {
        !           168:        // scan the width of the line
        !           169:                for (l=0 ; l<40 ; l++)
        !           170:                        if (s[l] == '\n' || !s[l])
        !           171:                                break;
        !           172:                for (i=0 ; i<(40-l)/2 ; i++)
        !           173:                        line[i] = ' ';
        !           174: 
        !           175:                for (j=0 ; j<l ; j++)
        !           176:                {
        !           177:                        line[i++] = s[j];
        !           178:                }
        !           179: 
        !           180:                line[i] = '\n';
        !           181:                line[i+1] = 0;
        !           182: 
        !           183:                Com_Printf ("%s", line);
        !           184: 
        !           185:                while (*s && *s != '\n')
        !           186:                        s++;
        !           187: 
        !           188:                if (!*s)
        !           189:                        break;
        !           190:                s++;            // skip the \n
        !           191:        } while (1);
        !           192:        Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
        !           193:        Con_ClearNotify ();
        !           194: }
        !           195: void SCR_DrawCenterString (void)
        !           196: {
        !           197:        char    *start;
        !           198:        int             l;
        !           199:        int             j;
        !           200:        int             x, y;
        !           201:        int             remaining;
        !           202: // the finale prints the characters one at a time
        !           203:        remaining = 9999;
        !           204:        scr_erase_center = 0;
        !           205:        start = scr_centerstring;
        !           206:        if (scr_center_lines <= 4)
        !           207:                y = viddef.height*0.35;
        !           208:        else
        !           209:                y = 48;
        !           210:        do      
        !           211:        {
        !           212:        // scan the width of the line
        !           213:                for (l=0 ; l<40 ; l++)
        !           214:                        if (start[l] == '\n' || !start[l])
        !           215:                                break;
        !           216:                x = (viddef.width - l*8)/2;
        !           217:                SCR_AddDirtyPoint (x, y);
        !           218:                for (j=0 ; j<l ; j++, x+=8)
        !           219:                {
        !           220:                        re.DrawChar (x, y, start[j]);   
        !           221:                        if (!remaining--)
        !           222:                                return;
        !           223:                }
        !           224:                SCR_AddDirtyPoint (x, y+8);
        !           225:                        
        !           226:                y += 8;
        !           227:                while (*start && *start != '\n')
        !           228:                        start++;
        !           229:                if (!*start)
        !           230:                        break;
        !           231:                start++;                // skip the \n
        !           232:        } while (1);
        !           233: }
        !           234: void SCR_CheckDrawCenterString (void)
        !           235: {
        !           236:        scr_centertime_off -= cls.frametime;
        !           237:        
        !           238:        if (scr_centertime_off <= 0)
        !           239:                return;
        !           240:        SCR_DrawCenterString ();
        !           241: }
        !           242: //=============================================================================
        !           243: /*
        !           244: =================
        !           245: SCR_CalcVrect
        !           246: Sets scr_vrect, the coordinates of the rendered window
        !           247: =================
        !           248: */
        !           249: static void SCR_CalcVrect (void)
        !           250: {
        !           251:        int             size;
        !           252:        // bound viewsize
        !           253:        if (scr_viewsize->value < 40)
        !           254:                Cvar_Set ("viewsize","40");
        !           255:        if (scr_viewsize->value > 100)
        !           256:                Cvar_Set ("viewsize","100");
        !           257:        size = scr_viewsize->value;
        !           258:        scr_vrect.width = viddef.width*size/100;
        !           259:        scr_vrect.width &= ~7;
        !           260:        scr_vrect.height = viddef.height*size/100;
        !           261:        scr_vrect.height &= ~1;
        !           262:        scr_vrect.x = (viddef.width - scr_vrect.width)/2;
        !           263:        scr_vrect.y = (viddef.height - scr_vrect.height)/2;
        !           264: }
        !           265: /*
        !           266: =================
        !           267: SCR_SizeUp_f
        !           268: Keybinding command
        !           269: =================
        !           270: */
        !           271: void SCR_SizeUp_f (void)
        !           272: {
        !           273:        Cvar_SetValue ("viewsize",scr_viewsize->value+10);
        !           274: }
        !           275: /*
        !           276: =================
        !           277: SCR_SizeDown_f
        !           278: Keybinding command
        !           279: =================
        !           280: */
        !           281: void SCR_SizeDown_f (void)
        !           282: {
        !           283:        Cvar_SetValue ("viewsize",scr_viewsize->value-10);
        !           284: }
        !           285: /*
        !           286: =================
        !           287: SCR_Sky_f
        !           288: Set a specific sky and rotation speed
        !           289: =================
        !           290: */
        !           291: void SCR_Sky_f (void)
        !           292: {
        !           293:        float   rotate;
        !           294:        vec3_t  axis;
        !           295:        if (Cmd_Argc() < 2)
        !           296:        {
        !           297:                Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
        !           298:                return;
        !           299:        }
        !           300:        if (Cmd_Argc() > 2)
        !           301:                rotate = atof(Cmd_Argv(2));
        !           302:        else
        !           303:                rotate = 0;
        !           304:        if (Cmd_Argc() == 6)
        !           305:        {
        !           306:                axis[0] = atof(Cmd_Argv(3));
        !           307:                axis[1] = atof(Cmd_Argv(4));
        !           308:                axis[2] = atof(Cmd_Argv(5));
        !           309:        }
        !           310:        else
        !           311:        {
        !           312:                axis[0] = 0;
        !           313:                axis[1] = 0;
        !           314:                axis[2] = 1;
        !           315:        }
        !           316:        re.SetSky (Cmd_Argv(1), rotate, axis);
        !           317: }
        !           318: //============================================================================
        !           319: /*
        !           320: ==================
        !           321: SCR_Init
        !           322: ==================
        !           323: */
        !           324: void SCR_Init (void)
        !           325: {
        !           326:        scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
        !           327:        scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
        !           328:        scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
        !           329:        scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
        !           330:        scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
        !           331:        scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
        !           332:        scr_netgraph = Cvar_Get ("netgraph", "0", 0);
        !           333:        scr_timegraph = Cvar_Get ("timegraph", "0", 0);
        !           334:        scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
        !           335:        scr_graphheight = Cvar_Get ("graphheight", "32", 0);
        !           336:        scr_graphscale = Cvar_Get ("graphscale", "1", 0);
        !           337:        scr_graphshift = Cvar_Get ("graphshift", "0", 0);
        !           338:        scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
        !           339: //
        !           340: // register our commands
        !           341: //
        !           342:        Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
        !           343:        Cmd_AddCommand ("loading",SCR_Loading_f);
        !           344:        Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
        !           345:        Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
        !           346:        Cmd_AddCommand ("sky",SCR_Sky_f);
        !           347:        scr_initialized = true;
        !           348: }
        !           349: /*
        !           350: ==============
        !           351: SCR_DrawNet
        !           352: ==============
        !           353: */
        !           354: void SCR_DrawNet (void)
        !           355: {
        !           356:        if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged 
        !           357:                < CMD_BACKUP-1)
        !           358:                return;
        !           359:        re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
        !           360: }
        !           361: /*
        !           362: ==============
        !           363: SCR_DrawPause
        !           364: ==============
        !           365: */
        !           366: void SCR_DrawPause (void)
        !           367: {
        !           368:        int             w, h;
        !           369:        if (!scr_showpause->value)              // turn off for screenshots
        !           370:                return;
        !           371:        if (!cl_paused->value)
        !           372:                return;
        !           373:        re.DrawGetPicSize (&w, &h, "pause");
        !           374:        re.DrawPic ((viddef.width-w)/2, viddef.height/2 + 8, "pause");
        !           375: }
        !           376: /*
        !           377: ==============
        !           378: SCR_DrawLoading
        !           379: ==============
        !           380: */
        !           381: void SCR_DrawLoading (void)
        !           382: {
        !           383:        int             w, h;
        !           384:                
        !           385:        if (!scr_draw_loading)
        !           386:                return;
        !           387:        scr_draw_loading = false;
        !           388:        re.DrawGetPicSize (&w, &h, "loading");
        !           389:        re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
        !           390: }
        !           391: //=============================================================================
        !           392: /*
        !           393: ==================
        !           394: SCR_RunConsole
        !           395: Scroll it up or down
        !           396: ==================
        !           397: */
        !           398: void SCR_RunConsole (void)
        !           399: {
        !           400: // decide on the height of the console
        !           401:        if (cls.key_dest == key_console)
        !           402:                scr_conlines = 0.5;             // half screen
        !           403:        else
        !           404:                scr_conlines = 0;                               // none visible
        !           405:        
        !           406:        if (scr_conlines < scr_con_current)
        !           407:        {
        !           408:                scr_con_current -= scr_conspeed->value*cls.frametime;
        !           409:                if (scr_conlines > scr_con_current)
        !           410:                        scr_con_current = scr_conlines;
        !           411:        }
        !           412:        else if (scr_conlines > scr_con_current)
        !           413:        {
        !           414:                scr_con_current += scr_conspeed->value*cls.frametime;
        !           415:                if (scr_conlines < scr_con_current)
        !           416:                        scr_con_current = scr_conlines;
        !           417:        }
        !           418: }
        !           419: /*
        !           420: ==================
        !           421: SCR_DrawConsole
        !           422: ==================
        !           423: */
        !           424: void SCR_DrawConsole (void)
        !           425: {
        !           426:        Con_CheckResize ();
        !           427:        
        !           428:        if (cls.state == ca_disconnected || cls.state == ca_connecting)
        !           429:        {       // forced full screen console
        !           430:                Con_DrawConsole (1.0);
        !           431:                return;
        !           432:        }
        !           433:        if (cls.state != ca_active || !cl.refresh_prepped)
        !           434:        {       // connected, but can't render
        !           435:                Con_DrawConsole (0.5);
        !           436:                re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
        !           437:                return;
        !           438:        }
        !           439:        if (scr_con_current)
        !           440:        {
        !           441:                Con_DrawConsole (scr_con_current);
        !           442:        }
        !           443:        else
        !           444:        {
        !           445:                if (cls.key_dest == key_game || cls.key_dest == key_message)
        !           446:                        Con_DrawNotify ();      // only draw notify in game
        !           447:        }
        !           448: }
        !           449: //=============================================================================
        !           450: /*
        !           451: ================
        !           452: SCR_BeginLoadingPlaque
        !           453: ================
        !           454: */
        !           455: void SCR_BeginLoadingPlaque (void)
        !           456: {
        !           457:        S_StopAllSounds ();
        !           458:        cl.sound_prepped = false;               // don't play ambients
        !           459:        CDAudio_Stop ();
        !           460:        if (cls.disable_screen)
        !           461:                return;
        !           462:        if (developer->value)
        !           463:                return;
        !           464:        if (cls.state == ca_disconnected)
        !           465:                return; // if at console, don't bring up the plaque
        !           466:        if (cls.key_dest == key_console)
        !           467:                return;
        !           468:        if (cl.cinematictime > 0)
        !           469:                scr_draw_loading = 2;   // clear to balack first
        !           470:        else
        !           471:                scr_draw_loading = 1;
        !           472:        SCR_UpdateScreen ();
        !           473:        cls.disable_screen = Sys_Milliseconds ();
        !           474:        cls.disable_servercount = cl.servercount;
        !           475: }
        !           476: /*
        !           477: ================
        !           478: SCR_EndLoadingPlaque
        !           479: ================
        !           480: */
        !           481: void SCR_EndLoadingPlaque (void)
        !           482: {
        !           483:        cls.disable_screen = 0;
        !           484:        Con_ClearNotify ();
        !           485: }
        !           486: /*
        !           487: ================
        !           488: SCR_Loading_f
        !           489: ================
        !           490: */
        !           491: void SCR_Loading_f (void)
        !           492: {
        !           493:        SCR_BeginLoadingPlaque ();
        !           494: }
        !           495: /*
        !           496: ================
        !           497: SCR_TimeRefresh_f
        !           498: ================
        !           499: */
        !           500: int entitycmpfnc( const entity_t *a, const entity_t *b )
        !           501: {
        !           502:        /*
        !           503:        ** all other models are sorted by model then skin
        !           504:        */
        !           505:        if ( a->model == b->model )
        !           506:        {
        !           507:                return ( ( int ) a->skin - ( int ) b->skin );
        !           508:        }
        !           509:        else
        !           510:        {
        !           511:                return ( ( int ) a->model - ( int ) b->model );
        !           512:        }
        !           513: }
        !           514: 
        !           515: void SCR_TimeRefresh_f (void)
        !           516: {
        !           517:        int             i;
        !           518:        int             start, stop;
        !           519:        float   time;
        !           520: 
        !           521:        if ( cls.state != ca_active )
        !           522:                return;
        !           523:        start = Sys_Milliseconds ();
        !           524:        if (Cmd_Argc() == 2)
        !           525:        {       // run without page flipping
        !           526:                re.BeginFrame( 0 );
        !           527:                for (i=0 ; i<128 ; i++)
        !           528:                {
        !           529:                        cl.refdef.viewangles[1] = i/128.0*360.0;
        !           530:                        re.RenderFrame (&cl.refdef);
        !           531:                }
        !           532:                re.EndFrame();
        !           533:        }
        !           534:        else
        !           535:        {
        !           536:                for (i=0 ; i<128 ; i++)
        !           537:                {
        !           538:                        cl.refdef.viewangles[1] = i/128.0*360.0;
        !           539:                        re.BeginFrame( 0 );
        !           540:                        re.RenderFrame (&cl.refdef);
        !           541:                        re.EndFrame();
        !           542:                }
        !           543:        }
        !           544:        stop = Sys_Milliseconds ();
        !           545:        time = (stop-start)/1000.0;
        !           546:        Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
        !           547: }
        !           548: /*
        !           549: =================
        !           550: SCR_AddDirtyPoint
        !           551: =================
        !           552: */
        !           553: void SCR_AddDirtyPoint (int x, int y)
        !           554: {
        !           555:        if (x < scr_dirty.x1)
        !           556:                scr_dirty.x1 = x;
        !           557:        if (x > scr_dirty.x2)
        !           558:                scr_dirty.x2 = x;
        !           559:        if (y < scr_dirty.y1)
        !           560:                scr_dirty.y1 = y;
        !           561:        if (y > scr_dirty.y2)
        !           562:                scr_dirty.y2 = y;
        !           563: }
        !           564: void SCR_DirtyScreen (void)
        !           565: {
        !           566:        SCR_AddDirtyPoint (0, 0);
        !           567:        SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
        !           568: }
        !           569: /*
        !           570: ==============
        !           571: SCR_TileClear
        !           572: Clear any parts of the tiled background that were drawn on last frame
        !           573: ==============
        !           574: */
        !           575: void SCR_TileClear (void)
        !           576: {
        !           577:        int             i;
        !           578:        int             top, bottom, left, right;
        !           579:        dirty_t clear;
        !           580: 
        !           581:        if (scr_drawall->value)
        !           582:                SCR_DirtyScreen ();     // for power vr or broken page flippers...
        !           583:        if (scr_con_current == 1.0)
        !           584:                return;         // full screen console
        !           585:        if (scr_viewsize->value == 100)
        !           586:                return;         // full screen rendering
        !           587:        if (cl.cinematictime > 0)
        !           588:                return;         // full screen cinematic
        !           589:        // erase rect will be the union of the past three frames
        !           590:        // so tripple buffering works properly
        !           591:        clear = scr_dirty;
        !           592:        for (i=0 ; i<2 ; i++)
        !           593:        {
        !           594:                if (scr_old_dirty[i].x1 < clear.x1)
        !           595:                        clear.x1 = scr_old_dirty[i].x1;
        !           596:                if (scr_old_dirty[i].x2 > clear.x2)
        !           597:                        clear.x2 = scr_old_dirty[i].x2;
        !           598:                if (scr_old_dirty[i].y1 < clear.y1)
        !           599:                        clear.y1 = scr_old_dirty[i].y1;
        !           600:                if (scr_old_dirty[i].y2 > clear.y2)
        !           601:                        clear.y2 = scr_old_dirty[i].y2;
        !           602:        }
        !           603:        scr_old_dirty[1] = scr_old_dirty[0];
        !           604:        scr_old_dirty[0] = scr_dirty;
        !           605:        scr_dirty.x1 = 9999;
        !           606:        scr_dirty.x2 = -9999;
        !           607:        scr_dirty.y1 = 9999;
        !           608:        scr_dirty.y2 = -9999;
        !           609:        // don't bother with anything convered by the console)
        !           610:        top = scr_con_current*viddef.height;
        !           611:        if (top >= clear.y1)
        !           612:                clear.y1 = top;
        !           613:        if (clear.y2 <= clear.y1)
        !           614:                return;         // nothing disturbed
        !           615:        top = scr_vrect.y;
        !           616:        bottom = top + scr_vrect.height-1;
        !           617:        left = scr_vrect.x;
        !           618:        right = left + scr_vrect.width-1;
        !           619:        if (clear.y1 < top)
        !           620:        {       // clear above view screen
        !           621:                i = clear.y2 < top-1 ? clear.y2 : top-1;
        !           622:                re.DrawTileClear (clear.x1 , clear.y1,
        !           623:                        clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
        !           624:                clear.y1 = top;
        !           625:        }
        !           626:        if (clear.y2 > bottom)
        !           627:        {       // clear below view screen
        !           628:                i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
        !           629:                re.DrawTileClear (clear.x1, i,
        !           630:                        clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
        !           631:                clear.y2 = bottom;
        !           632:        }
        !           633:        if (clear.x1 < left)
        !           634:        {       // clear left of view screen
        !           635:                i = clear.x2 < left-1 ? clear.x2 : left-1;
        !           636:                re.DrawTileClear (clear.x1, clear.y1,
        !           637:                        i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
        !           638:                clear.x1 = left;
        !           639:        }
        !           640:        if (clear.x2 > right)
        !           641:        {       // clear left of view screen
        !           642:                i = clear.x1 > right+1 ? clear.x1 : right+1;
        !           643:                re.DrawTileClear (i, clear.y1,
        !           644:                        clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
        !           645:                clear.x2 = right;
        !           646:        }
        !           647: }
        !           648: //===============================================================
        !           649: #define STAT_MINUS             10      // num frame for '-' stats digit
        !           650: char           *sb_nums[2][11] = 
        !           651: {
        !           652:        {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
        !           653:        "num_6", "num_7", "num_8", "num_9", "num_minus"},
        !           654:        {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
        !           655:        "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
        !           656: };
        !           657: #define        ICON_WIDTH      24
        !           658: #define        ICON_HEIGHT     24
        !           659: #define        CHAR_WIDTH      16
        !           660: #define        ICON_SPACE      8
        !           661: /*
        !           662: ================
        !           663: SizeHUDString
        !           664: Allow embedded \n in the string
        !           665: ================
        !           666: */
        !           667: void SizeHUDString (char *string, int *w, int *h)
        !           668: {
        !           669:        int             lines, width, current;
        !           670:        lines = 1;
        !           671:        width = 0;
        !           672:        current = 0;
        !           673:        while (*string)
        !           674:        {
        !           675:                if (*string == '\n')
        !           676:                {
        !           677:                        lines++;
        !           678:                        current = 0;
        !           679:                }
        !           680:                else
        !           681:                {
        !           682:                        current++;
        !           683:                        if (current > width)
        !           684:                                width = current;
        !           685:                }
        !           686:                string++;
        !           687:        }
        !           688:        *w = width * 8;
        !           689:        *h = lines * 8;
        !           690: }
        !           691: void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
        !           692: {
        !           693:        int             margin;
        !           694:        char    line[1024];
        !           695:        int             width;
        !           696:        int             i;
        !           697:        margin = x;
        !           698:        while (*string)
        !           699:        {
        !           700:                // scan out one line of text from the string
        !           701:                width = 0;
        !           702:                while (*string && *string != '\n')
        !           703:                        line[width++] = *string++;
        !           704:                line[width] = 0;
        !           705:                if (centerwidth)
        !           706:                        x = margin + (centerwidth - width*8)/2;
        !           707:                else
        !           708:                        x = margin;
        !           709:                for (i=0 ; i<width ; i++)
        !           710:                {
        !           711:                        re.DrawChar (x, y, line[i]^xor);
        !           712:                        x += 8;
        !           713:                }
        !           714:                if (*string)
        !           715:                {
        !           716:                        string++;       // skip the \n
        !           717:                        x = margin;
        !           718:                        y += 8;
        !           719:                }
        !           720:        }
        !           721: }
        !           722: /*
        !           723: ==============
        !           724: SCR_DrawField
        !           725: ==============
        !           726: */
        !           727: void SCR_DrawField (int x, int y, int color, int width, int value)
        !           728: {
        !           729:        char    num[16], *ptr;
        !           730:        int             l;
        !           731:        int             frame;
        !           732:        if (width < 1)
        !           733:                return;
        !           734:        // draw number string
        !           735:        if (width > 5)
        !           736:                width = 5;
        !           737:        SCR_AddDirtyPoint (x, y);
        !           738:        SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
        !           739: 
        !           740:        Com_sprintf (num, sizeof(num), "%i", value);
        !           741:        l = strlen(num);
        !           742:        if (l > width)
        !           743:                l = width;
        !           744:        x += 2 + CHAR_WIDTH*(width - l);
        !           745:        ptr = num;
        !           746:        while (*ptr && l)
        !           747:        {
        !           748:                if (*ptr == '-')
        !           749:                        frame = STAT_MINUS;
        !           750:                else
        !           751:                        frame = *ptr -'0';
        !           752:                re.DrawPic (x,y,sb_nums[color][frame]);
        !           753:                x += CHAR_WIDTH;
        !           754:                ptr++;
        !           755:                l--;
        !           756:        }
        !           757: }
        !           758: /*
        !           759: ===============
        !           760: SCR_TouchPics
        !           761: Allows rendering code to cache all needed sbar graphics
        !           762: ===============
        !           763: */
        !           764: void SCR_TouchPics (void)
        !           765: {
        !           766:        int             i, j;
        !           767:        for (i=0 ; i<2 ; i++)
        !           768:                for (j=0 ; j<11 ; j++)
        !           769:                        re.RegisterPic (sb_nums[i][j]);
        !           770: 
        !           771:        if (crosshair->value)
        !           772:        {
        !           773:                if (crosshair->value > 3 || crosshair->value < 0)
        !           774:                        crosshair->value = 3;
        !           775: 
        !           776:                Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
        !           777:                re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
        !           778:                if (!crosshair_width)
        !           779:                        crosshair_pic[0] = 0;
        !           780:        }
        !           781: }
        !           782: /*
        !           783: ================
        !           784: SCR_ExecuteLayoutString 
        !           785: ================
        !           786: */
        !           787: void SCR_ExecuteLayoutString (char *s)
        !           788: {
        !           789:        int             x, y;
        !           790:        int             value;
        !           791:        char    *token;
        !           792:        int             width;
        !           793:        int             index;
        !           794:        clientinfo_t    *ci;
        !           795:        if (cls.state != ca_active || !cl.refresh_prepped)
        !           796:                return;
        !           797:        if (!s[0])
        !           798:                return;
        !           799:        x = 0;
        !           800:        y = 0;
        !           801:        width = 3;
        !           802:        while (s)
        !           803:        {
        !           804:                token = COM_Parse (&s);
        !           805:                if (!strcmp(token, "xl"))
        !           806:                {
        !           807:                        token = COM_Parse (&s);
        !           808:                        x = atoi(token);
        !           809:                        continue;
        !           810:                }
        !           811:                if (!strcmp(token, "xr"))
        !           812:                {
        !           813:                        token = COM_Parse (&s);
        !           814:                        x = viddef.width + atoi(token);
        !           815:                        continue;
        !           816:                }
        !           817:                if (!strcmp(token, "xv"))
        !           818:                {
        !           819:                        token = COM_Parse (&s);
        !           820:                        x = viddef.width/2 - 160 + atoi(token);
        !           821:                        continue;
        !           822:                }
        !           823:                if (!strcmp(token, "yt"))
        !           824:                {
        !           825:                        token = COM_Parse (&s);
        !           826:                        y = atoi(token);
        !           827:                        continue;
        !           828:                }
        !           829:                if (!strcmp(token, "yb"))
        !           830:                {
        !           831:                        token = COM_Parse (&s);
        !           832:                        y = viddef.height + atoi(token);
        !           833:                        continue;
        !           834:                }
        !           835:                if (!strcmp(token, "yv"))
        !           836:                {
        !           837:                        token = COM_Parse (&s);
        !           838:                        y = viddef.height/2 - 120 + atoi(token);
        !           839:                        continue;
        !           840:                }
        !           841:                if (!strcmp(token, "pic"))
        !           842:                {       // draw a pic from a stat number
        !           843:                        token = COM_Parse (&s);
        !           844:                        value = cl.frame.playerstate.stats[atoi(token)];
        !           845:                        if (value >= MAX_IMAGES)
        !           846:                                Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
        !           847:                        if (cl.configstrings[CS_IMAGES+value])
        !           848:                        {
        !           849:                                SCR_AddDirtyPoint (x, y);
        !           850:                                SCR_AddDirtyPoint (x+23, y+23);
        !           851:                                re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
        !           852:                        }
        !           853:                        continue;
        !           854:                }
        !           855: 
        !           856:                if (!strcmp(token, "client"))
        !           857:                {       // draw a deathmatch client block
        !           858:                        int             score, ping, time;
        !           859: 
        !           860:                        token = COM_Parse (&s);
        !           861:                        x = viddef.width/2 - 160 + atoi(token);
        !           862:                        token = COM_Parse (&s);
        !           863:                        y = viddef.height/2 - 120 + atoi(token);
        !           864:                        SCR_AddDirtyPoint (x, y);
        !           865:                        SCR_AddDirtyPoint (x+159, y+31);
        !           866: 
        !           867:                        token = COM_Parse (&s);
        !           868:                        value = atoi(token);
        !           869:                        if (value >= MAX_CLIENTS || value < 0)
        !           870:                                Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
        !           871:                        ci = &cl.clientinfo[value];
        !           872: 
        !           873:                        token = COM_Parse (&s);
        !           874:                        score = atoi(token);
        !           875: 
        !           876:                        token = COM_Parse (&s);
        !           877:                        ping = atoi(token);
        !           878: 
        !           879:                        token = COM_Parse (&s);
        !           880:                        time = atoi(token);
        !           881: 
        !           882:                        DrawAltString (x+32, y, ci->name);
        !           883:                        DrawString (x+32, y+8,  "Score: ");
        !           884:                        DrawAltString (x+32+7*8, y+8,  va("%i", score));
        !           885:                        DrawString (x+32, y+16, va("Ping:  %i", ping));
        !           886:                        DrawString (x+32, y+24, va("Time:  %i", time));
        !           887: 
        !           888:                        if (!ci->icon)
        !           889:                                ci = &cl.baseclientinfo;
        !           890:                        re.DrawPic (x, y, ci->iconname);
        !           891:                        continue;
        !           892:                }
        !           893: 
        !           894:                if (!strcmp(token, "ctf"))
        !           895:                {       // draw a ctf client block
        !           896:                        int             score, ping;
        !           897:                        char    block[80];
        !           898: 
        !           899:                        token = COM_Parse (&s);
        !           900:                        x = viddef.width/2 - 160 + atoi(token);
        !           901:                        token = COM_Parse (&s);
        !           902:                        y = viddef.height/2 - 120 + atoi(token);
        !           903:                        SCR_AddDirtyPoint (x, y);
        !           904:                        SCR_AddDirtyPoint (x+159, y+31);
        !           905: 
        !           906:                        token = COM_Parse (&s);
        !           907:                        value = atoi(token);
        !           908:                        if (value >= MAX_CLIENTS || value < 0)
        !           909:                                Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
        !           910:                        ci = &cl.clientinfo[value];
        !           911: 
        !           912:                        token = COM_Parse (&s);
        !           913:                        score = atoi(token);
        !           914: 
        !           915:                        token = COM_Parse (&s);
        !           916:                        ping = atoi(token);
        !           917:                        if (ping > 999)
        !           918:                                ping = 999;
        !           919: 
        !           920:                        sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
        !           921: 
        !           922:                        if (value == cl.playernum)
        !           923:                                DrawAltString (x, y, block);
        !           924:                        else
        !           925:                                DrawString (x, y, block);
        !           926:                        continue;
        !           927:                }
        !           928: 
        !           929:                if (!strcmp(token, "picn"))
        !           930:                {       // draw a pic from a name
        !           931:                        token = COM_Parse (&s);
        !           932:                        SCR_AddDirtyPoint (x, y);
        !           933:                        SCR_AddDirtyPoint (x+23, y+23);
        !           934:                        re.DrawPic (x, y, token);
        !           935:                        continue;
        !           936:                }
        !           937:                if (!strcmp(token, "num"))
        !           938:                {       // draw a number
        !           939:                        token = COM_Parse (&s);
        !           940:                        width = atoi(token);
        !           941:                        token = COM_Parse (&s);
        !           942:                        value = cl.frame.playerstate.stats[atoi(token)];
        !           943:                        SCR_DrawField (x, y, 0, width, value);
        !           944:                        continue;
        !           945:                }
        !           946: 
        !           947:                if (!strcmp(token, "hnum"))
        !           948:                {       // health number
        !           949:                        int             color;
        !           950: 
        !           951:                        width = 3;
        !           952:                        value = cl.frame.playerstate.stats[STAT_HEALTH];
        !           953:                        if (value > 25)
        !           954:                                color = 0;      // green
        !           955:                        else if (value > 0)
        !           956:                                color = (cl.frame.serverframe>>2) & 1;          // flash
        !           957:                        else
        !           958:                                color = 1;
        !           959: 
        !           960:                        if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
        !           961:                                re.DrawPic (x, y, "field_3");
        !           962: 
        !           963:                        SCR_DrawField (x, y, color, width, value);
        !           964:                        continue;
        !           965:                }
        !           966: 
        !           967:                if (!strcmp(token, "anum"))
        !           968:                {       // ammo number
        !           969:                        int             color;
        !           970: 
        !           971:                        width = 3;
        !           972:                        value = cl.frame.playerstate.stats[STAT_AMMO];
        !           973:                        if (value > 5)
        !           974:                                color = 0;      // green
        !           975:                        else if (value >= 0)
        !           976:                                color = (cl.frame.serverframe>>2) & 1;          // flash
        !           977:                        else
        !           978:                                continue;       // negative number = don't show
        !           979: 
        !           980:                        if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
        !           981:                                re.DrawPic (x, y, "field_3");
        !           982: 
        !           983:                        SCR_DrawField (x, y, color, width, value);
        !           984:                        continue;
        !           985:                }
        !           986: 
        !           987:                if (!strcmp(token, "rnum"))
        !           988:                {       // armor number
        !           989:                        int             color;
        !           990: 
        !           991:                        width = 3;
        !           992:                        value = cl.frame.playerstate.stats[STAT_ARMOR];
        !           993:                        if (value < 1)
        !           994:                                continue;
        !           995: 
        !           996:                        color = 0;      // green
        !           997: 
        !           998:                        if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
        !           999:                                re.DrawPic (x, y, "field_3");
        !          1000: 
        !          1001:                        SCR_DrawField (x, y, color, width, value);
        !          1002:                        continue;
        !          1003:                }
        !          1004: 
        !          1005: 
        !          1006:                if (!strcmp(token, "stat_string"))
        !          1007:                {
        !          1008:                        token = COM_Parse (&s);
        !          1009:                        index = atoi(token);
        !          1010:                        if (index < 0 || index >= MAX_CONFIGSTRINGS)
        !          1011:                                Com_Error (ERR_DROP, "Bad stat_string index");
        !          1012:                        index = cl.frame.playerstate.stats[index];
        !          1013:                        if (index < 0 || index >= MAX_CONFIGSTRINGS)
        !          1014:                                Com_Error (ERR_DROP, "Bad stat_string index");
        !          1015:                        DrawString (x, y, cl.configstrings[index]);
        !          1016:                        continue;
        !          1017:                }
        !          1018:                if (!strcmp(token, "cstring"))
        !          1019:                {
        !          1020:                        token = COM_Parse (&s);
        !          1021:                        DrawHUDString (token, x, y, 320, 0);
        !          1022:                        continue;
        !          1023:                }
        !          1024:                if (!strcmp(token, "string"))
        !          1025:                {
        !          1026:                        token = COM_Parse (&s);
        !          1027:                        DrawString (x, y, token);
        !          1028:                        continue;
        !          1029:                }
        !          1030: 
        !          1031:                if (!strcmp(token, "cstring2"))
        !          1032:                {
        !          1033:                        token = COM_Parse (&s);
        !          1034:                        DrawHUDString (token, x, y, 320,0x80);
        !          1035:                        continue;
        !          1036:                }
        !          1037: 
        !          1038:                if (!strcmp(token, "string2"))
        !          1039:                {
        !          1040:                        token = COM_Parse (&s);
        !          1041:                        DrawAltString (x, y, token);
        !          1042:                        continue;
        !          1043:                }
        !          1044:                if (!strcmp(token, "if"))
        !          1045:                {       // draw a number
        !          1046:                        token = COM_Parse (&s);
        !          1047:                        value = cl.frame.playerstate.stats[atoi(token)];
        !          1048:                        if (!value)
        !          1049:                        {       // skip to endif
        !          1050:                                while (s && strcmp(token, "endif") )
        !          1051:                                {
        !          1052:                                        token = COM_Parse (&s);
        !          1053:                                }
        !          1054:                        }
        !          1055:                        continue;
        !          1056:                }
        !          1057:        }
        !          1058: }
        !          1059: /*
        !          1060: ================
        !          1061: SCR_DrawStats
        !          1062: The status bar is a small layout program that
        !          1063: is based on the stats array
        !          1064: ================
        !          1065: */
        !          1066: void SCR_DrawStats (void)
        !          1067: {
        !          1068:        SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
        !          1069: }
        !          1070: /*
        !          1071: ================
        !          1072: SCR_DrawLayout
        !          1073: ================
        !          1074: */
        !          1075: #define        STAT_LAYOUTS            13
        !          1076: void SCR_DrawLayout (void)
        !          1077: {
        !          1078:        if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
        !          1079:                return;
        !          1080:        SCR_ExecuteLayoutString (cl.layout);
        !          1081: }
        !          1082: //=======================================================
        !          1083: /*
        !          1084: ==================
        !          1085: SCR_UpdateScreen
        !          1086: This is called every frame, and can also be called explicitly to flush
        !          1087: text to the screen.
        !          1088: ==================
        !          1089: */
        !          1090: void SCR_UpdateScreen (void)
        !          1091: {
        !          1092:        int numframes;
        !          1093:        int i;
        !          1094:        float separation[2] = { 0, 0 };
        !          1095: 
        !          1096:        // if the screen is disabled (loading plaque is up, or vid mode changing)
        !          1097:        // do nothing at all
        !          1098:        if (cls.disable_screen)
        !          1099:        {
        !          1100:                if (Sys_Milliseconds() - cls.disable_screen > 120000)
        !          1101:                {
        !          1102:                        cls.disable_screen = 0;
        !          1103:                        Com_Printf ("Loading plaque timed out.\n");
        !          1104:                }
        !          1105:                return;
        !          1106:        }
        !          1107: 
        !          1108:        if (!scr_initialized || !con.initialized)
        !          1109:                return;                         // not initialized yet
        !          1110: 
        !          1111:        /*
        !          1112:        ** range check cl_camera_separation so we don't inadvertently fry someone's
        !          1113:        ** brain
        !          1114:        */
        !          1115:        if ( cl_stereo_separation->value > 1.0 )
        !          1116:                Cvar_SetValue( "cl_stereo_separation", 1.0 );
        !          1117:        else if ( cl_stereo_separation->value < 0 )
        !          1118:                Cvar_SetValue( "cl_stereo_separation", 0.0 );
        !          1119: 
        !          1120:        if ( cl_stereo->value )
        !          1121:        {
        !          1122:                numframes = 2;
        !          1123:                separation[0] = -cl_stereo_separation->value / 2;
        !          1124:                separation[1] =  cl_stereo_separation->value / 2;
        !          1125:        }               
        !          1126:        else
        !          1127:        {
        !          1128:                separation[0] = 0;
        !          1129:                separation[1] = 0;
        !          1130:                numframes = 1;
        !          1131:        }
        !          1132:        for ( i = 0; i < numframes; i++ )
        !          1133:        {
        !          1134:                re.BeginFrame( separation[i] );
        !          1135:                if (scr_draw_loading == 2)
        !          1136:                {       //  loading plaque over black screen
        !          1137:                        int             w, h;
        !          1138:                        re.CinematicSetPalette(NULL);
        !          1139:                        scr_draw_loading = false;
        !          1140:                        re.DrawGetPicSize (&w, &h, "loading");
        !          1141:                        re.DrawPic ((viddef.width-w)/2, (viddef.height-h)/2, "loading");
        !          1142: //                     re.EndFrame();
        !          1143: //                     return;
        !          1144:                } 
        !          1145:                // if a cinematic is supposed to be running, handle menus
        !          1146:                // and console specially
        !          1147:                else if (cl.cinematictime > 0)
        !          1148:                {
        !          1149:                        if (cls.key_dest == key_menu)
        !          1150:                        {
        !          1151:                                if (cl.cinematicpalette_active)
        !          1152:                                {
        !          1153:                                        re.CinematicSetPalette(NULL);
        !          1154:                                        cl.cinematicpalette_active = false;
        !          1155:                                }
        !          1156:                                M_Draw ();
        !          1157: //                             re.EndFrame();
        !          1158: //                             return;
        !          1159:                        }
        !          1160:                        else if (cls.key_dest == key_console)
        !          1161:                        {
        !          1162:                                if (cl.cinematicpalette_active)
        !          1163:                                {
        !          1164:                                        re.CinematicSetPalette(NULL);
        !          1165:                                        cl.cinematicpalette_active = false;
        !          1166:                                }
        !          1167:                                SCR_DrawConsole ();
        !          1168: //                             re.EndFrame();
        !          1169: //                             return;
        !          1170:                        }
        !          1171:                        else
        !          1172:                        {
        !          1173:                                SCR_DrawCinematic();
        !          1174: //                             re.EndFrame();
        !          1175: //                             return;
        !          1176:                        }
        !          1177:                }
        !          1178:                else 
        !          1179:                {
        !          1180:                        // make sure the game palette is active
        !          1181:                        if (cl.cinematicpalette_active)
        !          1182:                        {
        !          1183:                                re.CinematicSetPalette(NULL);
        !          1184:                                cl.cinematicpalette_active = false;
        !          1185:                        }
        !          1186:                        // do 3D refresh drawing, and then update the screen
        !          1187:                        SCR_CalcVrect ();
        !          1188:                        // clear any dirty part of the background
        !          1189:                        SCR_TileClear ();
        !          1190:                        V_RenderView ( separation[i] );
        !          1191:                        SCR_DrawStats ();
        !          1192:                        if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
        !          1193:                                SCR_DrawLayout ();
        !          1194:                        if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
        !          1195:                                CL_DrawInventory ();
        !          1196: 
        !          1197:                        SCR_DrawNet ();
        !          1198:                        SCR_CheckDrawCenterString ();
        !          1199:                        if (scr_timegraph->value)
        !          1200:                                SCR_DebugGraph (cls.frametime*300, 0);
        !          1201:                        if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
        !          1202:                                SCR_DrawDebugGraph ();
        !          1203:                        SCR_DrawPause ();
        !          1204:                        SCR_DrawConsole ();
        !          1205:                        M_Draw ();
        !          1206:                        SCR_DrawLoading ();
        !          1207:                }
        !          1208:        }
        !          1209:        re.EndFrame();
        !          1210: }

unix.superglobalmegacorp.com

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