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"};
47 #define MAX_NOTIFYLINES 32
48 // cl.time time the line was generated for transparent notify lines
49 float con_times[MAX_NOTIFYLINES];
53 qboolean con_debuglog;
55 #define MAXCMDLINE 256
56 extern char key_lines[32][MAXCMDLINE];
58 extern int key_linepos;
59 extern int key_insert;
62 qboolean con_initialized;
64 mempool_t *console_mempool;
66 extern void M_Menu_Main_f (void);
73 void Con_ToggleConsole_f (void)
75 // toggle the 'user wants console' bit
76 key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
77 memset (con_times, 0, sizeof(con_times));
85 void Con_Clear_f (void)
88 memset (con_text, ' ', CON_TEXTSIZE);
97 void Con_ClearNotify (void)
101 for (i=0 ; i<MAX_NOTIFYLINES ; i++)
111 void Con_MessageMode_f (void)
113 key_dest = key_message;
123 void Con_MessageMode2_f (void)
125 key_dest = key_message;
134 If the line width has changed, reformat the buffer.
137 void Con_CheckResize (void)
139 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
140 char tbuf[CON_TEXTSIZE];
142 width = (vid.conwidth >> 3);
144 if (width == con_linewidth)
147 if (width < 1) // video hasn't been initialized yet
150 con_linewidth = width;
151 con_totallines = CON_TEXTSIZE / con_linewidth;
152 memset (con_text, ' ', CON_TEXTSIZE);
156 oldwidth = con_linewidth;
157 con_linewidth = width;
158 oldtotallines = con_totallines;
159 con_totallines = CON_TEXTSIZE / con_linewidth;
160 numlines = oldtotallines;
162 if (con_totallines < numlines)
163 numlines = con_totallines;
167 if (con_linewidth < numchars)
168 numchars = con_linewidth;
170 memcpy (tbuf, con_text, CON_TEXTSIZE);
171 memset (con_text, ' ', CON_TEXTSIZE);
173 for (i=0 ; i<numlines ; i++)
175 for (j=0 ; j<numchars ; j++)
177 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
178 tbuf[((con_current - i + oldtotallines) %
179 oldtotallines) * oldwidth + j];
187 con_current = con_totallines - 1;
191 void Con_InitLogging (void)
193 #define MAXGAMEDIRLEN 1000
194 char temp[MAXGAMEDIRLEN+1];
195 char *t2 = "/qconsole.log";
197 con_debuglog = COM_CheckParm("-condebug");
200 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
202 sprintf (temp, "%s%s", fs_gamedir, t2);
215 console_mempool = Mem_AllocPool("console");
216 con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
217 memset (con_text, ' ', CON_TEXTSIZE);
221 Con_Print("Console initialized.\n");
224 // register our commands
226 Cvar_RegisterVariable (&con_notifytime);
227 Cvar_RegisterVariable (&con_notify);
229 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
230 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
231 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
232 Cmd_AddCommand ("clear", Con_Clear_f);
233 con_initialized = true;
242 void Con_Linefeed (void)
246 memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
253 Handles cursor positioning, line wrapping, etc
254 All console printing must go through this in order to be displayed
255 If no console is visible, the notify window will pop up.
258 void Con_PrintToHistory(const char *txt)
267 mask = 128; // go to colored text
268 S_LocalSound ("misc/talk.wav");
272 else if (txt[0] == 2)
274 mask = 128; // go to colored text
284 for (l=0 ; l< con_linewidth ; l++)
289 if (l != con_linewidth && (con_x + l > con_linewidth) )
304 // mark time for transparent overlay
305 if (con_current >= 0)
307 if (con_notify.integer < 0)
308 Cvar_SetValueQuick(&con_notify, 0);
309 if (con_notify.integer > MAX_NOTIFYLINES)
310 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
311 if (con_notify.integer > 0)
312 con_times[con_current % con_notify.integer] = cl.time;
327 default: // display character and advance
328 y = con_current % con_totallines;
329 con_text[y*con_linewidth+con_x] = c | mask;
331 if (con_x >= con_linewidth)
339 // LordHavoc: increased from 4096 to 16384
340 #define MAXPRINTMSG 16384
347 void Con_LogPrint(const char *logfilename, const char *msg)
350 file = FS_Open(logfilename, "at", true);
363 void Con_LogPrintf(const char *logfilename, const char *fmt, ...)
366 char msg[MAXPRINTMSG];
368 va_start(argptr,fmt);
369 vsprintf(msg,fmt,argptr);
372 Con_LogPrint(logfilename, msg);
379 Prints to all appropriate console targets
382 void Con_Print(const char *msg)
384 // also echo to debugging console
387 // log all messages to file
389 Con_LogPrint("qconsole.log", msg);
391 if (!con_initialized)
394 if (cls.state == ca_dedicated)
395 return; // no graphics mode
397 // write it to the scrollable buffer
398 Con_PrintToHistory(msg);
405 Prints to all appropriate console targets
408 void Con_Printf(const char *fmt, ...)
411 char msg[MAXPRINTMSG];
413 va_start(argptr,fmt);
414 vsprintf(msg,fmt,argptr);
424 A Con_Print that only shows up if the "developer" cvar is set
427 void Con_DPrint(const char *msg)
429 if (!developer.integer)
430 return; // don't confuse non-developers with techie stuff...
438 A Con_Printf that only shows up if the "developer" cvar is set
441 void Con_DPrintf(const char *fmt, ...)
444 char msg[MAXPRINTMSG];
446 if (!developer.integer)
447 return; // don't confuse non-developers with techie stuff...
449 va_start(argptr,fmt);
450 vsprintf(msg,fmt,argptr);
461 Okay to call even when the screen can't be updated
464 void Con_SafePrint(const char *msg)
473 Okay to call even when the screen can't be updated
476 void Con_SafePrintf(const char *fmt, ...)
479 char msg[MAXPRINTMSG];
481 va_start(argptr,fmt);
482 vsprintf(msg,fmt,argptr);
490 ==============================================================================
494 ==============================================================================
502 The input line scrolls horizontally if typing goes beyond the right edge
504 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
507 void Con_DrawInput (void)
509 char editlinecopy[257], *text;
511 if (!key_consoleactive)
512 return; // don't draw anything
514 text = strcpy(editlinecopy, key_lines[edit_line]);
516 // Advanced Console Editing by Radix radix@planetquake.com
517 // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
518 // use strlen of edit_line instead of key_linepos to allow editing
519 // of early characters w/o erasing
521 // add the cursor frame
522 if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible
523 text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right
525 text[key_linepos + 1] = 0;
527 // prestep if horizontally scrolling
528 if (key_linepos >= con_linewidth)
529 text += 1 + key_linepos - con_linewidth;
532 DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
535 key_lines[edit_line][key_linepos] = 0;
543 Draws the last few lines of output transparently over the game top
546 void Con_DrawNotify (void)
552 extern char chat_buffer[];
555 if (con_notify.integer < 0)
556 Cvar_SetValueQuick(&con_notify, 0);
557 if (con_notify.integer > MAX_NOTIFYLINES)
558 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
560 for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
564 time = con_times[i % con_notify.integer];
567 time = cl.time - time;
568 if (time > con_notifytime.value)
570 text = con_text + (i % con_totallines)*con_linewidth;
574 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
580 if (key_dest == key_message)
586 // LordHavoc: speedup, and other improvements
588 sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
590 sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
591 while (strlen(temptext) >= (size_t) con_linewidth)
593 DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
594 strcpy(temptext, &temptext[con_linewidth]);
597 if (strlen(temptext) > 0)
599 DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
609 Draws the console with the solid background
610 The typing input line at the bottom should only be drawn if typing is allowed
613 extern char engineversion[40];
614 void Con_DrawConsole (int lines)
622 // draw the background
623 if (scr_conbrightness.value >= 0.01f)
624 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);
626 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
627 DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
630 con_vislines = lines;
632 rows = (lines-16)>>3; // rows of text to draw
633 y = lines - 16 - (rows<<3); // may start slightly negative
635 for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
637 j = max(i - con_backscroll, 0);
638 text = con_text + (j % con_totallines)*con_linewidth;
640 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
643 // draw the input prompt, user text, and cursor if desired
650 New function for tab-completion system
652 MEGA Thanks to Taniwha
655 void Con_DisplayList(const char **list)
657 int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
658 const char **walk = list;
670 if (pos + maxlen >= width) {
676 for (i = 0; i < (maxlen - len); i++)
688 Con_CompleteCommandLine
690 New function for tab-completion system
692 Thanks to Fett erich@heintz.com
696 void Con_CompleteCommandLine (void)
698 const char *cmd = "", *s;
699 const char **list[3] = {0, 0, 0};
700 int c, v, a, i, cmd_len;
702 s = key_lines[edit_line] + 1;
703 // Count number of possible matches
704 c = Cmd_CompleteCountPossible(s);
705 v = Cvar_CompleteCountPossible(s);
706 a = Cmd_CompleteAliasCountPossible(s);
708 if (!(c + v + a)) // No possible matches
711 if (c + v + a == 1) {
713 list[0] = Cmd_CompleteBuildList(s);
715 list[0] = Cvar_CompleteBuildList(s);
717 list[0] = Cmd_CompleteAliasBuildList(s);
719 cmd_len = strlen (cmd);
722 cmd = *(list[0] = Cmd_CompleteBuildList(s));
724 cmd = *(list[1] = Cvar_CompleteBuildList(s));
726 cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
728 cmd_len = strlen (s);
730 for (i = 0; i < 3; i++) {
731 char ch = cmd[cmd_len];
732 const char **l = list[i];
734 while (*l && (*l)[cmd_len] == ch)
745 for (i = 0; i < con_linewidth - 4; i++)
749 // Print Possible Commands
751 Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
752 Con_DisplayList(list[0]);
756 Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
757 Con_DisplayList(list[1]);
761 Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
762 Con_DisplayList(list[2]);
767 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
768 key_linepos = cmd_len + 1;
769 if (c + v + a == 1) {
770 key_lines[edit_line][key_linepos] = ' ';
773 key_lines[edit_line][key_linepos] = 0;
775 for (i = 0; i < 3; i++)
777 Mem_Free((void *)list[i]);