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.
38 float con_cursorspeed = 4;
40 #define CON_TEXTSIZE 131072
42 // total lines in console scrollback
44 // lines up from bottom to display
46 // where next message will be printed
48 // offset in current line for next print
53 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
54 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
55 cvar_t logfile = {0, "logfile","0"};
57 #define MAX_NOTIFYLINES 32
58 // realtime time the line was generated for transparent notify lines
59 float con_times[MAX_NOTIFYLINES];
63 qboolean con_debuglog;
65 #define MAXCMDLINE 256
66 extern char key_lines[32][MAXCMDLINE];
68 extern int key_linepos;
69 extern int key_insert;
72 qboolean con_initialized;
74 mempool_t *console_mempool;
76 // scan lines to clear for notify lines
79 extern void M_Menu_Main_f (void);
86 void Con_ToggleConsole_f (void)
88 // toggle the 'user wants console' bit
89 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
90 memset (con_times, 0, sizeof(con_times));
98 void Con_Clear_f (void)
101 memset (con_text, ' ', CON_TEXTSIZE);
110 void Con_ClearNotify (void)
114 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
124 void Con_MessageMode_f (void)
126 key_dest = key_message;
136 void Con_MessageMode2_f (void)
138 key_dest = key_message;
147 If the line width has changed, reformat the buffer.
150 void Con_CheckResize (void)
152 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
153 char tbuf[CON_TEXTSIZE];
155 width = (vid.conwidth >> 3);
157 if (width == con_linewidth)
160 if (width < 1) // video hasn't been initialized yet
163 con_linewidth = width;
164 con_totallines = CON_TEXTSIZE / con_linewidth;
165 memset (con_text, ' ', CON_TEXTSIZE);
169 oldwidth = con_linewidth;
170 con_linewidth = width;
171 oldtotallines = con_totallines;
172 con_totallines = CON_TEXTSIZE / con_linewidth;
173 numlines = oldtotallines;
175 if (con_totallines < numlines)
176 numlines = con_totallines;
180 if (con_linewidth < numchars)
181 numchars = con_linewidth;
183 memcpy (tbuf, con_text, CON_TEXTSIZE);
184 memset (con_text, ' ', CON_TEXTSIZE);
186 for (i=0 ; i<numlines ; i++)
188 for (j=0 ; j<numchars ; j++)
190 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
191 tbuf[((con_current - i + oldtotallines) %
192 oldtotallines) * oldwidth + j];
200 con_current = con_totallines - 1;
204 void Con_InitLogging (void)
206 #define MAXGAMEDIRLEN 1000
207 char temp[MAXGAMEDIRLEN+1];
208 char *t2 = "/qconsole.log";
210 con_debuglog = COM_CheckParm("-condebug");
213 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
215 sprintf (temp, "%s%s", fs_gamedir, t2);
229 Cvar_RegisterVariable(&logfile);
231 console_mempool = Mem_AllocPool("console");
232 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
233 memset (con_text, ' ', CON_TEXTSIZE);
237 Con_Printf ("Console initialized.\n");
240 // register our commands
242 Cvar_RegisterVariable (&con_notifytime);
243 Cvar_RegisterVariable (&con_notify);
245 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
246 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
247 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
248 Cmd_AddCommand ("clear", Con_Clear_f);
249 con_initialized = true;
258 void Con_Linefeed (void)
262 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
269 Handles cursor positioning, line wrapping, etc
270 All console printing must go through this in order to be logged to disk
271 If no console is visible, the notify window will pop up.
274 void Con_Print (const char *txt)
283 mask = 128; // go to colored text
284 S_LocalSound ("misc/talk.wav");
288 else if (txt[0] == 2)
290 mask = 128; // go to colored text
300 for (l=0 ; l< con_linewidth ; l++)
305 if (l != con_linewidth && (con_x + l > con_linewidth) )
320 // mark time for transparent overlay
321 if (con_current >= 0)
323 if (con_notify.integer < 0)
324 Cvar_SetValueQuick(&con_notify, 0);
325 if (con_notifylines > MAX_NOTIFYLINES)
326 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
327 if (con_notify.integer > 0)
328 con_times[con_current % con_notify.integer] = realtime;
343 default: // display character and advance
344 y = con_current % con_totallines;
345 con_text[y*con_linewidth+con_x] = c | mask;
347 if (con_x >= con_linewidth)
361 void Con_DebugLog (const char *msg)
365 file = FS_Open ("qconsole.log", "at", true);
368 FS_Printf (file, "%s", msg);
378 Handles cursor positioning, line wrapping, etc
381 // LordHavoc: increased from 4096 to 16384
382 #define MAXPRINTMSG 16384
383 // FIXME: make a buffer size safe vsprintf?
384 void Con_Printf (const char *fmt, ...)
387 char msg[MAXPRINTMSG];
389 va_start (argptr,fmt);
390 vsprintf (msg,fmt,argptr);
393 // also echo to debugging console
394 Sys_Printf ("%s", msg);
396 // log all messages to file
400 if (!con_initialized)
403 if (cls.state == ca_dedicated)
404 return; // no graphics mode
406 // write it to the scrollable buffer
414 A Con_Printf that only shows up if the "developer" cvar is set
417 void Con_DPrintf (const char *fmt, ...)
420 char msg[MAXPRINTMSG];
422 if (!developer.integer)
423 return; // don't confuse non-developers with techie stuff...
425 va_start (argptr,fmt);
426 vsprintf (msg,fmt,argptr);
429 Con_Printf ("%s", msg);
437 Okay to call even when the screen can't be updated
440 void Con_SafePrintf (const char *fmt, ...)
445 va_start (argptr,fmt);
446 vsprintf (msg,fmt,argptr);
449 Con_Printf ("%s", msg);
454 ==============================================================================
458 ==============================================================================
466 The input line scrolls horizontally if typing goes beyond the right edge
468 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
471 void Con_DrawInput (void)
473 char editlinecopy[256], *text;
475 if (!key_consoleactive)
476 return; // don't draw anything
478 text = strcpy(editlinecopy, key_lines[edit_line]);
480 // Advanced Console Editing by Radix radix@planetquake.com
481 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
482 // use strlen of edit_line instead of key_linepos to allow editing
483 // of early characters w/o erasing
485 // add the cursor frame
486 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
487 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
489 text[key_linepos + 1] = 0;
491 // prestep if horizontally scrolling
492 if (key_linepos >= con_linewidth)
493 text += 1 + key_linepos - con_linewidth;
496 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
499 key_lines[edit_line][key_linepos] = 0;
507 Draws the last few lines of output transparently over the game top
510 void Con_DrawNotify (void)
516 extern char chat_buffer[];
519 if (con_notify.integer < 0)
520 Cvar_SetValueQuick(&con_notify, 0);
521 if (con_notifylines > MAX_NOTIFYLINES)
522 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
524 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
528 time = con_times[i % con_notify.integer];
531 time = realtime - time;
532 if (time > con_notifytime.value)
534 text = con_text + (i % con_totallines)*con_linewidth;
538 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
544 if (key_dest == key_message)
550 // LordHavoc: speedup, and other improvements
552 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
554 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
555 while (strlen(temptext) >= (size_t) con_linewidth)
557 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
558 strcpy(temptext, &temptext[con_linewidth]);
561 if (strlen(temptext) > 0)
563 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
568 if (con_notifylines < v)
576 Draws the console with the solid background
577 The typing input line at the bottom should only be drawn if typing is allowed
580 extern cvar_t scr_conalpha;
581 extern char engineversion[40];
582 void Con_DrawConsole (int lines)
590 // draw the background
591 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, 1, 1, 1, scr_conalpha.value * lines / vid.conheight, 0);
592 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
595 con_vislines = lines;
597 rows = (lines-16)>>3; // rows of text to draw
598 y = lines - 16 - (rows<<3); // may start slightly negative
600 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
602 j = max(i - con_backscroll, 0);
603 text = con_text + (j % con_totallines)*con_linewidth;
605 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
608 // draw the input prompt, user text, and cursor if desired
615 New function for tab-completion system
617 MEGA Thanks to Taniwha
620 void Con_DisplayList(const char **list)
622 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
623 const char **walk = list;
635 if (pos + maxlen >= width) {
640 Con_Printf("%s", *list);
641 for (i = 0; i < (maxlen - len); i++)
653 Con_CompleteCommandLine
655 New function for tab-completion system
657 Thanks to Fett erich@heintz.com
661 void Con_CompleteCommandLine (void)
663 const char *cmd = "", *s;
664 const char **list[3] = {0, 0, 0};
665 int c, v, a, i, cmd_len;
667 s = key_lines[edit_line] + 1;
668 // Count number of possible matches
669 c = Cmd_CompleteCountPossible(s);
670 v = Cvar_CompleteCountPossible(s);
671 a = Cmd_CompleteAliasCountPossible(s);
673 if (!(c + v + a)) // No possible matches
676 if (c + v + a == 1) {
678 list[0] = Cmd_CompleteBuildList(s);
680 list[0] = Cvar_CompleteBuildList(s);
682 list[0] = Cmd_CompleteAliasBuildList(s);
684 cmd_len = strlen (cmd);
687 cmd = *(list[0] = Cmd_CompleteBuildList(s));
689 cmd = *(list[1] = Cvar_CompleteBuildList(s));
691 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
693 cmd_len = strlen (s);
695 for (i = 0; i < 3; i++) {
696 char ch = cmd[cmd_len];
697 const char **l = list[i];
699 while (*l && (*l)[cmd_len] == ch)
710 for (i = 0; i < con_linewidth - 4; i++)
714 // Print Possible Commands
716 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
717 Con_DisplayList(list[0]);
721 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
722 Con_DisplayList(list[1]);
726 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
727 Con_DisplayList(list[2]);
732 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
733 key_linepos = cmd_len + 1;
734 if (c + v + a == 1) {
735 key_lines[edit_line][key_linepos] = ' ';
738 key_lines[edit_line][key_linepos] = 0;
740 for (i = 0; i < 3; i++)
742 Mem_Free((void *)list[i]);