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 void Con_MessageMode_f (void)
125 key_dest = key_message;
135 void Con_MessageMode2_f (void)
137 key_dest = key_message;
146 If the line width has changed, reformat the buffer.
149 void Con_CheckResize (void)
151 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
152 char tbuf[CON_TEXTSIZE];
154 width = (vid.conwidth >> 3);
156 if (width == con_linewidth)
159 if (width < 1) // video hasn't been initialized yet
162 con_linewidth = width;
163 con_totallines = CON_TEXTSIZE / con_linewidth;
164 memset (con_text, ' ', CON_TEXTSIZE);
168 oldwidth = con_linewidth;
169 con_linewidth = width;
170 oldtotallines = con_totallines;
171 con_totallines = CON_TEXTSIZE / con_linewidth;
172 numlines = oldtotallines;
174 if (con_totallines < numlines)
175 numlines = con_totallines;
179 if (con_linewidth < numchars)
180 numchars = con_linewidth;
182 memcpy (tbuf, con_text, CON_TEXTSIZE);
183 memset (con_text, ' ', CON_TEXTSIZE);
185 for (i=0 ; i<numlines ; i++)
187 for (j=0 ; j<numchars ; j++)
189 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
190 tbuf[((con_current - i + oldtotallines) %
191 oldtotallines) * oldwidth + j];
199 con_current = con_totallines - 1;
210 #define MAXGAMEDIRLEN 1000
211 char temp[MAXGAMEDIRLEN+1];
212 char *t2 = "/qconsole.log";
214 Cvar_RegisterVariable(&logfile);
215 con_debuglog = COM_CheckParm("-condebug");
219 if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
221 sprintf (temp, "%s%s", com_gamedir, t2);
227 console_mempool = Mem_AllocPool("console");
228 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
229 memset (con_text, ' ', CON_TEXTSIZE);
233 Con_Printf ("Console initialized.\n");
236 // register our commands
238 Cvar_RegisterVariable (&con_notifytime);
240 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
241 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
242 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
243 Cmd_AddCommand ("clear", Con_Clear_f);
244 con_initialized = true;
253 void Con_Linefeed (void)
257 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
264 Handles cursor positioning, line wrapping, etc
265 All console printing must go through this in order to be logged to disk
266 If no console is visible, the notify window will pop up.
269 void Con_Print (const char *txt)
278 mask = 128; // go to colored text
279 S_LocalSound ("misc/talk.wav");
283 else if (txt[0] == 2)
285 mask = 128; // go to colored text
295 for (l=0 ; l< con_linewidth ; l++)
300 if (l != con_linewidth && (con_x + l > con_linewidth) )
315 // mark time for transparent overlay
316 if (con_current >= 0)
317 con_times[con_current % NUM_CON_TIMES] = realtime;
331 default: // display character and advance
332 y = con_current % con_totallines;
333 con_text[y*con_linewidth+con_x] = c | mask;
335 if (con_x >= con_linewidth)
349 void Con_DebugLog(const char *file, const char *fmt, ...)
354 fd = fopen(file, "at");
355 va_start(argptr, fmt);
356 vfprintf (fd, fmt, argptr);
366 Handles cursor positioning, line wrapping, etc
369 // LordHavoc: increased from 4096 to 16384
370 #define MAXPRINTMSG 16384
371 // FIXME: make a buffer size safe vsprintf?
372 void Con_Printf (const char *fmt, ...)
375 char msg[MAXPRINTMSG];
377 va_start (argptr,fmt);
378 vsprintf (msg,fmt,argptr);
381 // also echo to debugging console
382 Sys_Printf ("%s", msg);
384 // log all messages to file
387 // can't use va() here because it might overwrite other important things
388 char logname[MAX_OSPATH];
389 sprintf(logname, "%s/qconsole.log", com_gamedir);
390 Con_DebugLog(logname, "%s", msg);
393 if (!con_initialized)
396 if (cls.state == ca_dedicated)
397 return; // no graphics mode
399 // write it to the scrollable buffer
407 A Con_Printf that only shows up if the "developer" cvar is set
410 void Con_DPrintf (const char *fmt, ...)
413 char msg[MAXPRINTMSG];
415 if (!developer.integer)
416 return; // don't confuse non-developers with techie stuff...
418 va_start (argptr,fmt);
419 vsprintf (msg,fmt,argptr);
422 Con_Printf ("%s", msg);
430 Okay to call even when the screen can't be updated
433 void Con_SafePrintf (const char *fmt, ...)
438 va_start (argptr,fmt);
439 vsprintf (msg,fmt,argptr);
442 Con_Printf ("%s", msg);
447 ==============================================================================
451 ==============================================================================
459 The input line scrolls horizontally if typing goes beyond the right edge
461 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
464 void Con_DrawInput (void)
466 char editlinecopy[256], *text;
468 if (!key_consoleactive)
469 return; // don't draw anything
471 text = strcpy(editlinecopy, key_lines[edit_line]);
473 // Advanced Console Editing by Radix radix@planetquake.com
474 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
475 // use strlen of edit_line instead of key_linepos to allow editing
476 // of early characters w/o erasing
478 // add the cursor frame
479 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
480 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
482 text[key_linepos + 1] = 0;
484 // prestep if horizontally scrolling
485 if (key_linepos >= con_linewidth)
486 text += 1 + key_linepos - con_linewidth;
489 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
492 key_lines[edit_line][key_linepos] = 0;
500 Draws the last few lines of output transparently over the game top
503 void Con_DrawNotify (void)
509 extern char chat_buffer[];
513 for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
517 time = con_times[i % NUM_CON_TIMES];
520 time = realtime - time;
521 if (time > con_notifytime.value)
523 text = con_text + (i % con_totallines)*con_linewidth;
527 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
533 if (key_dest == key_message)
539 // LordHavoc: speedup, and other improvements
541 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
543 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
544 while (strlen(temptext) >= (size_t) con_linewidth)
546 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
547 strcpy(temptext, &temptext[con_linewidth]);
550 if (strlen(temptext) > 0)
552 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
557 if (v > con_notifylines)
565 Draws the console with the solid background
566 The typing input line at the bottom should only be drawn if typing is allowed
569 extern cvar_t scr_conalpha;
570 extern char engineversion[40];
571 void Con_DrawConsole (int lines)
579 // draw the background
580 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, 1, 1, 1, scr_conalpha.value * lines / vid.conheight, 0);
581 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
584 con_vislines = lines;
586 rows = (lines-16)>>3; // rows of text to draw
587 y = lines - 16 - (rows<<3); // may start slightly negative
589 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
591 j = max(i - con_backscroll, 0);
592 text = con_text + (j % con_totallines)*con_linewidth;
594 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
597 // draw the input prompt, user text, and cursor if desired
604 New function for tab-completion system
606 MEGA Thanks to Taniwha
609 void Con_DisplayList(const char **list)
611 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
612 const char **walk = list;
624 if (pos + maxlen >= width) {
629 Con_Printf("%s", *list);
630 for (i = 0; i < (maxlen - len); i++)
642 Con_CompleteCommandLine
644 New function for tab-completion system
646 Thanks to Fett erich@heintz.com
650 void Con_CompleteCommandLine (void)
652 const char *cmd = "", *s;
653 const char **list[3] = {0, 0, 0};
654 int c, v, a, i, cmd_len;
656 s = key_lines[edit_line] + 1;
657 // Count number of possible matches
658 c = Cmd_CompleteCountPossible(s);
659 v = Cvar_CompleteCountPossible(s);
660 a = Cmd_CompleteAliasCountPossible(s);
662 if (!(c + v + a)) // No possible matches
665 if (c + v + a == 1) {
667 list[0] = Cmd_CompleteBuildList(s);
669 list[0] = Cvar_CompleteBuildList(s);
671 list[0] = Cmd_CompleteAliasBuildList(s);
673 cmd_len = strlen (cmd);
676 cmd = *(list[0] = Cmd_CompleteBuildList(s));
678 cmd = *(list[1] = Cvar_CompleteBuildList(s));
680 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
682 cmd_len = strlen (s);
684 for (i = 0; i < 3; i++) {
685 char ch = cmd[cmd_len];
686 const char **l = list[i];
688 while (*l && (*l)[cmd_len] == ch)
699 for (i = 0; i < con_linewidth - 4; i++)
703 // Print Possible Commands
705 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
706 Con_DisplayList(list[0]);
710 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
711 Con_DisplayList(list[1]);
715 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
716 Con_DisplayList(list[2]);
721 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
722 key_linepos = cmd_len + 1;
723 if (c + v + a == 1) {
724 key_lines[edit_line][key_linepos] = ' ';
727 key_lines[edit_line][key_linepos] = 0;
729 for (i = 0; i < 3; i++)
731 Mem_Free((void *)list[i]);