/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // console.c //#ifdef NeXT //#include //#endif #ifndef _MSC_VER #include #endif #ifdef _WIN32 #include #endif #include #include "quakedef.h" int con_linewidth; float con_cursorspeed = 6; // joe: increased to make it blink faster #define CON_TEXTSIZE 32768 qboolean con_forcedup; // because no entities to refresh int con_totallines; // total lines in console scrollback int con_numlines = 0; // number of non-blank text lines, used for backscrolling, added by joe int con_backscroll; // lines up from bottom to display int con_current; // where next message will be printed int con_x; // offset in current line for next print char *con_text = 0; cvar_t con_notifytime = {"con_notifytime","3"}; //seconds cvar_t _con_notifylines = {"con_notifylines","4"}; #define NUM_CON_TIMES 16 float con_times[NUM_CON_TIMES]; // realtime time the line was generated // for transparent notify lines int con_vislines; int con_notifylines; // scan lines to clear for notify lines qboolean con_debuglog = false; extern char key_lines[32][MAXCMDLINE]; extern int edit_line; extern int key_linepos; extern int key_insert; qboolean con_initialized = false; /* ================ Con_ToggleConsole_f ================ */ void Con_ToggleConsole_f (void) { key_lines[edit_line][1] = 0; // clear any typing key_linepos = 1; if (key_dest == key_console) { if (cls.state == ca_connected) key_dest = key_game; else M_Menu_Main_f (); } else { key_dest = key_console; } SCR_EndLoadingPlaque (); memset (con_times, 0, sizeof(con_times)); } /* ================ Con_Clear_f ================ */ void Con_Clear_f (void) { if (con_text) memset (con_text, ' ', CON_TEXTSIZE); } /* ================ Con_ClearNotify ================ */ void Con_ClearNotify (void) { int i; for (i=0 ; i> 3) - 2; if (width == con_linewidth) return; if (width < 1) // video hasn't been initialized yet { width = 38; con_linewidth = width; con_totallines = CON_TEXTSIZE / con_linewidth; memset (con_text, ' ', CON_TEXTSIZE); } else { oldwidth = con_linewidth; con_linewidth = width; oldtotallines = con_totallines; con_totallines = CON_TEXTSIZE / con_linewidth; numlines = oldtotallines; if (con_totallines < numlines) numlines = con_totallines; numchars = oldwidth; if (con_linewidth < numchars) numchars = con_linewidth; memcpy (tbuf, con_text, CON_TEXTSIZE); memset (con_text, ' ', CON_TEXTSIZE); for (i=0 ; i con_linewidth)) con_x = 0; txt++; if (cr) { con_current--; cr = false; } if (!con_x) { Con_Linefeed (); // mark time for transparent overlay if (con_current >= 0) con_times[con_current % NUM_CON_TIMES] = realtime; } switch (c) { case '\n': con_x = 0; break; case '\r': con_x = 0; cr = 1; break; default: // display character and advance y = con_current % con_totallines; con_text[y*con_linewidth+con_x] = c | mask; con_x++; if (con_x >= con_linewidth) con_x = 0; break; } } } /* ================ Con_DebugLog ================ */ void Con_DebugLog (char *file, char *fmt, ...) { va_list argptr; static char data[1024]; int fd; va_start (argptr, fmt); vsnprintf (data, sizeof(data), fmt, argptr); va_end (argptr); fd = open (file, O_WRONLY | O_CREAT | O_APPEND, 0666); write (fd, data, strlen(data)); close (fd); } /* ================ Con_Printf Handles cursor positioning, line wrapping, etc ================ */ #define MAXPRINTMSG 4096 void Con_Printf (char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; va_start (argptr, fmt); vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); // also echo to debugging console Sys_Printf ("%s", msg); // log all messages to file if (con_debuglog) Con_DebugLog (va("%s/qconsole.log", com_gamedir), "%s", msg); if (!con_initialized) return; if (cls.state == ca_dedicated) return; // no graphics mode // write it to the scrollable buffer Con_Print (msg); } /* ================ Con_DPrintf A Con_Printf that only shows up if the "developer" cvar is set ================ */ void Con_DPrintf (char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; if (!developer.value) return; // don't confuse non-developers with techie stuff... va_start (argptr, fmt); vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); Con_Printf ("%s", msg); } /* ================== Con_SafePrintf Okay to call even when the screen can't be updated ================== */ void Con_SafePrintf (char *fmt, ...) { va_list argptr; char msg[1024]; int temp; va_start (argptr, fmt); vsnprintf (msg, sizeof(msg), fmt, argptr); va_end (argptr); temp = scr_disabled_for_loading; scr_disabled_for_loading = true; Con_Printf ("%s", msg); scr_disabled_for_loading = temp; } /* ============================================================================== DRAWING ============================================================================== */ /* ================ Con_DrawInput The input line scrolls horizontally if typing goes beyond the right edge ================ */ // modified by joe to work as ZQuake void Con_DrawInput (void) { int i; char *text; char temp[MAXCMDLINE]; if (key_dest != key_console && !con_forcedup) return; // don't draw anything text = strcpy (temp, key_lines[edit_line]); // fill out remainder with spaces for (i = strlen(text) ; i < MAXCMDLINE ; i++) text[i] = ' '; // add the cursor frame if ((int)(realtime * con_cursorspeed) & 1) text[key_linepos] = 11 + 84 * key_insert; // prestep if horizontally scrolling if (key_linepos >= con_linewidth) text += 1 + key_linepos - con_linewidth; // draw it //#ifdef GLQUAKE Draw_String (8, con_vislines - 16, text); //#else // for (i=0 ; i con_notifytime.value) continue; text = con_text + (i % con_totallines) * con_linewidth; clearnotify = 0; scr_copytop = 1; for (x = 0 ; x < con_linewidth ; x++) Draw_Character ((x+1)<<3, v, text[x]); v += 8; } if (key_dest == key_message) { clearnotify = 0; scr_copytop = 1; i = 0; if (team_message) { Draw_String (8, v, "(say):"); x = 7; } else { Draw_String (8, v, "say:"); x = 5; } while (chat_buffer[i]) { Draw_Character (x << 3, v, chat_buffer[i]); x++; i++; if (x > con_linewidth) { x = team_message ? 7 : 5; v += 8; } } Draw_Character (x << 3, v, 10 + ((int)(realtime * con_cursorspeed) & 1)); v += 8; } if (v > con_notifylines) con_notifylines = v; } /* ================ Con_DrawConsole Draws the console with the solid background The typing input line at the bottom should only be drawn if typing is allowed ================ */ void Con_DrawConsole (int lines, qboolean drawinput) { int i, j, x, y, rows; char *text; if (lines <= 0) return; // draw the background Draw_ConsoleBackground (lines); // draw the text con_vislines = lines; rows = (lines - 16)>>3; // rows of text to draw y = lines - 16 - (rows<<3); // may start slightly negative for (i = con_current - rows + 1 ; i <= con_current ; i++, y += 8) { j = i - con_backscroll; if (j < 0) j = 0; // added by joe if (con_backscroll && i == con_current) { for (x = 0 ; x < con_linewidth ; x += 4) Draw_Character ((x+1)<<3, y, '^'); continue; } text = con_text + (j % con_totallines)*con_linewidth; for (x = 0 ; x < con_linewidth ; x++) Draw_Character ((x+1)<<3, y, text[x]); } // draw the input prompt, user text, and cursor if desired if (drawinput) Con_DrawInput (); } /* ================== Con_NotifyBox ================== */ void Con_NotifyBox (char *text) { double t1, t2; // during startup for sound / cd warnings Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); Con_Printf (text); Con_Printf ("Press a key.\n"); Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); key_count = -2; // wait for a key down and up key_dest = key_console; do { t1 = Sys_DoubleTime (); SCR_UpdateScreen (); Sys_SendKeyEvents (); t2 = Sys_DoubleTime (); realtime += t2-t1; // make the cursor blink } while (key_count < 0); Con_Printf ("\n"); key_dest = key_game; realtime = 0; // put the cursor back to invisible }