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 displayed
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 char engineversion[40];
581 void Con_DrawConsole (int lines)
589 // draw the background
590 if (scr_conbrightness.value >= 0.01f)
591 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);
593 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
594 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
597 con_vislines = lines;
599 rows = (lines-16)>>3; // rows of text to draw
600 y = lines - 16 - (rows<<3); // may start slightly negative
602 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
604 j = max(i - con_backscroll, 0);
605 text = con_text + (j % con_totallines)*con_linewidth;
607 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
610 // draw the input prompt, user text, and cursor if desired
617 New function for tab-completion system
619 MEGA Thanks to Taniwha
622 void Con_DisplayList(const char **list)
624 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
625 const char **walk = list;
637 if (pos + maxlen >= width) {
642 Con_Printf("%s", *list);
643 for (i = 0; i < (maxlen - len); i++)
655 Con_CompleteCommandLine
657 New function for tab-completion system
659 Thanks to Fett erich@heintz.com
663 void Con_CompleteCommandLine (void)
665 const char *cmd = "", *s;
666 const char **list[3] = {0, 0, 0};
667 int c, v, a, i, cmd_len;
669 s = key_lines[edit_line] + 1;
670 // Count number of possible matches
671 c = Cmd_CompleteCountPossible(s);
672 v = Cvar_CompleteCountPossible(s);
673 a = Cmd_CompleteAliasCountPossible(s);
675 if (!(c + v + a)) // No possible matches
678 if (c + v + a == 1) {
680 list[0] = Cmd_CompleteBuildList(s);
682 list[0] = Cvar_CompleteBuildList(s);
684 list[0] = Cmd_CompleteAliasBuildList(s);
686 cmd_len = strlen (cmd);
689 cmd = *(list[0] = Cmd_CompleteBuildList(s));
691 cmd = *(list[1] = Cvar_CompleteBuildList(s));
693 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
695 cmd_len = strlen (s);
697 for (i = 0; i < 3; i++) {
698 char ch = cmd[cmd_len];
699 const char **l = list[i];
701 while (*l && (*l)[cmd_len] == ch)
712 for (i = 0; i < con_linewidth - 4; i++)
716 // Print Possible Commands
718 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
719 Con_DisplayList(list[0]);
723 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
724 Con_DisplayList(list[1]);
728 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
729 Con_DisplayList(list[2]);
734 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
735 key_linepos = cmd_len + 1;
736 if (c + v + a == 1) {
737 key_lines[edit_line][key_linepos] = ' ';
740 key_lines[edit_line][key_linepos] = 0;
742 for (i = 0; i < 3; i++)
744 Mem_Free((void *)list[i]);