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 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_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 displayed
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_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] = 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 *msg)
362 file = FS_Open ("qconsole.log", "at", true);
365 FS_Printf (file, "%s", msg);
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
397 if (!con_initialized)
400 if (cls.state == ca_dedicated)
401 return; // no graphics mode
403 // write it to the scrollable buffer
411 A Con_Printf that only shows up if the "developer" cvar is set
414 void Con_DPrintf (const char *fmt, ...)
417 char msg[MAXPRINTMSG];
419 if (!developer.integer)
420 return; // don't confuse non-developers with techie stuff...
422 va_start (argptr,fmt);
423 vsprintf (msg,fmt,argptr);
426 Con_Printf ("%s", msg);
434 Okay to call even when the screen can't be updated
437 void Con_SafePrintf (const char *fmt, ...)
442 va_start (argptr,fmt);
443 vsprintf (msg,fmt,argptr);
446 Con_Printf ("%s", msg);
451 ==============================================================================
455 ==============================================================================
463 The input line scrolls horizontally if typing goes beyond the right edge
465 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
468 void Con_DrawInput (void)
470 char editlinecopy[256], *text;
472 if (!key_consoleactive)
473 return; // don't draw anything
475 text = strcpy(editlinecopy, key_lines[edit_line]);
477 // Advanced Console Editing by Radix radix@planetquake.com
478 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
479 // use strlen of edit_line instead of key_linepos to allow editing
480 // of early characters w/o erasing
482 // add the cursor frame
483 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
484 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
486 text[key_linepos + 1] = 0;
488 // prestep if horizontally scrolling
489 if (key_linepos >= con_linewidth)
490 text += 1 + key_linepos - con_linewidth;
493 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
496 key_lines[edit_line][key_linepos] = 0;
504 Draws the last few lines of output transparently over the game top
507 void Con_DrawNotify (void)
513 extern char chat_buffer[];
516 if (con_notify.integer < 0)
517 Cvar_SetValueQuick(&con_notify, 0);
518 if (con_notify.integer > MAX_NOTIFYLINES)
519 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
521 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
525 time = con_times[i % con_notify.integer];
528 time = realtime - time;
529 if (time > con_notifytime.value)
531 text = con_text + (i % con_totallines)*con_linewidth;
535 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
541 if (key_dest == key_message)
547 // LordHavoc: speedup, and other improvements
549 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
551 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
552 while (strlen(temptext) >= (size_t) con_linewidth)
554 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
555 strcpy(temptext, &temptext[con_linewidth]);
558 if (strlen(temptext) > 0)
560 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
570 Draws the console with the solid background
571 The typing input line at the bottom should only be drawn if typing is allowed
574 extern char engineversion[40];
575 void Con_DrawConsole (int lines)
583 // draw the background
584 if (scr_conbrightness.value >= 0.01f)
585 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);
587 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
588 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
591 con_vislines = lines;
593 rows = (lines-16)>>3; // rows of text to draw
594 y = lines - 16 - (rows<<3); // may start slightly negative
596 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
598 j = max(i - con_backscroll, 0);
599 text = con_text + (j % con_totallines)*con_linewidth;
601 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
604 // draw the input prompt, user text, and cursor if desired
611 New function for tab-completion system
613 MEGA Thanks to Taniwha
616 void Con_DisplayList(const char **list)
618 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
619 const char **walk = list;
631 if (pos + maxlen >= width) {
636 Con_Printf("%s", *list);
637 for (i = 0; i < (maxlen - len); i++)
649 Con_CompleteCommandLine
651 New function for tab-completion system
653 Thanks to Fett erich@heintz.com
657 void Con_CompleteCommandLine (void)
659 const char *cmd = "", *s;
660 const char **list[3] = {0, 0, 0};
661 int c, v, a, i, cmd_len;
663 s = key_lines[edit_line] + 1;
664 // Count number of possible matches
665 c = Cmd_CompleteCountPossible(s);
666 v = Cvar_CompleteCountPossible(s);
667 a = Cmd_CompleteAliasCountPossible(s);
669 if (!(c + v + a)) // No possible matches
672 if (c + v + a == 1) {
674 list[0] = Cmd_CompleteBuildList(s);
676 list[0] = Cvar_CompleteBuildList(s);
678 list[0] = Cmd_CompleteAliasBuildList(s);
680 cmd_len = strlen (cmd);
683 cmd = *(list[0] = Cmd_CompleteBuildList(s));
685 cmd = *(list[1] = Cvar_CompleteBuildList(s));
687 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
689 cmd_len = strlen (s);
691 for (i = 0; i < 3; i++) {
692 char ch = cmd[cmd_len];
693 const char **l = list[i];
695 while (*l && (*l)[cmd_len] == ch)
706 for (i = 0; i < con_linewidth - 4; i++)
710 // Print Possible Commands
712 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
713 Con_DisplayList(list[0]);
717 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
718 Con_DisplayList(list[1]);
722 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
723 Con_DisplayList(list[2]);
728 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
729 key_linepos = cmd_len + 1;
730 if (c + v + a == 1) {
731 key_lines[edit_line][key_linepos] = ' ';
734 key_lines[edit_line][key_linepos] = 0;
736 for (i = 0; i < 3; i++)
738 Mem_Free((void *)list[i]);