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