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 // cl.time 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 extern void M_Menu_Main_f (void);
83 void Con_ToggleConsole_f (void)
85 // toggle the 'user wants console' bit
86 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
87 memset (con_times, 0, sizeof(con_times));
95 void Con_Clear_f (void)
98 memset (con_text, ' ', CON_TEXTSIZE);
107 void Con_ClearNotify (void)
111 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
121 void Con_MessageMode_f (void)
123 key_dest = key_message;
133 void Con_MessageMode2_f (void)
135 key_dest = key_message;
144 If the line width has changed, reformat the buffer.
147 void Con_CheckResize (void)
149 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
150 char tbuf[CON_TEXTSIZE];
152 width = (vid.conwidth >> 3);
154 if (width == con_linewidth)
157 if (width < 1) // video hasn't been initialized yet
160 con_linewidth = width;
161 con_totallines = CON_TEXTSIZE / con_linewidth;
162 memset (con_text, ' ', CON_TEXTSIZE);
166 oldwidth = con_linewidth;
167 con_linewidth = width;
168 oldtotallines = con_totallines;
169 con_totallines = CON_TEXTSIZE / con_linewidth;
170 numlines = oldtotallines;
172 if (con_totallines < numlines)
173 numlines = con_totallines;
177 if (con_linewidth < numchars)
178 numchars = con_linewidth;
180 memcpy (tbuf, con_text, CON_TEXTSIZE);
181 memset (con_text, ' ', CON_TEXTSIZE);
183 for (i=0 ; i<numlines ; i++)
185 for (j=0 ; j<numchars ; j++)
187 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
188 tbuf[((con_current - i + oldtotallines) %
189 oldtotallines) * oldwidth + j];
197 con_current = con_totallines - 1;
201 void Con_InitLogging (void)
203 #define MAXGAMEDIRLEN 1000
204 char temp[MAXGAMEDIRLEN+1];
205 char *t2 = "/qconsole.log";
207 con_debuglog = COM_CheckParm("-condebug");
210 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
212 sprintf (temp, "%s%s", fs_gamedir, t2);
226 Cvar_RegisterVariable(&logfile);
228 console_mempool = Mem_AllocPool("console");
229 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
230 memset (con_text, ' ', CON_TEXTSIZE);
234 Con_Print("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 displayed
268 If no console is visible, the notify window will pop up.
271 void Con_PrintToHistory(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_notify.integer > MAX_NOTIFYLINES)
323 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
324 if (con_notify.integer > 0)
325 con_times[con_current % con_notify.integer] = cl.time;
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)
352 // LordHavoc: increased from 4096 to 16384
353 #define MAXPRINTMSG 16384
360 void Con_LogPrint(const char *logfilename, const char *msg)
363 file = FS_Open(logfilename, "at", true);
376 void Con_LogPrintf(const char *logfilename, const char *fmt, ...)
379 char msg[MAXPRINTMSG];
381 va_start(argptr,fmt);
382 vsprintf(msg,fmt,argptr);
385 Con_LogPrint(logfilename, msg);
392 Prints to all appropriate console targets
395 void Con_Print(const char *msg)
397 // also echo to debugging console
400 // log all messages to file
402 Con_LogPrint("qconsole.log", msg);
404 if (!con_initialized)
407 if (cls.state == ca_dedicated)
408 return; // no graphics mode
410 // write it to the scrollable buffer
411 Con_PrintToHistory(msg);
418 Prints to all appropriate console targets
421 void Con_Printf(const char *fmt, ...)
424 char msg[MAXPRINTMSG];
426 va_start(argptr,fmt);
427 vsprintf(msg,fmt,argptr);
437 A Con_Print that only shows up if the "developer" cvar is set
440 void Con_DPrint(const char *msg)
442 if (!developer.integer)
443 return; // don't confuse non-developers with techie stuff...
451 A Con_Printf that only shows up if the "developer" cvar is set
454 void Con_DPrintf(const char *fmt, ...)
457 char msg[MAXPRINTMSG];
459 if (!developer.integer)
460 return; // don't confuse non-developers with techie stuff...
462 va_start(argptr,fmt);
463 vsprintf(msg,fmt,argptr);
474 Okay to call even when the screen can't be updated
477 void Con_SafePrint(const char *msg)
486 Okay to call even when the screen can't be updated
489 void Con_SafePrintf(const char *fmt, ...)
492 char msg[MAXPRINTMSG];
494 va_start(argptr,fmt);
495 vsprintf(msg,fmt,argptr);
503 ==============================================================================
507 ==============================================================================
515 The input line scrolls horizontally if typing goes beyond the right edge
517 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
520 void Con_DrawInput (void)
522 char editlinecopy[257], *text;
524 if (!key_consoleactive)
525 return; // don't draw anything
527 text = strcpy(editlinecopy, key_lines[edit_line]);
529 // Advanced Console Editing by Radix radix@planetquake.com
530 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
531 // use strlen of edit_line instead of key_linepos to allow editing
532 // of early characters w/o erasing
534 // add the cursor frame
535 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
536 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
538 text[key_linepos + 1] = 0;
540 // prestep if horizontally scrolling
541 if (key_linepos >= con_linewidth)
542 text += 1 + key_linepos - con_linewidth;
545 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
548 key_lines[edit_line][key_linepos] = 0;
556 Draws the last few lines of output transparently over the game top
559 void Con_DrawNotify (void)
565 extern char chat_buffer[];
568 if (con_notify.integer < 0)
569 Cvar_SetValueQuick(&con_notify, 0);
570 if (con_notify.integer > MAX_NOTIFYLINES)
571 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
573 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
577 time = con_times[i % con_notify.integer];
580 time = cl.time - time;
581 if (time > con_notifytime.value)
583 text = con_text + (i % con_totallines)*con_linewidth;
587 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
593 if (key_dest == key_message)
599 // LordHavoc: speedup, and other improvements
601 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
603 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
604 while (strlen(temptext) >= (size_t) con_linewidth)
606 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
607 strcpy(temptext, &temptext[con_linewidth]);
610 if (strlen(temptext) > 0)
612 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
622 Draws the console with the solid background
623 The typing input line at the bottom should only be drawn if typing is allowed
626 extern char engineversion[40];
627 void Con_DrawConsole (int lines)
635 // draw the background
636 if (scr_conbrightness.value >= 0.01f)
637 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);
639 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
640 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
643 con_vislines = lines;
645 rows = (lines-16)>>3; // rows of text to draw
646 y = lines - 16 - (rows<<3); // may start slightly negative
648 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
650 j = max(i - con_backscroll, 0);
651 text = con_text + (j % con_totallines)*con_linewidth;
653 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
656 // draw the input prompt, user text, and cursor if desired
663 New function for tab-completion system
665 MEGA Thanks to Taniwha
668 void Con_DisplayList(const char **list)
670 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
671 const char **walk = list;
683 if (pos + maxlen >= width) {
689 for (i = 0; i < (maxlen - len); i++)
701 Con_CompleteCommandLine
703 New function for tab-completion system
705 Thanks to Fett erich@heintz.com
709 void Con_CompleteCommandLine (void)
711 const char *cmd = "", *s;
712 const char **list[3] = {0, 0, 0};
713 int c, v, a, i, cmd_len;
715 s = key_lines[edit_line] + 1;
716 // Count number of possible matches
717 c = Cmd_CompleteCountPossible(s);
718 v = Cvar_CompleteCountPossible(s);
719 a = Cmd_CompleteAliasCountPossible(s);
721 if (!(c + v + a)) // No possible matches
724 if (c + v + a == 1) {
726 list[0] = Cmd_CompleteBuildList(s);
728 list[0] = Cvar_CompleteBuildList(s);
730 list[0] = Cmd_CompleteAliasBuildList(s);
732 cmd_len = strlen (cmd);
735 cmd = *(list[0] = Cmd_CompleteBuildList(s));
737 cmd = *(list[1] = Cvar_CompleteBuildList(s));
739 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
741 cmd_len = strlen (s);
743 for (i = 0; i < 3; i++) {
744 char ch = cmd[cmd_len];
745 const char **l = list[i];
747 while (*l && (*l)[cmd_len] == ch)
758 for (i = 0; i < con_linewidth - 4; i++)
762 // Print Possible Commands
764 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
765 Con_DisplayList(list[0]);
769 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
770 Con_DisplayList(list[1]);
774 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
775 Con_DisplayList(list[2]);
780 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
781 key_linepos = cmd_len + 1;
782 if (c + v + a == 1) {
783 key_lines[edit_line][key_linepos] = ' ';
786 key_lines[edit_line][key_linepos] = 0;
788 for (i = 0; i < 3; i++)
790 Mem_Free((void *)list[i]);