2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
29 float con_cursorspeed = 4;
31 #define CON_TEXTSIZE 131072
33 // total lines in console scrollback
35 // lines up from bottom to display
37 // where next message will be printed
39 // offset in current line for next print
44 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
45 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
47 #define MAX_NOTIFYLINES 32
48 // cl.time time the line was generated for transparent notify lines
49 float con_times[MAX_NOTIFYLINES];
53 #define MAXCMDLINE 256
54 extern char key_lines[32][MAXCMDLINE];
56 extern int key_linepos;
57 extern int key_insert;
60 qboolean con_initialized;
62 mempool_t *console_mempool;
66 ==============================================================================
70 ==============================================================================
73 cvar_t log_file = {0, "log_file",""};
74 cvar_t log_sync = {0, "log_sync","0"};
75 qfile_t* logfile = NULL;
77 qbyte* logqueue = NULL;
88 Cvar_RegisterVariable (&log_file);
89 Cvar_RegisterVariable (&log_sync);
91 // support for the classic Quake option
92 if (COM_CheckParm ("-condebug") != 0)
94 Cvar_SetQuick (&log_file, "qconsole.log");
95 Cvar_SetValueQuick (&log_sync, 1);
98 // Allocate a log queue
100 logqueue = Mem_Alloc (tempmempool, logq_size);
110 void Log_Start (void)
112 if (log_file.string[0] != '\0')
113 logfile = FS_Open (log_file.string, "wt", false);
115 // Dump the contents of the log queue into the log file and free it
116 if (logqueue != NULL)
118 if (logfile != NULL && logq_ind != 0)
119 FS_Write (logfile, logqueue, logq_ind);
133 void Log_ConPrint (const char *msg)
135 // Easy case: a log has been started
138 FS_Print (logfile, msg);
139 if (log_sync.integer)
144 // Until the host is completely initialized, we maintain a log queue
145 // to store the messages, since the log can't be started before
146 if (logqueue != NULL)
148 size_t remain = logq_size - logq_ind;
149 size_t len = strlen (msg);
151 // If we need to enlarge the log queue
154 unsigned int factor = ((logq_ind + len) / logq_size) + 1;
158 newqueue = Mem_Alloc (tempmempool, logq_size);
159 memcpy (newqueue, logqueue, logq_ind);
162 remain = logq_size - logq_ind;
164 memcpy (&logqueue[logq_ind], msg, len);
175 void Log_Print (const char *logfilename, const char *msg)
178 file = FS_Open(logfilename, "at", true);
191 void Log_Printf (const char *logfilename, const char *fmt, ...)
195 file = FS_Open (logfilename, "at", true);
200 va_start (argptr, fmt);
201 FS_VPrintf (file, fmt, argptr);
210 ==============================================================================
214 ==============================================================================
222 void Con_ToggleConsole_f (void)
224 // toggle the 'user wants console' bit
225 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
226 memset (con_times, 0, sizeof(con_times));
234 void Con_Clear_f (void)
237 memset (con_text, ' ', CON_TEXTSIZE);
246 void Con_ClearNotify (void)
250 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
260 void Con_MessageMode_f (void)
262 key_dest = key_message;
272 void Con_MessageMode2_f (void)
274 key_dest = key_message;
283 If the line width has changed, reformat the buffer.
286 void Con_CheckResize (void)
288 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
289 char tbuf[CON_TEXTSIZE];
291 width = (vid.conwidth >> 3);
293 if (width == con_linewidth)
296 if (width < 1) // video hasn't been initialized yet
299 con_linewidth = width;
300 con_totallines = CON_TEXTSIZE / con_linewidth;
301 memset (con_text, ' ', CON_TEXTSIZE);
305 oldwidth = con_linewidth;
306 con_linewidth = width;
307 oldtotallines = con_totallines;
308 con_totallines = CON_TEXTSIZE / con_linewidth;
309 numlines = oldtotallines;
311 if (con_totallines < numlines)
312 numlines = con_totallines;
316 if (con_linewidth < numchars)
317 numchars = con_linewidth;
319 memcpy (tbuf, con_text, CON_TEXTSIZE);
320 memset (con_text, ' ', CON_TEXTSIZE);
322 for (i=0 ; i<numlines ; i++)
324 for (j=0 ; j<numchars ; j++)
326 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
327 tbuf[((con_current - i + oldtotallines) %
328 oldtotallines) * oldwidth + j];
336 con_current = con_totallines - 1;
346 console_mempool = Mem_AllocPool("console");
347 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
348 memset (con_text, ' ', CON_TEXTSIZE);
352 Con_Print("Console initialized.\n");
354 // register our cvars
355 Cvar_RegisterVariable (&con_notifytime);
356 Cvar_RegisterVariable (&con_notify);
358 // register our commands
359 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
360 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
361 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
362 Cmd_AddCommand ("clear", Con_Clear_f);
363 con_initialized = true;
372 void Con_Linefeed (void)
376 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
383 Handles cursor positioning, line wrapping, etc
384 All console printing must go through this in order to be displayed
385 If no console is visible, the notify window will pop up.
388 void Con_PrintToHistory(const char *txt)
397 mask = 128; // go to colored text
398 S_LocalSound ("misc/talk.wav");
402 else if (txt[0] == 2)
404 mask = 128; // go to colored text
414 for (l=0 ; l< con_linewidth ; l++)
419 if (l != con_linewidth && (con_x + l > con_linewidth) )
434 // mark time for transparent overlay
435 if (con_current >= 0)
437 if (con_notify.integer < 0)
438 Cvar_SetValueQuick(&con_notify, 0);
439 if (con_notify.integer > MAX_NOTIFYLINES)
440 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
441 if (con_notify.integer > 0)
442 con_times[con_current % con_notify.integer] = cl.time;
457 default: // display character and advance
458 y = con_current % con_totallines;
459 con_text[y*con_linewidth+con_x] = c | mask;
461 if (con_x >= con_linewidth)
473 Prints to all appropriate console targets
476 void Con_Print(const char *msg)
478 // also echo to debugging console
481 // log all messages to file
484 if (!con_initialized)
487 if (cls.state == ca_dedicated)
488 return; // no graphics mode
490 // write it to the scrollable buffer
491 Con_PrintToHistory(msg);
495 // LordHavoc: increased from 4096 to 16384
496 #define MAXPRINTMSG 16384
502 Prints to all appropriate console targets
505 void Con_Printf(const char *fmt, ...)
508 char msg[MAXPRINTMSG];
510 va_start(argptr,fmt);
511 vsprintf(msg,fmt,argptr);
521 A Con_Print that only shows up if the "developer" cvar is set
524 void Con_DPrint(const char *msg)
526 if (!developer.integer)
527 return; // don't confuse non-developers with techie stuff...
535 A Con_Printf that only shows up if the "developer" cvar is set
538 void Con_DPrintf(const char *fmt, ...)
541 char msg[MAXPRINTMSG];
543 if (!developer.integer)
544 return; // don't confuse non-developers with techie stuff...
546 va_start(argptr,fmt);
547 vsprintf(msg,fmt,argptr);
558 Okay to call even when the screen can't be updated
561 void Con_SafePrint(const char *msg)
570 Okay to call even when the screen can't be updated
573 void Con_SafePrintf(const char *fmt, ...)
576 char msg[MAXPRINTMSG];
578 va_start(argptr,fmt);
579 vsprintf(msg,fmt,argptr);
587 ==============================================================================
591 ==============================================================================
599 The input line scrolls horizontally if typing goes beyond the right edge
601 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
604 void Con_DrawInput (void)
606 char editlinecopy[257], *text;
608 if (!key_consoleactive)
609 return; // don't draw anything
611 text = strcpy(editlinecopy, key_lines[edit_line]);
613 // Advanced Console Editing by Radix radix@planetquake.com
614 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
615 // use strlen of edit_line instead of key_linepos to allow editing
616 // of early characters w/o erasing
618 // add the cursor frame
619 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
620 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
622 text[key_linepos + 1] = 0;
624 // prestep if horizontally scrolling
625 if (key_linepos >= con_linewidth)
626 text += 1 + key_linepos - con_linewidth;
629 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
632 key_lines[edit_line][key_linepos] = 0;
640 Draws the last few lines of output transparently over the game top
643 void Con_DrawNotify (void)
649 extern char chat_buffer[];
652 if (con_notify.integer < 0)
653 Cvar_SetValueQuick(&con_notify, 0);
654 if (con_notify.integer > MAX_NOTIFYLINES)
655 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
656 if (gamemode == GAME_TRANSFUSION)
660 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
664 time = con_times[i % con_notify.integer];
667 time = cl.time - time;
668 if (time > con_notifytime.value)
670 text = con_text + (i % con_totallines)*con_linewidth;
674 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
680 if (key_dest == key_message)
686 // LordHavoc: speedup, and other improvements
688 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
690 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
691 while (strlen(temptext) >= (size_t) con_linewidth)
693 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
694 strcpy(temptext, &temptext[con_linewidth]);
697 if (strlen(temptext) > 0)
699 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
709 Draws the console with the solid background
710 The typing input line at the bottom should only be drawn if typing is allowed
713 extern char engineversion[40];
714 void Con_DrawConsole (int lines)
722 // draw the background
723 if (scr_conbrightness.value >= 0.01f)
724 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, scr_conalpha.value, 0);
726 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
727 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
730 con_vislines = lines;
732 rows = (lines-16)>>3; // rows of text to draw
733 y = lines - 16 - (rows<<3); // may start slightly negative
735 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
737 j = max(i - con_backscroll, 0);
738 text = con_text + (j % con_totallines)*con_linewidth;
740 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
743 // draw the input prompt, user text, and cursor if desired
750 New function for tab-completion system
752 MEGA Thanks to Taniwha
755 void Con_DisplayList(const char **list)
757 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
758 const char **walk = list;
770 if (pos + maxlen >= width) {
776 for (i = 0; i < (maxlen - len); i++)
788 Con_CompleteCommandLine
790 New function for tab-completion system
792 Thanks to Fett erich@heintz.com
796 void Con_CompleteCommandLine (void)
798 const char *cmd = "", *s;
799 const char **list[3] = {0, 0, 0};
800 int c, v, a, i, cmd_len;
802 s = key_lines[edit_line] + 1;
803 // Count number of possible matches
804 c = Cmd_CompleteCountPossible(s);
805 v = Cvar_CompleteCountPossible(s);
806 a = Cmd_CompleteAliasCountPossible(s);
808 if (!(c + v + a)) // No possible matches
811 if (c + v + a == 1) {
813 list[0] = Cmd_CompleteBuildList(s);
815 list[0] = Cvar_CompleteBuildList(s);
817 list[0] = Cmd_CompleteAliasBuildList(s);
819 cmd_len = strlen (cmd);
822 cmd = *(list[0] = Cmd_CompleteBuildList(s));
824 cmd = *(list[1] = Cvar_CompleteBuildList(s));
826 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
828 cmd_len = strlen (s);
830 for (i = 0; i < 3; i++) {
831 char ch = cmd[cmd_len];
832 const char **l = list[i];
834 while (*l && (*l)[cmd_len] == ch)
845 for (i = 0; i < con_linewidth - 4; i++)
849 // Print Possible Commands
851 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
852 Con_DisplayList(list[0]);
856 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
857 Con_DisplayList(list[1]);
861 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
862 Con_DisplayList(list[2]);
867 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
868 key_linepos = cmd_len + 1;
869 if (c + v + a == 1) {
870 key_lines[edit_line][key_linepos] = ' ';
873 key_lines[edit_line][key_linepos] = 0;
875 for (i = 0; i < 3; i++)
877 Mem_Free((void *)list[i]);