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.
29 float con_cursorspeed = 4;
31 #define CON_TEXTSIZE 131072
33 // total lines in console scrollback
35 // lines up from bottom to display
37 // where next message will be printed
39 // offset in current line for next print
44 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
45 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
46 cvar_t logfile = {0, "logfile","0"};
48 #define MAX_NOTIFYLINES 32
49 // cl.time time the line was generated for transparent notify lines
50 float con_times[MAX_NOTIFYLINES];
54 qboolean con_debuglog;
56 #define MAXCMDLINE 256
57 extern char key_lines[32][MAXCMDLINE];
59 extern int key_linepos;
60 extern int key_insert;
63 qboolean con_initialized;
65 mempool_t *console_mempool;
67 extern void M_Menu_Main_f (void);
74 void Con_ToggleConsole_f (void)
76 // toggle the 'user wants console' bit
77 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
78 memset (con_times, 0, sizeof(con_times));
86 void Con_Clear_f (void)
89 memset (con_text, ' ', CON_TEXTSIZE);
98 void Con_ClearNotify (void)
102 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
112 void Con_MessageMode_f (void)
114 key_dest = key_message;
124 void Con_MessageMode2_f (void)
126 key_dest = key_message;
135 If the line width has changed, reformat the buffer.
138 void Con_CheckResize (void)
140 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
141 char tbuf[CON_TEXTSIZE];
143 width = (vid.conwidth >> 3);
145 if (width == con_linewidth)
148 if (width < 1) // video hasn't been initialized yet
151 con_linewidth = width;
152 con_totallines = CON_TEXTSIZE / con_linewidth;
153 memset (con_text, ' ', CON_TEXTSIZE);
157 oldwidth = con_linewidth;
158 con_linewidth = width;
159 oldtotallines = con_totallines;
160 con_totallines = CON_TEXTSIZE / con_linewidth;
161 numlines = oldtotallines;
163 if (con_totallines < numlines)
164 numlines = con_totallines;
168 if (con_linewidth < numchars)
169 numchars = con_linewidth;
171 memcpy (tbuf, con_text, CON_TEXTSIZE);
172 memset (con_text, ' ', CON_TEXTSIZE);
174 for (i=0 ; i<numlines ; i++)
176 for (j=0 ; j<numchars ; j++)
178 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
179 tbuf[((con_current - i + oldtotallines) %
180 oldtotallines) * oldwidth + j];
188 con_current = con_totallines - 1;
192 void Con_InitLogging (void)
194 #define MAXGAMEDIRLEN 1000
195 char temp[MAXGAMEDIRLEN+1];
196 char *t2 = "/qconsole.log";
198 con_debuglog = COM_CheckParm("-condebug");
201 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
203 sprintf (temp, "%s%s", fs_gamedir, t2);
217 Cvar_RegisterVariable(&logfile);
219 console_mempool = Mem_AllocPool("console");
220 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
221 memset (con_text, ' ', CON_TEXTSIZE);
225 Con_Print("Console initialized.\n");
228 // register our commands
230 Cvar_RegisterVariable (&con_notifytime);
231 Cvar_RegisterVariable (&con_notify);
233 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
234 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
235 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
236 Cmd_AddCommand ("clear", Con_Clear_f);
237 con_initialized = true;
246 void Con_Linefeed (void)
250 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
257 Handles cursor positioning, line wrapping, etc
258 All console printing must go through this in order to be displayed
259 If no console is visible, the notify window will pop up.
262 void Con_PrintToHistory(const char *txt)
271 mask = 128; // go to colored text
272 S_LocalSound ("misc/talk.wav");
276 else if (txt[0] == 2)
278 mask = 128; // go to colored text
288 for (l=0 ; l< con_linewidth ; l++)
293 if (l != con_linewidth && (con_x + l > con_linewidth) )
308 // mark time for transparent overlay
309 if (con_current >= 0)
311 if (con_notify.integer < 0)
312 Cvar_SetValueQuick(&con_notify, 0);
313 if (con_notify.integer > MAX_NOTIFYLINES)
314 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
315 if (con_notify.integer > 0)
316 con_times[con_current % con_notify.integer] = cl.time;
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)
343 // LordHavoc: increased from 4096 to 16384
344 #define MAXPRINTMSG 16384
351 void Con_LogPrint(const char *logfilename, const char *msg)
354 file = FS_Open(logfilename, "at", true);
367 void Con_LogPrintf(const char *logfilename, const char *fmt, ...)
370 char msg[MAXPRINTMSG];
372 va_start(argptr,fmt);
373 vsprintf(msg,fmt,argptr);
376 Con_LogPrint(logfilename, msg);
383 Prints to all appropriate console targets
386 void Con_Print(const char *msg)
388 // also echo to debugging console
391 // log all messages to file
393 Con_LogPrint("qconsole.log", msg);
395 if (!con_initialized)
398 if (cls.state == ca_dedicated)
399 return; // no graphics mode
401 // write it to the scrollable buffer
402 Con_PrintToHistory(msg);
409 Prints to all appropriate console targets
412 void Con_Printf(const char *fmt, ...)
415 char msg[MAXPRINTMSG];
417 va_start(argptr,fmt);
418 vsprintf(msg,fmt,argptr);
428 A Con_Print that only shows up if the "developer" cvar is set
431 void Con_DPrint(const char *msg)
433 if (!developer.integer)
434 return; // don't confuse non-developers with techie stuff...
442 A Con_Printf that only shows up if the "developer" cvar is set
445 void Con_DPrintf(const char *fmt, ...)
448 char msg[MAXPRINTMSG];
450 if (!developer.integer)
451 return; // don't confuse non-developers with techie stuff...
453 va_start(argptr,fmt);
454 vsprintf(msg,fmt,argptr);
465 Okay to call even when the screen can't be updated
468 void Con_SafePrint(const char *msg)
477 Okay to call even when the screen can't be updated
480 void Con_SafePrintf(const char *fmt, ...)
483 char msg[MAXPRINTMSG];
485 va_start(argptr,fmt);
486 vsprintf(msg,fmt,argptr);
494 ==============================================================================
498 ==============================================================================
506 The input line scrolls horizontally if typing goes beyond the right edge
508 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
511 void Con_DrawInput (void)
513 char editlinecopy[257], *text;
515 if (!key_consoleactive)
516 return; // don't draw anything
518 text = strcpy(editlinecopy, key_lines[edit_line]);
520 // Advanced Console Editing by Radix radix@planetquake.com
521 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
522 // use strlen of edit_line instead of key_linepos to allow editing
523 // of early characters w/o erasing
525 // add the cursor frame
526 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
527 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
529 text[key_linepos + 1] = 0;
531 // prestep if horizontally scrolling
532 if (key_linepos >= con_linewidth)
533 text += 1 + key_linepos - con_linewidth;
536 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
539 key_lines[edit_line][key_linepos] = 0;
547 Draws the last few lines of output transparently over the game top
550 void Con_DrawNotify (void)
556 extern char chat_buffer[];
559 if (con_notify.integer < 0)
560 Cvar_SetValueQuick(&con_notify, 0);
561 if (con_notify.integer > MAX_NOTIFYLINES)
562 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
564 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
568 time = con_times[i % con_notify.integer];
571 time = cl.time - time;
572 if (time > con_notifytime.value)
574 text = con_text + (i % con_totallines)*con_linewidth;
578 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
584 if (key_dest == key_message)
590 // LordHavoc: speedup, and other improvements
592 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
594 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
595 while (strlen(temptext) >= (size_t) con_linewidth)
597 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
598 strcpy(temptext, &temptext[con_linewidth]);
601 if (strlen(temptext) > 0)
603 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
613 Draws the console with the solid background
614 The typing input line at the bottom should only be drawn if typing is allowed
617 extern char engineversion[40];
618 void Con_DrawConsole (int lines)
626 // draw the background
627 if (scr_conbrightness.value >= 0.01f)
628 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);
630 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
631 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
634 con_vislines = lines;
636 rows = (lines-16)>>3; // rows of text to draw
637 y = lines - 16 - (rows<<3); // may start slightly negative
639 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
641 j = max(i - con_backscroll, 0);
642 text = con_text + (j % con_totallines)*con_linewidth;
644 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
647 // draw the input prompt, user text, and cursor if desired
654 New function for tab-completion system
656 MEGA Thanks to Taniwha
659 void Con_DisplayList(const char **list)
661 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
662 const char **walk = list;
674 if (pos + maxlen >= width) {
680 for (i = 0; i < (maxlen - len); i++)
692 Con_CompleteCommandLine
694 New function for tab-completion system
696 Thanks to Fett erich@heintz.com
700 void Con_CompleteCommandLine (void)
702 const char *cmd = "", *s;
703 const char **list[3] = {0, 0, 0};
704 int c, v, a, i, cmd_len;
706 s = key_lines[edit_line] + 1;
707 // Count number of possible matches
708 c = Cmd_CompleteCountPossible(s);
709 v = Cvar_CompleteCountPossible(s);
710 a = Cmd_CompleteAliasCountPossible(s);
712 if (!(c + v + a)) // No possible matches
715 if (c + v + a == 1) {
717 list[0] = Cmd_CompleteBuildList(s);
719 list[0] = Cvar_CompleteBuildList(s);
721 list[0] = Cmd_CompleteAliasBuildList(s);
723 cmd_len = strlen (cmd);
726 cmd = *(list[0] = Cmd_CompleteBuildList(s));
728 cmd = *(list[1] = Cvar_CompleteBuildList(s));
730 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
732 cmd_len = strlen (s);
734 for (i = 0; i < 3; i++) {
735 char ch = cmd[cmd_len];
736 const char **l = list[i];
738 while (*l && (*l)[cmd_len] == ch)
749 for (i = 0; i < con_linewidth - 4; i++)
753 // Print Possible Commands
755 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
756 Con_DisplayList(list[0]);
760 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
761 Con_DisplayList(list[1]);
765 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
766 Con_DisplayList(list[2]);
771 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
772 key_linepos = cmd_len + 1;
773 if (c + v + a == 1) {
774 key_lines[edit_line][key_linepos] = ' ';
777 key_lines[edit_line][key_linepos] = 0;
779 for (i = 0; i < 3; i++)
781 Mem_Free((void *)list[i]);