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);
657 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
661 time = con_times[i % con_notify.integer];
664 time = cl.time - time;
665 if (time > con_notifytime.value)
667 text = con_text + (i % con_totallines)*con_linewidth;
671 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
677 if (key_dest == key_message)
683 // LordHavoc: speedup, and other improvements
685 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
687 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
688 while (strlen(temptext) >= (size_t) con_linewidth)
690 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
691 strcpy(temptext, &temptext[con_linewidth]);
694 if (strlen(temptext) > 0)
696 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
706 Draws the console with the solid background
707 The typing input line at the bottom should only be drawn if typing is allowed
710 extern char engineversion[40];
711 void Con_DrawConsole (int lines)
719 // draw the background
720 if (scr_conbrightness.value >= 0.01f)
721 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);
723 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
724 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
727 con_vislines = lines;
729 rows = (lines-16)>>3; // rows of text to draw
730 y = lines - 16 - (rows<<3); // may start slightly negative
732 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
734 j = max(i - con_backscroll, 0);
735 text = con_text + (j % con_totallines)*con_linewidth;
737 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
740 // draw the input prompt, user text, and cursor if desired
747 New function for tab-completion system
749 MEGA Thanks to Taniwha
752 void Con_DisplayList(const char **list)
754 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
755 const char **walk = list;
767 if (pos + maxlen >= width) {
773 for (i = 0; i < (maxlen - len); i++)
785 Con_CompleteCommandLine
787 New function for tab-completion system
789 Thanks to Fett erich@heintz.com
793 void Con_CompleteCommandLine (void)
795 const char *cmd = "", *s;
796 const char **list[3] = {0, 0, 0};
797 int c, v, a, i, cmd_len;
799 s = key_lines[edit_line] + 1;
800 // Count number of possible matches
801 c = Cmd_CompleteCountPossible(s);
802 v = Cvar_CompleteCountPossible(s);
803 a = Cmd_CompleteAliasCountPossible(s);
805 if (!(c + v + a)) // No possible matches
808 if (c + v + a == 1) {
810 list[0] = Cmd_CompleteBuildList(s);
812 list[0] = Cvar_CompleteBuildList(s);
814 list[0] = Cmd_CompleteAliasBuildList(s);
816 cmd_len = strlen (cmd);
819 cmd = *(list[0] = Cmd_CompleteBuildList(s));
821 cmd = *(list[1] = Cvar_CompleteBuildList(s));
823 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
825 cmd_len = strlen (s);
827 for (i = 0; i < 3; i++) {
828 char ch = cmd[cmd_len];
829 const char **l = list[i];
831 while (*l && (*l)[cmd_len] == ch)
842 for (i = 0; i < con_linewidth - 4; i++)
846 // Print Possible Commands
848 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
849 Con_DisplayList(list[0]);
853 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
854 Con_DisplayList(list[1]);
858 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
859 Con_DisplayList(list[2]);
864 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
865 key_linepos = cmd_len + 1;
866 if (c + v + a == 1) {
867 key_lines[edit_line][key_linepos] = ' ';
870 key_lines[edit_line][key_linepos] = 0;
872 for (i = 0; i < 3; i++)
874 Mem_Free((void *)list[i]);