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;
211 #define MAXGAMEDIRLEN 1000
212 char temp[MAXGAMEDIRLEN+1];
213 char *t2 = "/qconsole.log";
215 Cvar_RegisterVariable(&logfile);
216 con_debuglog = COM_CheckParm("-condebug");
220 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
222 sprintf (temp, "%s%s", fs_gamedir, t2);
228 console_mempool = Mem_AllocPool("console");
229 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
230 memset (con_text, ' ', CON_TEXTSIZE);
234 Con_Printf ("Console initialized.\n");
237 // register our commands
239 Cvar_RegisterVariable (&con_notifytime);
240 Cvar_RegisterVariable (&con_notify);
242 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
243 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
244 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
245 Cmd_AddCommand ("clear", Con_Clear_f);
246 con_initialized = true;
255 void Con_Linefeed (void)
259 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
266 Handles cursor positioning, line wrapping, etc
267 All console printing must go through this in order to be logged to disk
268 If no console is visible, the notify window will pop up.
271 void Con_Print (const char *txt)
280 mask = 128; // go to colored text
281 S_LocalSound ("misc/talk.wav");
285 else if (txt[0] == 2)
287 mask = 128; // go to colored text
297 for (l=0 ; l< con_linewidth ; l++)
302 if (l != con_linewidth && (con_x + l > con_linewidth) )
317 // mark time for transparent overlay
318 if (con_current >= 0)
320 if (con_notify.integer < 0)
321 Cvar_SetValueQuick(&con_notify, 0);
322 if (con_notifylines > MAX_NOTIFYLINES)
323 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
324 if (con_notify.integer > 0)
325 con_times[con_current % con_notify.integer] = realtime;
340 default: // display character and advance
341 y = con_current % con_totallines;
342 con_text[y*con_linewidth+con_x] = c | mask;
344 if (con_x >= con_linewidth)
358 void Con_DebugLog (const char *msg)
362 file = FS_Open ("qconsole.log", "at", true);
365 FS_Printf (file, "%s", msg);
375 Handles cursor positioning, line wrapping, etc
378 // LordHavoc: increased from 4096 to 16384
379 #define MAXPRINTMSG 16384
380 // FIXME: make a buffer size safe vsprintf?
381 void Con_Printf (const char *fmt, ...)
384 char msg[MAXPRINTMSG];
386 va_start (argptr,fmt);
387 vsprintf (msg,fmt,argptr);
390 // also echo to debugging console
391 Sys_Printf ("%s", msg);
393 // log all messages to file
397 if (!con_initialized)
400 if (cls.state == ca_dedicated)
401 return; // no graphics mode
403 // write it to the scrollable buffer
411 A Con_Printf that only shows up if the "developer" cvar is set
414 void Con_DPrintf (const char *fmt, ...)
417 char msg[MAXPRINTMSG];
419 if (!developer.integer)
420 return; // don't confuse non-developers with techie stuff...
422 va_start (argptr,fmt);
423 vsprintf (msg,fmt,argptr);
426 Con_Printf ("%s", msg);
434 Okay to call even when the screen can't be updated
437 void Con_SafePrintf (const char *fmt, ...)
442 va_start (argptr,fmt);
443 vsprintf (msg,fmt,argptr);
446 Con_Printf ("%s", msg);
451 ==============================================================================
455 ==============================================================================
463 The input line scrolls horizontally if typing goes beyond the right edge
465 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
468 void Con_DrawInput (void)
470 char editlinecopy[256], *text;
472 if (!key_consoleactive)
473 return; // don't draw anything
475 text = strcpy(editlinecopy, key_lines[edit_line]);
477 // Advanced Console Editing by Radix radix@planetquake.com
478 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
479 // use strlen of edit_line instead of key_linepos to allow editing
480 // of early characters w/o erasing
482 // add the cursor frame
483 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
484 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
486 text[key_linepos + 1] = 0;
488 // prestep if horizontally scrolling
489 if (key_linepos >= con_linewidth)
490 text += 1 + key_linepos - con_linewidth;
493 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
496 key_lines[edit_line][key_linepos] = 0;
504 Draws the last few lines of output transparently over the game top
507 void Con_DrawNotify (void)
513 extern char chat_buffer[];
516 if (con_notify.integer < 0)
517 Cvar_SetValueQuick(&con_notify, 0);
518 if (con_notifylines > MAX_NOTIFYLINES)
519 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
521 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
525 time = con_times[i % con_notify.integer];
528 time = realtime - time;
529 if (time > con_notifytime.value)
531 text = con_text + (i % con_totallines)*con_linewidth;
535 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
541 if (key_dest == key_message)
547 // LordHavoc: speedup, and other improvements
549 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
551 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
552 while (strlen(temptext) >= (size_t) con_linewidth)
554 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
555 strcpy(temptext, &temptext[con_linewidth]);
558 if (strlen(temptext) > 0)
560 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
565 if (con_notifylines < v)
573 Draws the console with the solid background
574 The typing input line at the bottom should only be drawn if typing is allowed
577 extern cvar_t scr_conalpha;
578 extern char engineversion[40];
579 void Con_DrawConsole (int lines)
587 // draw the background
588 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, 1, 1, 1, scr_conalpha.value * lines / vid.conheight, 0);
589 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
592 con_vislines = lines;
594 rows = (lines-16)>>3; // rows of text to draw
595 y = lines - 16 - (rows<<3); // may start slightly negative
597 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
599 j = max(i - con_backscroll, 0);
600 text = con_text + (j % con_totallines)*con_linewidth;
602 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
605 // draw the input prompt, user text, and cursor if desired
612 New function for tab-completion system
614 MEGA Thanks to Taniwha
617 void Con_DisplayList(const char **list)
619 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
620 const char **walk = list;
632 if (pos + maxlen >= width) {
637 Con_Printf("%s", *list);
638 for (i = 0; i < (maxlen - len); i++)
650 Con_CompleteCommandLine
652 New function for tab-completion system
654 Thanks to Fett erich@heintz.com
658 void Con_CompleteCommandLine (void)
660 const char *cmd = "", *s;
661 const char **list[3] = {0, 0, 0};
662 int c, v, a, i, cmd_len;
664 s = key_lines[edit_line] + 1;
665 // Count number of possible matches
666 c = Cmd_CompleteCountPossible(s);
667 v = Cvar_CompleteCountPossible(s);
668 a = Cmd_CompleteAliasCountPossible(s);
670 if (!(c + v + a)) // No possible matches
673 if (c + v + a == 1) {
675 list[0] = Cmd_CompleteBuildList(s);
677 list[0] = Cvar_CompleteBuildList(s);
679 list[0] = Cmd_CompleteAliasBuildList(s);
681 cmd_len = strlen (cmd);
684 cmd = *(list[0] = Cmd_CompleteBuildList(s));
686 cmd = *(list[1] = Cvar_CompleteBuildList(s));
688 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
690 cmd_len = strlen (s);
692 for (i = 0; i < 3; i++) {
693 char ch = cmd[cmd_len];
694 const char **l = list[i];
696 while (*l && (*l)[cmd_len] == ch)
707 for (i = 0; i < con_linewidth - 4; i++)
711 // Print Possible Commands
713 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
714 Con_DisplayList(list[0]);
718 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
719 Con_DisplayList(list[1]);
723 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
724 Con_DisplayList(list[2]);
729 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
730 key_linepos = cmd_len + 1;
731 if (c + v + a == 1) {
732 key_lines[edit_line][key_linepos] = ' ';
735 key_lines[edit_line][key_linepos] = 0;
737 for (i = 0; i < 3; i++)
739 Mem_Free((void *)list[i]);