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 logfile = {0, "logfile","0"};
56 #define NUM_CON_TIMES 4
57 // realtime time the line was generated for transparent notify lines
58 float con_times[NUM_CON_TIMES];
62 qboolean con_debuglog;
64 #define MAXCMDLINE 256
65 extern char key_lines[32][MAXCMDLINE];
67 extern int key_linepos;
68 extern int key_insert;
71 qboolean con_initialized;
73 mempool_t *console_mempool;
75 // scan lines to clear for notify lines
78 extern void M_Menu_Main_f (void);
85 void Con_ToggleConsole_f (void)
87 // toggle the 'user wants console' bit
88 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
89 memset (con_times, 0, sizeof(con_times));
97 void Con_Clear_f (void)
100 memset (con_text, ' ', CON_TEXTSIZE);
109 void Con_ClearNotify (void)
113 for (i=0 ; i<NUM_CON_TIMES ; i++)
123 extern qboolean team_message;
125 void Con_MessageMode_f (void)
127 key_dest = key_message;
128 team_message = false;
137 void Con_MessageMode2_f (void)
139 key_dest = key_message;
148 If the line width has changed, reformat the buffer.
151 void Con_CheckResize (void)
153 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
154 char tbuf[CON_TEXTSIZE];
156 width = (vid.conwidth >> 3);
158 if (width == con_linewidth)
161 if (width < 1) // video hasn't been initialized yet
164 con_linewidth = width;
165 con_totallines = CON_TEXTSIZE / con_linewidth;
166 memset (con_text, ' ', CON_TEXTSIZE);
170 oldwidth = con_linewidth;
171 con_linewidth = width;
172 oldtotallines = con_totallines;
173 con_totallines = CON_TEXTSIZE / con_linewidth;
174 numlines = oldtotallines;
176 if (con_totallines < numlines)
177 numlines = con_totallines;
181 if (con_linewidth < numchars)
182 numchars = con_linewidth;
184 memcpy (tbuf, con_text, CON_TEXTSIZE);
185 memset (con_text, ' ', CON_TEXTSIZE);
187 for (i=0 ; i<numlines ; i++)
189 for (j=0 ; j<numchars ; j++)
191 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
192 tbuf[((con_current - i + oldtotallines) %
193 oldtotallines) * oldwidth + j];
201 con_current = con_totallines - 1;
212 #define MAXGAMEDIRLEN 1000
213 char temp[MAXGAMEDIRLEN+1];
214 char *t2 = "/qconsole.log";
216 Cvar_RegisterVariable(&logfile);
217 con_debuglog = COM_CheckParm("-condebug");
221 if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
223 sprintf (temp, "%s%s", com_gamedir, t2);
229 console_mempool = Mem_AllocPool("console");
230 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
231 memset (con_text, ' ', CON_TEXTSIZE);
235 Con_Printf ("Console initialized.\n");
238 // register our commands
240 Cvar_RegisterVariable (&con_notifytime);
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)
319 con_times[con_current % NUM_CON_TIMES] = realtime;
333 default: // display character and advance
334 y = con_current % con_totallines;
335 con_text[y*con_linewidth+con_x] = c | mask;
337 if (con_x >= con_linewidth)
351 void Con_DebugLog(const char *file, const char *fmt, ...)
356 fd = fopen(file, "at");
357 va_start(argptr, fmt);
358 vfprintf (fd, fmt, argptr);
368 Handles cursor positioning, line wrapping, etc
371 // LordHavoc: increased from 4096 to 16384
372 #define MAXPRINTMSG 16384
373 // FIXME: make a buffer size safe vsprintf?
374 void Con_Printf (const char *fmt, ...)
377 char msg[MAXPRINTMSG];
379 va_start (argptr,fmt);
380 vsprintf (msg,fmt,argptr);
383 // also echo to debugging console
384 Sys_Printf ("%s", msg);
386 // log all messages to file
389 // can't use va() here because it might overwrite other important things
390 char logname[MAX_OSPATH];
391 sprintf(logname, "%s/qconsole.log", com_gamedir);
392 Con_DebugLog(logname, "%s", msg);
395 if (!con_initialized)
398 if (cls.state == ca_dedicated)
399 return; // no graphics mode
401 // write it to the scrollable buffer
409 A Con_Printf that only shows up if the "developer" cvar is set
412 void Con_DPrintf (const char *fmt, ...)
415 char msg[MAXPRINTMSG];
417 if (!developer.integer)
418 return; // don't confuse non-developers with techie stuff...
420 va_start (argptr,fmt);
421 vsprintf (msg,fmt,argptr);
424 Con_Printf ("%s", msg);
432 Okay to call even when the screen can't be updated
435 void Con_SafePrintf (const char *fmt, ...)
440 va_start (argptr,fmt);
441 vsprintf (msg,fmt,argptr);
444 Con_Printf ("%s", msg);
449 ==============================================================================
453 ==============================================================================
461 The input line scrolls horizontally if typing goes beyond the right edge
463 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
466 void Con_DrawInput (void)
468 char editlinecopy[256], *text;
470 if (!key_consoleactive)
471 return; // don't draw anything
473 text = strcpy(editlinecopy, key_lines[edit_line]);
475 // Advanced Console Editing by Radix radix@planetquake.com
476 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
477 // use strlen of edit_line instead of key_linepos to allow editing
478 // of early characters w/o erasing
480 // add the cursor frame
481 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
482 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
484 text[key_linepos + 1] = 0;
486 // prestep if horizontally scrolling
487 if (key_linepos >= con_linewidth)
488 text += 1 + key_linepos - con_linewidth;
491 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
494 key_lines[edit_line][key_linepos] = 0;
502 Draws the last few lines of output transparently over the game top
505 void Con_DrawNotify (void)
511 extern char chat_buffer[];
515 for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
519 time = con_times[i % NUM_CON_TIMES];
522 time = realtime - time;
523 if (time > con_notifytime.value)
525 text = con_text + (i % con_totallines)*con_linewidth;
529 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
535 if (key_dest == key_message)
541 // LordHavoc: speedup, and other improvements
543 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
545 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
546 while (strlen(temptext) >= con_linewidth)
548 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
549 strcpy(temptext, &temptext[con_linewidth]);
552 if (strlen(temptext) > 0)
554 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
559 if (v > con_notifylines)
567 Draws the console with the solid background
568 The typing input line at the bottom should only be drawn if typing is allowed
571 extern cvar_t scr_conalpha;
572 extern char engineversion[40];
573 void Con_DrawConsole (int lines)
581 // draw the background
582 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, 1, 1, 1, scr_conalpha.value * lines / vid.conheight, 0);
583 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
586 con_vislines = lines;
588 rows = (lines-16)>>3; // rows of text to draw
589 y = lines - 16 - (rows<<3); // may start slightly negative
591 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
593 j = max(i - con_backscroll, 0);
594 text = con_text + (j % con_totallines)*con_linewidth;
596 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
599 // draw the input prompt, user text, and cursor if desired
606 New function for tab-completion system
608 MEGA Thanks to Taniwha
611 void Con_DisplayList(const char **list)
613 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
614 const char **walk = list;
626 if (pos + maxlen >= width) {
631 Con_Printf("%s", *list);
632 for (i = 0; i < (maxlen - len); i++)
644 Con_CompleteCommandLine
646 New function for tab-completion system
648 Thanks to Fett erich@heintz.com
652 void Con_CompleteCommandLine (void)
654 const char *cmd = "", *s;
655 const char **list[3] = {0, 0, 0};
656 int c, v, a, i, cmd_len;
658 s = key_lines[edit_line] + 1;
659 // Count number of possible matches
660 c = Cmd_CompleteCountPossible(s);
661 v = Cvar_CompleteCountPossible(s);
662 a = Cmd_CompleteAliasCountPossible(s);
664 if (!(c + v + a)) // No possible matches
667 if (c + v + a == 1) {
669 list[0] = Cmd_CompleteBuildList(s);
671 list[0] = Cvar_CompleteBuildList(s);
673 list[0] = Cmd_CompleteAliasBuildList(s);
675 cmd_len = strlen (cmd);
678 cmd = *(list[0] = Cmd_CompleteBuildList(s));
680 cmd = *(list[1] = Cvar_CompleteBuildList(s));
682 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
684 cmd_len = strlen (s);
686 for (i = 0; i < 3; i++) {
687 char ch = cmd[cmd_len];
688 const char **l = list[i];
690 while (*l && (*l)[cmd_len] == ch)
701 for (i = 0; i < con_linewidth - 4; i++)
705 // Print Possible Commands
707 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
708 Con_DisplayList(list[0]);
712 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
713 Con_DisplayList(list[1]);
717 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
718 Con_DisplayList(list[2]);
723 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
724 key_linepos = cmd_len + 1;
725 if (c + v + a == 1) {
726 key_lines[edit_line][key_linepos] = ' ';
729 key_lines[edit_line][key_linepos] = 0;
731 for (i = 0; i < 3; i++)