0,0 → 1,651 |
/* |
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 <libc.h> |
#endif |
#ifndef _MSC_VER |
#include <unistd.h> |
#endif |
#include <fcntl.h> |
#include "quakedef.h" |
|
int con_linewidth; |
|
float con_cursorspeed = 4; |
|
#define CON_TEXTSIZE 16384 |
|
qboolean con_forcedup; // because no entities to refresh |
|
int con_totallines; // total lines in console scrollback |
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 |
|
#define NUM_CON_TIMES 4 |
float con_times[NUM_CON_TIMES]; // realtime time the line was generated |
// for transparent notify lines |
|
int con_vislines; |
|
qboolean con_debuglog; |
|
#define MAXCMDLINE 256 |
extern char key_lines[32][MAXCMDLINE]; |
extern int edit_line; |
extern int key_linepos; |
|
|
qboolean con_initialized; |
|
int con_notifylines; // scan lines to clear for notify lines |
|
extern void M_Menu_Main_f (void); |
|
/* |
================ |
Con_ToggleConsole_f |
================ |
*/ |
void Con_ToggleConsole_f (void) |
{ |
if (key_dest == key_console) |
{ |
if (cls.state == ca_connected) |
{ |
key_dest = key_game; |
key_lines[edit_line][1] = 0; // clear any typing |
key_linepos = 1; |
} |
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) |
Q_memset (con_text, ' ', CON_TEXTSIZE); |
} |
|
|
/* |
================ |
Con_ClearNotify |
================ |
*/ |
void Con_ClearNotify (void) |
{ |
int i; |
|
for (i=0 ; i<NUM_CON_TIMES ; i++) |
con_times[i] = 0; |
} |
|
|
/* |
================ |
Con_MessageMode_f |
================ |
*/ |
extern qboolean team_message; |
|
void Con_MessageMode_f (void) |
{ |
key_dest = key_message; |
team_message = false; |
} |
|
|
/* |
================ |
Con_MessageMode2_f |
================ |
*/ |
void Con_MessageMode2_f (void) |
{ |
key_dest = key_message; |
team_message = true; |
} |
|
|
/* |
================ |
Con_CheckResize |
|
If the line width has changed, reformat the buffer. |
================ |
*/ |
void Con_CheckResize (void) |
{ |
int i, j, width, oldwidth, oldtotallines, numlines, numchars; |
char tbuf[CON_TEXTSIZE]; |
|
width = (vid.width >> 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; |
Q_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; |
|
Q_memcpy (tbuf, con_text, CON_TEXTSIZE); |
Q_memset (con_text, ' ', CON_TEXTSIZE); |
|
for (i=0 ; i<numlines ; i++) |
{ |
for (j=0 ; j<numchars ; j++) |
{ |
con_text[(con_totallines - 1 - i) * con_linewidth + j] = |
tbuf[((con_current - i + oldtotallines) % |
oldtotallines) * oldwidth + j]; |
} |
} |
|
Con_ClearNotify (); |
} |
|
con_backscroll = 0; |
con_current = con_totallines - 1; |
} |
|
|
/* |
================ |
Con_Init |
================ |
*/ |
void Con_Init (void) |
{ |
#define MAXGAMEDIRLEN 1000 |
char temp[MAXGAMEDIRLEN+1]; |
char *t2 = "/qconsole.log"; |
|
con_debuglog = COM_CheckParm("-condebug"); |
|
if (con_debuglog) |
{ |
if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2))) |
{ |
sprintf (temp, "%s%s", com_gamedir, t2); |
unlink (temp); |
} |
} |
|
con_text = Hunk_AllocName (CON_TEXTSIZE, "context"); |
Q_memset (con_text, ' ', CON_TEXTSIZE); |
con_linewidth = -1; |
Con_CheckResize (); |
|
Con_Printf ("Console initialized.\n"); |
|
// |
// register our commands |
// |
Cvar_RegisterVariable (&con_notifytime); |
|
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); |
Cmd_AddCommand ("messagemode", Con_MessageMode_f); |
Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); |
Cmd_AddCommand ("clear", Con_Clear_f); |
con_initialized = true; |
} |
|
|
/* |
=============== |
Con_Linefeed |
=============== |
*/ |
void Con_Linefeed (void) |
{ |
if ( ! con_initialized ) return; |
con_x = 0; |
con_current++; |
Q_memset (&con_text[(con_current%con_totallines)*con_linewidth] |
, ' ', con_linewidth); |
} |
|
/* |
================ |
Con_Print |
|
Handles cursor positioning, line wrapping, etc |
All console printing must go through this in order to be logged to disk |
If no console is visible, the notify window will pop up. |
================ |
*/ |
void Con_Print (char *txt) |
{ |
int y; |
int c, l; |
static int cr; |
int mask; |
|
if ( ! con_initialized ) return; |
con_backscroll = 0; |
|
if (txt[0] == 1) |
{ |
mask = 128; // go to colored text |
S_LocalSound ("misc/talk.wav"); |
// play talk wav |
txt++; |
} |
else if (txt[0] == 2) |
{ |
mask = 128; // go to colored text |
txt++; |
} |
else |
mask = 0; |
|
|
while ( (c = *txt) ) |
{ |
// count word length |
for (l=0 ; l< con_linewidth ; l++) |
if ( txt[l] <= ' ') |
break; |
|
// word wrap |
if (l != con_linewidth && (con_x + l > 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); |
vsprintf(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 |
// FIXME: make a buffer size safe vsprintf? |
void Con_Printf (char *fmt, ...) |
{ |
va_list argptr; |
char msg[MAXPRINTMSG]; |
static qboolean inupdate; |
|
va_start (argptr,fmt); |
vsprintf (msg,fmt,argptr); |
va_end (argptr); |
|
// also echo to debugging console |
Sys_Printf ("%s", msg); // also echo to debugging console |
|
// 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); |
|
// update the screen if the console is displayed |
if (cls.signon != SIGNONS && !scr_disabled_for_loading ) |
{ |
// protect against infinite loop if something in SCR_UpdateScreen calls |
// Con_Printd |
if (!inupdate) |
{ |
inupdate = true; |
SCR_UpdateScreen (); |
inupdate = false; |
} |
} |
} |
|
/* |
================ |
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); |
vsprintf (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); |
vsprintf (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 |
================ |
*/ |
void Con_DrawInput (void) |
{ |
int y; |
int i; |
char *text; |
|
if (key_dest != key_console && !con_forcedup) |
return; // don't draw anything |
|
text = key_lines[edit_line]; |
|
// add the cursor frame |
text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1); |
|
// fill out remainder with spaces |
for (i=key_linepos+1 ; i< con_linewidth ; i++) |
text[i] = ' '; |
|
// prestep if horizontally scrolling |
if (key_linepos >= con_linewidth) |
text += 1 + key_linepos - con_linewidth; |
|
// draw it |
y = con_vislines-16; |
|
for (i=0 ; i<con_linewidth ; i++) |
Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]); |
|
// remove cursor |
key_lines[edit_line][key_linepos] = 0; |
} |
|
|
/* |
================ |
Con_DrawNotify |
|
Draws the last few lines of output transparently over the game top |
================ |
*/ |
void Con_DrawNotify (void) |
{ |
int x, v; |
char *text; |
int i; |
float time; |
extern char chat_buffer[]; |
|
v = 0; |
for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++) |
{ |
if (i < 0) |
continue; |
time = con_times[i % NUM_CON_TIMES]; |
if (time == 0) |
continue; |
time = realtime - time; |
if (time > 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; |
|
x = 0; |
|
Draw_String (8, v, "say:"); |
while(chat_buffer[x]) |
{ |
Draw_Character ( (x+5)<<3, v, chat_buffer[x]); |
x++; |
} |
Draw_Character ( (x+5)<<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, x, y; |
int rows; |
char *text; |
int j; |
|
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; |
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_FloatTime (); |
SCR_UpdateScreen (); |
Sys_SendKeyEvents (); |
t2 = Sys_FloatTime (); |
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 |
} |
|