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 (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
222 sprintf (temp, "%s%s", com_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 *file, const char *fmt, ...)
363 fd = fopen(file, "at");
364 va_start(argptr, fmt);
365 vfprintf (fd, fmt, argptr);
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
396 // can't use va() here because it might overwrite other important things
397 char logname[MAX_OSPATH];
398 sprintf(logname, "%s/qconsole.log", com_gamedir);
399 Con_DebugLog(logname, "%s", msg);
402 if (!con_initialized)
405 if (cls.state == ca_dedicated)
406 return; // no graphics mode
408 // write it to the scrollable buffer
416 A Con_Printf that only shows up if the "developer" cvar is set
419 void Con_DPrintf (const char *fmt, ...)
422 char msg[MAXPRINTMSG];
424 if (!developer.integer)
425 return; // don't confuse non-developers with techie stuff...
427 va_start (argptr,fmt);
428 vsprintf (msg,fmt,argptr);
431 Con_Printf ("%s", msg);
439 Okay to call even when the screen can't be updated
442 void Con_SafePrintf (const char *fmt, ...)
447 va_start (argptr,fmt);
448 vsprintf (msg,fmt,argptr);
451 Con_Printf ("%s", msg);
456 ==============================================================================
460 ==============================================================================
468 The input line scrolls horizontally if typing goes beyond the right edge
470 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
473 void Con_DrawInput (void)
475 char editlinecopy[256], *text;
477 if (!key_consoleactive)
478 return; // don't draw anything
480 text = strcpy(editlinecopy, key_lines[edit_line]);
482 // Advanced Console Editing by Radix radix@planetquake.com
483 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
484 // use strlen of edit_line instead of key_linepos to allow editing
485 // of early characters w/o erasing
487 // add the cursor frame
488 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
489 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
491 text[key_linepos + 1] = 0;
493 // prestep if horizontally scrolling
494 if (key_linepos >= con_linewidth)
495 text += 1 + key_linepos - con_linewidth;
498 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
501 key_lines[edit_line][key_linepos] = 0;
509 Draws the last few lines of output transparently over the game top
512 void Con_DrawNotify (void)
518 extern char chat_buffer[];
521 if (con_notify.integer < 0)
522 Cvar_SetValueQuick(&con_notify, 0);
523 if (con_notifylines > MAX_NOTIFYLINES)
524 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
526 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
530 time = con_times[i % con_notify.integer];
533 time = realtime - time;
534 if (time > con_notifytime.value)
536 text = con_text + (i % con_totallines)*con_linewidth;
540 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
546 if (key_dest == key_message)
552 // LordHavoc: speedup, and other improvements
554 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
556 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
557 while (strlen(temptext) >= (size_t) con_linewidth)
559 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
560 strcpy(temptext, &temptext[con_linewidth]);
563 if (strlen(temptext) > 0)
565 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
570 if (con_notifylines < v)
578 Draws the console with the solid background
579 The typing input line at the bottom should only be drawn if typing is allowed
582 extern cvar_t scr_conalpha;
583 extern char engineversion[40];
584 void Con_DrawConsole (int lines)
592 // draw the background
593 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, 1, 1, 1, scr_conalpha.value * lines / vid.conheight, 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]);