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.
30 float con_cursorspeed = 4;
32 #define CON_TEXTSIZE 131072
34 // total lines in console scrollback
36 // lines up from bottom to display
38 // where next message will be printed
40 // offset in current line for next print
45 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
46 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
48 #define MAX_NOTIFYLINES 32
49 // cl.time time the line was generated for transparent notify lines
50 float con_times[MAX_NOTIFYLINES];
54 #define MAXCMDLINE 256
55 extern char key_lines[32][MAXCMDLINE];
57 extern int key_linepos;
58 extern int key_insert;
61 qboolean con_initialized;
63 mempool_t *console_mempool;
67 ==============================================================================
71 ==============================================================================
74 cvar_t log_file = {0, "log_file",""};
75 cvar_t log_sync = {0, "log_sync","0"};
76 char crt_log_file [MAX_OSPATH] = "";
77 qfile_t* logfile = NULL;
79 qbyte* logqueue = NULL;
83 void Log_ConPrint (const char *msg);
90 const char* Log_Timestamp (const char *desc)
92 static char timestamp [128];
94 const struct tm *crt_tm;
97 // Build the time stamp (ex: "Wed Jun 30 21:49:08 1993");
99 crt_tm = localtime (&crt_time);
100 strftime (timestring, sizeof (timestring), "%a %b %d %T %Y", crt_tm);
103 snprintf (timestamp, sizeof (timestamp), "====== %s (%s) ======\n", desc, timestring);
105 snprintf (timestamp, sizeof (timestamp), "====== %s ======\n", timestring);
118 Cvar_RegisterVariable (&log_file);
119 Cvar_RegisterVariable (&log_sync);
121 // support for the classic Quake option
122 if (COM_CheckParm ("-condebug") != 0)
124 Cvar_SetQuick (&log_file, "qconsole.log");
125 Cvar_SetValueQuick (&log_sync, 1);
126 unlink (va("%s/qconsole.log", fs_gamedir));
129 // Allocate a log queue
131 logqueue = Mem_Alloc (tempmempool, logq_size);
143 if (logfile != NULL || log_file.string[0] == '\0')
146 logfile = FS_Open (log_file.string, "at", false);
149 strlcpy (crt_log_file, log_file.string, sizeof (crt_log_file));
150 FS_Print (logfile, Log_Timestamp ("Log started"));
160 void Log_Close (void)
165 FS_Print (logfile, Log_Timestamp ("Log stopped"));
166 FS_Print (logfile, "\n");
170 crt_log_file[0] = '\0';
179 void Log_Start (void)
183 // Dump the contents of the log queue into the log file and free it
184 if (logqueue != NULL)
186 if (logfile != NULL && logq_ind != 0)
187 FS_Write (logfile, logqueue, logq_ind);
201 void Log_ConPrint (const char *msg)
203 // Until the host is completely initialized, we maintain a log queue
204 // to store the messages, since the log can't be started before
205 if (logqueue != NULL)
207 size_t remain = logq_size - logq_ind;
208 size_t len = strlen (msg);
210 // If we need to enlarge the log queue
213 unsigned int factor = ((logq_ind + len) / logq_size) + 1;
217 newqueue = Mem_Alloc (tempmempool, logq_size);
218 memcpy (newqueue, logqueue, logq_ind);
221 remain = logq_size - logq_ind;
223 memcpy (&logqueue[logq_ind], msg, len);
229 // Check if log_file has changed
230 if (strcmp (crt_log_file, log_file.string) != 0)
236 // If a log file is available
239 FS_Print (logfile, msg);
240 if (log_sync.integer)
251 void Log_Print (const char *logfilename, const char *msg)
254 file = FS_Open(logfilename, "at", true);
267 void Log_Printf (const char *logfilename, const char *fmt, ...)
271 file = FS_Open (logfilename, "at", true);
276 va_start (argptr, fmt);
277 FS_VPrintf (file, fmt, argptr);
286 ==============================================================================
290 ==============================================================================
298 void Con_ToggleConsole_f (void)
300 // toggle the 'user wants console' bit
301 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
302 memset (con_times, 0, sizeof(con_times));
310 void Con_Clear_f (void)
313 memset (con_text, ' ', CON_TEXTSIZE);
322 void Con_ClearNotify (void)
326 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
336 void Con_MessageMode_f (void)
338 key_dest = key_message;
348 void Con_MessageMode2_f (void)
350 key_dest = key_message;
359 If the line width has changed, reformat the buffer.
362 void Con_CheckResize (void)
364 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
365 char tbuf[CON_TEXTSIZE];
367 width = (vid.conwidth >> 3);
369 if (width == con_linewidth)
372 if (width < 1) // video hasn't been initialized yet
375 con_linewidth = width;
376 con_totallines = CON_TEXTSIZE / con_linewidth;
377 memset (con_text, ' ', CON_TEXTSIZE);
381 oldwidth = con_linewidth;
382 con_linewidth = width;
383 oldtotallines = con_totallines;
384 con_totallines = CON_TEXTSIZE / con_linewidth;
385 numlines = oldtotallines;
387 if (con_totallines < numlines)
388 numlines = con_totallines;
392 if (con_linewidth < numchars)
393 numchars = con_linewidth;
395 memcpy (tbuf, con_text, CON_TEXTSIZE);
396 memset (con_text, ' ', CON_TEXTSIZE);
398 for (i=0 ; i<numlines ; i++)
400 for (j=0 ; j<numchars ; j++)
402 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
403 tbuf[((con_current - i + oldtotallines) %
404 oldtotallines) * oldwidth + j];
412 con_current = con_totallines - 1;
422 console_mempool = Mem_AllocPool("console");
423 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
424 memset (con_text, ' ', CON_TEXTSIZE);
428 Con_Print("Console initialized.\n");
430 // register our cvars
431 Cvar_RegisterVariable (&con_notifytime);
432 Cvar_RegisterVariable (&con_notify);
434 // register our commands
435 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
436 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
437 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
438 Cmd_AddCommand ("clear", Con_Clear_f);
439 con_initialized = true;
448 void Con_Linefeed (void)
452 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
459 Handles cursor positioning, line wrapping, etc
460 All console printing must go through this in order to be displayed
461 If no console is visible, the notify window will pop up.
464 void Con_PrintToHistory(const char *txt)
473 mask = 128; // go to colored text
474 S_LocalSound ("misc/talk.wav");
478 else if (txt[0] == 2)
480 mask = 128; // go to colored text
490 for (l=0 ; l< con_linewidth ; l++)
495 if (l != con_linewidth && (con_x + l > con_linewidth) )
510 // mark time for transparent overlay
511 if (con_current >= 0)
513 if (con_notify.integer < 0)
514 Cvar_SetValueQuick(&con_notify, 0);
515 if (con_notify.integer > MAX_NOTIFYLINES)
516 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
517 if (con_notify.integer > 0)
518 con_times[con_current % con_notify.integer] = cl.time;
533 default: // display character and advance
534 y = con_current % con_totallines;
535 con_text[y*con_linewidth+con_x] = c | mask;
537 if (con_x >= con_linewidth)
549 Prints to all appropriate console targets
552 void Con_Print(const char *msg)
554 // also echo to debugging console
557 // log all messages to file
560 if (!con_initialized)
563 if (cls.state == ca_dedicated)
564 return; // no graphics mode
566 // write it to the scrollable buffer
567 Con_PrintToHistory(msg);
571 // LordHavoc: increased from 4096 to 16384
572 #define MAXPRINTMSG 16384
578 Prints to all appropriate console targets
581 void Con_Printf(const char *fmt, ...)
584 char msg[MAXPRINTMSG];
586 va_start(argptr,fmt);
587 vsprintf(msg,fmt,argptr);
597 A Con_Print that only shows up if the "developer" cvar is set
600 void Con_DPrint(const char *msg)
602 if (!developer.integer)
603 return; // don't confuse non-developers with techie stuff...
611 A Con_Printf that only shows up if the "developer" cvar is set
614 void Con_DPrintf(const char *fmt, ...)
617 char msg[MAXPRINTMSG];
619 if (!developer.integer)
620 return; // don't confuse non-developers with techie stuff...
622 va_start(argptr,fmt);
623 vsprintf(msg,fmt,argptr);
634 Okay to call even when the screen can't be updated
637 void Con_SafePrint(const char *msg)
646 Okay to call even when the screen can't be updated
649 void Con_SafePrintf(const char *fmt, ...)
652 char msg[MAXPRINTMSG];
654 va_start(argptr,fmt);
655 vsprintf(msg,fmt,argptr);
663 ==============================================================================
667 ==============================================================================
675 The input line scrolls horizontally if typing goes beyond the right edge
677 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
680 void Con_DrawInput (void)
684 char editlinecopy[257], *text;
686 if (!key_consoleactive)
687 return; // don't draw anything
689 text = strcpy(editlinecopy, key_lines[edit_line]);
691 // Advanced Console Editing by Radix radix@planetquake.com
692 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
693 // use strlen of edit_line instead of key_linepos to allow editing
694 // of early characters w/o erasing
698 // fill out remainder with spaces
699 for (i = y; i < 256; i++)
702 // add the cursor frame
703 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
704 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
706 // text[key_linepos + 1] = 0;
708 // prestep if horizontally scrolling
709 if (key_linepos >= con_linewidth)
710 text += 1 + key_linepos - con_linewidth;
713 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
716 // key_lines[edit_line][key_linepos] = 0;
724 Draws the last few lines of output transparently over the game top
727 void Con_DrawNotify (void)
733 extern char chat_buffer[];
736 if (con_notify.integer < 0)
737 Cvar_SetValueQuick(&con_notify, 0);
738 if (con_notify.integer > MAX_NOTIFYLINES)
739 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
740 if (gamemode == GAME_TRANSFUSION)
744 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
748 time = con_times[i % con_notify.integer];
751 time = cl.time - time;
752 if (time > con_notifytime.value)
754 text = con_text + (i % con_totallines)*con_linewidth;
758 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
764 if (key_dest == key_message)
770 // LordHavoc: speedup, and other improvements
772 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
774 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
775 while (strlen(temptext) >= (size_t) con_linewidth)
777 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
778 strcpy(temptext, &temptext[con_linewidth]);
781 if (strlen(temptext) > 0)
783 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
793 Draws the console with the solid background
794 The typing input line at the bottom should only be drawn if typing is allowed
797 extern char engineversion[40];
798 void Con_DrawConsole (int lines)
806 // draw the background
807 if (scr_conbrightness.value >= 0.01f)
808 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);
810 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
811 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
814 con_vislines = lines;
816 rows = (lines-16)>>3; // rows of text to draw
817 y = lines - 16 - (rows<<3); // may start slightly negative
819 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
821 j = max(i - con_backscroll, 0);
822 text = con_text + (j % con_totallines)*con_linewidth;
824 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
827 // draw the input prompt, user text, and cursor if desired
834 New function for tab-completion system
836 MEGA Thanks to Taniwha
839 void Con_DisplayList(const char **list)
841 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
842 const char **walk = list;
854 if (pos + maxlen >= width) {
860 for (i = 0; i < (maxlen - len); i++)
872 Con_CompleteCommandLine
874 New function for tab-completion system
876 Thanks to Fett erich@heintz.com
880 void Con_CompleteCommandLine (void)
882 const char *cmd = "", *s;
883 const char **list[3] = {0, 0, 0};
884 int c, v, a, i, cmd_len;
886 s = key_lines[edit_line] + 1;
887 // Count number of possible matches
888 c = Cmd_CompleteCountPossible(s);
889 v = Cvar_CompleteCountPossible(s);
890 a = Cmd_CompleteAliasCountPossible(s);
892 if (!(c + v + a)) // No possible matches
895 if (c + v + a == 1) {
897 list[0] = Cmd_CompleteBuildList(s);
899 list[0] = Cvar_CompleteBuildList(s);
901 list[0] = Cmd_CompleteAliasBuildList(s);
903 cmd_len = strlen (cmd);
906 cmd = *(list[0] = Cmd_CompleteBuildList(s));
908 cmd = *(list[1] = Cvar_CompleteBuildList(s));
910 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
912 cmd_len = strlen (s);
914 for (i = 0; i < 3; i++) {
915 char ch = cmd[cmd_len];
916 const char **l = list[i];
918 while (*l && (*l)[cmd_len] == ch)
929 for (i = 0; i < con_linewidth - 4; i++)
933 // Print Possible Commands
935 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
936 Con_DisplayList(list[0]);
940 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
941 Con_DisplayList(list[1]);
945 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
946 Con_DisplayList(list[2]);
951 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
952 key_linepos = cmd_len + 1;
953 if (c + v + a == 1) {
954 key_lines[edit_line][key_linepos] = ' ';
957 key_lines[edit_line][key_linepos] = 0;
959 for (i = 0; i < 3; i++)
961 Mem_Free((void *)list[i]);