home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / console.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  12.6 KB  |  694 lines

  1. /*
  2. Copyright (C) 1996-1997 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. */
  20. // console.c
  21.  
  22. #include "quakedef.h"
  23.  
  24. int            con_ormask;
  25. console_t    con_main;
  26. console_t    con_chat;
  27. console_t    *con;            // point to either con_main or con_chat
  28.  
  29. int         con_linewidth;    // characters across screen
  30. int            con_totallines;        // total lines in console scrollback
  31.  
  32. float        con_cursorspeed = 4;
  33.  
  34.  
  35. cvar_t        con_notifytime = {"con_notifytime","3"};        //seconds
  36.  
  37. #define    NUM_CON_TIMES 4
  38. float        con_times[NUM_CON_TIMES];    // realtime time the line was generated
  39.                                 // for transparent notify lines
  40.  
  41. int            con_vislines;
  42. int            con_notifylines;        // scan lines to clear for notify lines
  43.  
  44. qboolean    con_debuglog;
  45.  
  46. #define        MAXCMDLINE    256
  47. extern    char    key_lines[32][MAXCMDLINE];
  48. extern    int        edit_line;
  49. extern    int        key_linepos;
  50.         
  51.  
  52. qboolean    con_initialized;
  53.  
  54.  
  55. void Key_ClearTyping (void)
  56. {
  57.     key_lines[edit_line][1] = 0;    // clear any typing
  58.     key_linepos = 1;
  59. }
  60.  
  61. /*
  62. ================
  63. Con_ToggleConsole_f
  64. ================
  65. */
  66. void Con_ToggleConsole_f (void)
  67. {
  68.     Key_ClearTyping ();
  69.  
  70.     if (key_dest == key_console)
  71.     {
  72.         if (cls.state == ca_active)
  73.             key_dest = key_game;
  74.     }
  75.     else
  76.         key_dest = key_console;
  77.     
  78.     Con_ClearNotify ();
  79. }
  80.  
  81. /*
  82. ================
  83. Con_ToggleChat_f
  84. ================
  85. */
  86. void Con_ToggleChat_f (void)
  87. {
  88.     Key_ClearTyping ();
  89.  
  90.     if (key_dest == key_console)
  91.     {
  92.         if (cls.state == ca_active)
  93.             key_dest = key_game;
  94.     }
  95.     else
  96.         key_dest = key_console;
  97.     
  98.     Con_ClearNotify ();
  99. }
  100.  
  101. /*
  102. ================
  103. Con_Clear_f
  104. ================
  105. */
  106. void Con_Clear_f (void)
  107. {
  108.     Q_memset (con_main.text, ' ', CON_TEXTSIZE);
  109.     Q_memset (con_chat.text, ' ', CON_TEXTSIZE);
  110. }
  111.  
  112.                         
  113. /*
  114. ================
  115. Con_ClearNotify
  116. ================
  117. */
  118. void Con_ClearNotify (void)
  119. {
  120.     int        i;
  121.     
  122.     for (i=0 ; i<NUM_CON_TIMES ; i++)
  123.         con_times[i] = 0;
  124. }
  125.  
  126.                         
  127. /*
  128. ================
  129. Con_MessageMode_f
  130. ================
  131. */
  132. void Con_MessageMode_f (void)
  133. {
  134.     chat_team = false;
  135.     key_dest = key_message;
  136. }
  137.  
  138. /*
  139. ================
  140. Con_MessageMode2_f
  141. ================
  142. */
  143. void Con_MessageMode2_f (void)
  144. {
  145.     chat_team = true;
  146.     key_dest = key_message;
  147. }
  148.  
  149. /*
  150. ================
  151. Con_Resize
  152.  
  153. ================
  154. */
  155. void Con_Resize (console_t *con)
  156. {
  157.     int        i, j, width, oldwidth, oldtotallines, numlines, numchars;
  158.     char    tbuf[CON_TEXTSIZE];
  159.  
  160.     width = (vid.width >> 3) - 2;
  161.  
  162.     if (width == con_linewidth)
  163.         return;
  164.  
  165.     if (width < 1)            // video hasn't been initialized yet
  166.     {
  167.         width = 38;
  168.         con_linewidth = width;
  169.         con_totallines = CON_TEXTSIZE / con_linewidth;
  170.         Q_memset (con->text, ' ', CON_TEXTSIZE);
  171.     }
  172.     else
  173.     {
  174.         oldwidth = con_linewidth;
  175.         con_linewidth = width;
  176.         oldtotallines = con_totallines;
  177.         con_totallines = CON_TEXTSIZE / con_linewidth;
  178.         numlines = oldtotallines;
  179.  
  180.         if (con_totallines < numlines)
  181.             numlines = con_totallines;
  182.  
  183.         numchars = oldwidth;
  184.     
  185.         if (con_linewidth < numchars)
  186.             numchars = con_linewidth;
  187.  
  188.         Q_memcpy (tbuf, con->text, CON_TEXTSIZE);
  189.         Q_memset (con->text, ' ', CON_TEXTSIZE);
  190.  
  191.         for (i=0 ; i<numlines ; i++)
  192.         {
  193.             for (j=0 ; j<numchars ; j++)
  194.             {
  195.                 con->text[(con_totallines - 1 - i) * con_linewidth + j] =
  196.                         tbuf[((con->current - i + oldtotallines) %
  197.                               oldtotallines) * oldwidth + j];
  198.             }
  199.         }
  200.  
  201.         Con_ClearNotify ();
  202.     }
  203.  
  204.     con->current = con_totallines - 1;
  205.     con->display = con->current;
  206. }
  207.  
  208.                     
  209. /*
  210. ================
  211. Con_CheckResize
  212.  
  213. If the line width has changed, reformat the buffer.
  214. ================
  215. */
  216. void Con_CheckResize (void)
  217. {
  218.     Con_Resize (&con_main);
  219.     Con_Resize (&con_chat);
  220. }
  221.  
  222.  
  223. /*
  224. ================
  225. Con_Init
  226. ================
  227. */
  228. void Con_Init (void)
  229. {
  230.     con_debuglog = COM_CheckParm("-condebug");
  231.  
  232.     con = &con_main;
  233.     con_linewidth = -1;
  234.     Con_CheckResize ();
  235.     
  236.     Con_Printf ("Console initialized.\n");
  237.  
  238. //
  239. // register our commands
  240. //
  241.     Cvar_RegisterVariable (&con_notifytime);
  242.  
  243.     Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
  244.     Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
  245.     Cmd_AddCommand ("messagemode", Con_MessageMode_f);
  246.     Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
  247.     Cmd_AddCommand ("clear", Con_Clear_f);
  248.     con_initialized = true;
  249. }
  250.  
  251.  
  252. /*
  253. ===============
  254. Con_Linefeed
  255. ===============
  256. */
  257. void Con_Linefeed (void)
  258. {
  259.     con->x = 0;
  260.     if (con->display == con->current)
  261.         con->display++;
  262.     con->current++;
  263.     Q_memset (&con->text[(con->current%con_totallines)*con_linewidth]
  264.     , ' ', con_linewidth);
  265. }
  266.  
  267. /*
  268. ================
  269. Con_Print
  270.  
  271. Handles cursor positioning, line wrapping, etc
  272. All console printing must go through this in order to be logged to disk
  273. If no console is visible, the notify window will pop up.
  274. ================
  275. */
  276. void Con_Print (char *txt)
  277. {
  278.     int        y;
  279.     int        c, l;
  280.     static int    cr;
  281.     int        mask;
  282.  
  283.     if (txt[0] == 1 || txt[0] == 2)
  284.     {
  285.         mask = 128;        // go to colored text
  286.         txt++;
  287.     }
  288.     else
  289.         mask = 0;
  290.  
  291.  
  292.     while ( (c = *txt) )
  293.     {
  294.     // count word length
  295.         for (l=0 ; l< con_linewidth ; l++)
  296.             if ( txt[l] <= ' ')
  297.                 break;
  298.  
  299.     // word wrap
  300.         if (l != con_linewidth && (con->x + l > con_linewidth) )
  301.             con->x = 0;
  302.  
  303.         txt++;
  304.  
  305.         if (cr)
  306.         {
  307.             con->current--;
  308.             cr = false;
  309.         }
  310.  
  311.         
  312.         if (!con->x)
  313.         {
  314.             Con_Linefeed ();
  315.         // mark time for transparent overlay
  316.             if (con->current >= 0)
  317.                 con_times[con->current % NUM_CON_TIMES] = realtime;
  318.         }
  319.  
  320.         switch (c)
  321.         {
  322.         case '\n':
  323.             con->x = 0;
  324.             break;
  325.  
  326.         case '\r':
  327.             con->x = 0;
  328.             cr = 1;
  329.             break;
  330.  
  331.         default:    // display character and advance
  332.             y = con->current % con_totallines;
  333.             con->text[y*con_linewidth+con->x] = c | mask | con_ormask;
  334.             con->x++;
  335.             if (con->x >= con_linewidth)
  336.                 con->x = 0;
  337.             break;
  338.         }
  339.         
  340.     }
  341. }
  342.  
  343.  
  344. /*
  345. ================
  346. Con_Printf
  347.  
  348. Handles cursor positioning, line wrapping, etc
  349. ================
  350. */
  351. #define    MAXPRINTMSG    4096
  352. // FIXME: make a buffer size safe vsprintf?
  353. void Con_Printf (char *fmt, ...)
  354. {
  355.     va_list        argptr;
  356.     char        msg[MAXPRINTMSG];
  357.     static qboolean    inupdate;
  358.     
  359.     va_start (argptr,fmt);
  360.     vsprintf (msg,fmt,argptr);
  361.     va_end (argptr);
  362.     
  363. // also echo to debugging console
  364.     Sys_Printf ("%s", msg);    // also echo to debugging console
  365.  
  366. // log all messages to file
  367.     if (con_debuglog)
  368.         Sys_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
  369.         
  370.     if (!con_initialized)
  371.         return;
  372.         
  373. // write it to the scrollable buffer
  374.     Con_Print (msg);
  375.     
  376. // update the screen immediately if the console is displayed
  377.     if (cls.state != ca_active)
  378.     {
  379.     // protect against infinite loop if something in SCR_UpdateScreen calls
  380.     // Con_Printd
  381.         if (!inupdate)
  382.         {
  383.             inupdate = true;
  384.             SCR_UpdateScreen ();
  385.             inupdate = false;
  386.         }
  387.     }
  388. }
  389.  
  390. /*
  391. ================
  392. Con_DPrintf
  393.  
  394. A Con_Printf that only shows up if the "developer" cvar is set
  395. ================
  396. */
  397. void Con_DPrintf (char *fmt, ...)
  398. {
  399.     va_list        argptr;
  400.     char        msg[MAXPRINTMSG];
  401.         
  402.     if (!developer.value)
  403.         return;            // don't confuse non-developers with techie stuff...
  404.  
  405.     va_start (argptr,fmt);
  406.     vsprintf (msg,fmt,argptr);
  407.     va_end (argptr);
  408.     
  409.     Con_Printf ("%s", msg);
  410. }
  411.  
  412. /*
  413. ==============================================================================
  414.  
  415. DRAWING
  416.  
  417. ==============================================================================
  418. */
  419.  
  420.  
  421. /*
  422. ================
  423. Con_DrawInput
  424.  
  425. The input line scrolls horizontally if typing goes beyond the right edge
  426. ================
  427. */
  428. void Con_DrawInput (void)
  429. {
  430.     int        y;
  431.     int        i;
  432.     char    *text;
  433.  
  434.     if (key_dest != key_console && cls.state == ca_active)
  435.         return;        // don't draw anything (allways draw if not active)
  436.  
  437.     text = key_lines[edit_line];
  438.     
  439. // add the cursor frame
  440.     text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
  441.     
  442. // fill out remainder with spaces
  443.     for (i=key_linepos+1 ; i< con_linewidth ; i++)
  444.         text[i] = ' ';
  445.         
  446. //    prestep if horizontally scrolling
  447.     if (key_linepos >= con_linewidth)
  448.         text += 1 + key_linepos - con_linewidth;
  449.         
  450. // draw it
  451.     y = con_vislines-22;
  452.  
  453.     for (i=0 ; i<con_linewidth ; i++)
  454.         Draw_Character ( (i+1)<<3, con_vislines - 22, text[i]);
  455.  
  456. // remove cursor
  457.     key_lines[edit_line][key_linepos] = 0;
  458. }
  459.  
  460.  
  461. /*
  462. ================
  463. Con_DrawNotify
  464.  
  465. Draws the last few lines of output transparently over the game top
  466. ================
  467. */
  468. void Con_DrawNotify (void)
  469. {
  470.     int        x, v;
  471.     char    *text;
  472.     int        i;
  473.     float    time;
  474.     char    *s;
  475.     int        skip;
  476.  
  477.     v = 0;
  478.     for (i= con->current-NUM_CON_TIMES+1 ; i<=con->current ; i++)
  479.     {
  480.         if (i < 0)
  481.             continue;
  482.         time = con_times[i % NUM_CON_TIMES];
  483.         if (time == 0)
  484.             continue;
  485.         time = realtime - time;
  486.         if (time > con_notifytime.value)
  487.             continue;
  488.         text = con->text + (i % con_totallines)*con_linewidth;
  489.         
  490.         clearnotify = 0;
  491.         scr_copytop = 1;
  492.  
  493.         for (x = 0 ; x < con_linewidth ; x++)
  494.             Draw_Character ( (x+1)<<3, v, text[x]);
  495.  
  496.         v += 8;
  497.     }
  498.  
  499.  
  500.     if (key_dest == key_message)
  501.     {
  502.         clearnotify = 0;
  503.         scr_copytop = 1;
  504.     
  505.         if (chat_team)
  506.         {
  507.             Draw_String (8, v, "say_team:");
  508.             skip = 11;
  509.         }
  510.         else
  511.         {
  512.             Draw_String (8, v, "say:");
  513.             skip = 5;
  514.         }
  515.  
  516.         s = chat_buffer;
  517.         if (chat_bufferlen > (vid.width>>3)-(skip+1))
  518.             s += chat_bufferlen - ((vid.width>>3)-(skip+1));
  519.         x = 0;
  520.         while(s[x])
  521.         {
  522.             Draw_Character ( (x+skip)<<3, v, s[x]);
  523.             x++;
  524.         }
  525.         Draw_Character ( (x+skip)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
  526.         v += 8;
  527.     }
  528.     
  529.     if (v > con_notifylines)
  530.         con_notifylines = v;
  531. }
  532.  
  533. /*
  534. ================
  535. Con_DrawConsole
  536.  
  537. Draws the console with the solid background
  538. ================
  539. */
  540. void Con_DrawConsole (int lines)
  541. {
  542.     int                i, j, x, y, n;
  543.     int                rows;
  544.     char            *text;
  545.     int                row;
  546.     char            dlbar[1024];
  547.     
  548.     if (lines <= 0)
  549.         return;
  550.  
  551. // draw the background
  552.     Draw_ConsoleBackground (lines);
  553.  
  554. // draw the text
  555.     con_vislines = lines;
  556.     
  557. // changed to line things up better
  558.     rows = (lines-22)>>3;        // rows of text to draw
  559.  
  560.     y = lines - 30;
  561.  
  562. // draw from the bottom up
  563.     if (con->display != con->current)
  564.     {
  565.     // draw arrows to show the buffer is backscrolled
  566.         for (x=0 ; x<con_linewidth ; x+=4)
  567.             Draw_Character ( (x+1)<<3, y, '^');
  568.     
  569.         y -= 8;
  570.         rows--;
  571.     }
  572.     
  573.     row = con->display;
  574.     for (i=0 ; i<rows ; i++, y-=8, row--)
  575.     {
  576.         if (row < 0)
  577.             break;
  578.         if (con->current - row >= con_totallines)
  579.             break;        // past scrollback wrap point
  580.             
  581.         text = con->text + (row % con_totallines)*con_linewidth;
  582.  
  583.         for (x=0 ; x<con_linewidth ; x++)
  584.             Draw_Character ( (x+1)<<3, y, text[x]);
  585.     }
  586.  
  587.     // draw the download bar
  588.     // figure out width
  589.     if (cls.download) {
  590.         if ((text = strrchr(cls.downloadname, '/')) != NULL)
  591.             text++;
  592.         else
  593.             text = cls.downloadname;
  594.  
  595.         x = con_linewidth - ((con_linewidth * 7) / 40);
  596.         y = x - strlen(text) - 8;
  597.         i = con_linewidth/3;
  598.         if (strlen(text) > i) {
  599.             y = x - i - 11;
  600.             strncpy(dlbar, text, i);
  601.             dlbar[i] = 0;
  602.             strcat(dlbar, "...");
  603.         } else
  604.             strcpy(dlbar, text);
  605.         strcat(dlbar, ": ");
  606.         i = strlen(dlbar);
  607.         dlbar[i++] = '\x80';
  608.         // where's the dot go?
  609.         if (cls.downloadpercent == 0)
  610.             n = 0;
  611.         else
  612.             n = y * cls.downloadpercent / 100;
  613.             
  614.         for (j = 0; j < y; j++)
  615.             if (j == n)
  616.                 dlbar[i++] = '\x83';
  617.             else
  618.                 dlbar[i++] = '\x81';
  619.         dlbar[i++] = '\x82';
  620.         dlbar[i] = 0;
  621.  
  622.         sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
  623.  
  624.         // draw it
  625.         y = con_vislines-22 + 8;
  626.         for (i = 0; i < strlen(dlbar); i++)
  627.             Draw_Character ( (i+1)<<3, y, dlbar[i]);
  628.     }
  629.  
  630.  
  631. // draw the input prompt, user text, and cursor if desired
  632.     Con_DrawInput ();
  633. }
  634.  
  635.  
  636. /*
  637. ==================
  638. Con_NotifyBox
  639. ==================
  640. */
  641. void Con_NotifyBox (char *text)
  642. {
  643.     double        t1, t2;
  644.  
  645. // during startup for sound / cd warnings
  646.     Con_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");
  647.  
  648.     Con_Printf (text);
  649.  
  650.     Con_Printf ("Press a key.\n");
  651.     Con_Printf("\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");
  652.  
  653.     key_count = -2;        // wait for a key down and up
  654.     key_dest = key_console;
  655.  
  656.     do
  657.     {
  658.         t1 = Sys_DoubleTime ();
  659.         SCR_UpdateScreen ();
  660.         Sys_SendKeyEvents ();
  661.         t2 = Sys_DoubleTime ();
  662.         realtime += t2-t1;        // make the cursor blink
  663.     } while (key_count < 0);
  664.  
  665.     Con_Printf ("\n");
  666.     key_dest = key_game;
  667.     realtime = 0;                // put the cursor back to invisible
  668. }
  669.  
  670.  
  671. /*
  672. ==================
  673. Con_SafePrintf
  674.  
  675. Okay to call even when the screen can't be updated
  676. ==================
  677. */
  678. void Con_SafePrintf (char *fmt, ...)
  679. {
  680.     va_list        argptr;
  681.     char        msg[1024];
  682.     int            temp;
  683.         
  684.     va_start (argptr,fmt);
  685.     vsprintf (msg,fmt,argptr);
  686.     va_end (argptr);
  687.     
  688.     temp = scr_disabled_for_loading;
  689.     scr_disabled_for_loading = true;
  690.     Con_Printf ("%s", msg);
  691.     scr_disabled_for_loading = temp;
  692. }
  693.  
  694.