mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
308e1b13c4
Fix crash vulnerabilities in hint_test, entid, and entlist developer commands in default Lazarus and missionpack DLLs.
1023 lines
24 KiB
C
1023 lines
24 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This file is part of Quake 2 source code.
|
|
|
|
Quake 2 source code 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.
|
|
|
|
Quake 2 source code 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 Quake 2 source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// console.c
|
|
|
|
#include "client.h"
|
|
|
|
console_t con;
|
|
|
|
cvar_t *con_notifytime;
|
|
qboolean newconback_found = false; // whether to draw Q3-style console
|
|
|
|
extern char key_lines[32][MAXCMDLINE];
|
|
extern int edit_line;
|
|
extern int key_linepos;
|
|
|
|
|
|
/*
|
|
================
|
|
Con_DrawString
|
|
================
|
|
*/
|
|
void Con_DrawString (int x, int y, char *string, fontslot_t font, int alpha)
|
|
{
|
|
CL_DrawStringGeneric (x, y, string, font, alpha, FONT_SIZE, SCALETYPE_CONSOLE, false);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Key_ClearTyping
|
|
================
|
|
*/
|
|
void Key_ClearTyping (void)
|
|
{
|
|
key_lines[edit_line][1] = 0; // clear any typing
|
|
key_linepos = 1;
|
|
con.backedit = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_ToggleConsole_f
|
|
================
|
|
*/
|
|
void Con_ToggleConsole_f (void)
|
|
{
|
|
// SCR_EndLoadingPlaque (); // get rid of loading plaque
|
|
|
|
// Knightmare- allow disconnected menu
|
|
if (cls.state == ca_disconnected && cls.key_dest != key_menu)
|
|
{ // start the demo loop again
|
|
Cbuf_AddText ("d1\n");
|
|
return;
|
|
}
|
|
|
|
Key_ClearTyping ();
|
|
Con_ClearNotify ();
|
|
|
|
if (cls.consoleActive) // Knightmare changed
|
|
//if (cls.key_dest == key_console)
|
|
{
|
|
cls.consoleActive = false; // Knightmare added
|
|
|
|
//UI_ForceMenuOff ();
|
|
//if (cls.key_dest != key_menu)
|
|
if (Cvar_VariableValue ("maxclients") == 1
|
|
&& Com_ServerState () && cls.key_dest != key_menu)
|
|
Cvar_Set ("paused", "0");
|
|
}
|
|
else
|
|
{
|
|
cls.consoleActive = true; // Knightmare added
|
|
//UI_ForceMenuOff ();
|
|
//cls.key_dest = key_console;
|
|
|
|
if (Cvar_VariableValue ("maxclients") == 1
|
|
&& Com_ServerState () && cls.key_dest != key_menu)
|
|
Cvar_Set ("paused", "1");
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
Con_ToggleChat_f
|
|
================
|
|
*/
|
|
void Con_ToggleChat_f (void)
|
|
{
|
|
Key_ClearTyping ();
|
|
|
|
if (cls.consoleActive) // Knightmare added
|
|
//if (cls.key_dest == key_console)
|
|
{
|
|
if (cls.state == ca_active)
|
|
{
|
|
UI_ForceMenuOff ();
|
|
cls.consoleActive = false; // Knightmare added
|
|
cls.key_dest = key_game;
|
|
}
|
|
}
|
|
else
|
|
//cls.key_dest = key_console;
|
|
cls.consoleActive = true; // Knightmare added
|
|
|
|
Con_ClearNotify ();
|
|
}
|
|
|
|
/*
|
|
================
|
|
Con_Clear_f
|
|
================
|
|
*/
|
|
void Con_Clear_f (void)
|
|
{
|
|
memset (con.text, ' ', CON_TEXTSIZE);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_Dump_f
|
|
|
|
Save the console contents out to a file
|
|
================
|
|
*/
|
|
void Con_Dump_f (void)
|
|
{
|
|
int l, x;
|
|
char *line;
|
|
FILE *f;
|
|
char buffer[1024];
|
|
char name[MAX_OSPATH];
|
|
|
|
if (Cmd_Argc() != 2)
|
|
{
|
|
Com_Printf ("usage: condump <filename>\n");
|
|
return;
|
|
}
|
|
|
|
Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Savegamedir(), Cmd_Argv(1)); // was FS_Gamedir()
|
|
|
|
Com_Printf ("Dumped console text to %s.\n", name);
|
|
FS_CreatePath (name);
|
|
f = fopen (name, "w");
|
|
if (!f)
|
|
{
|
|
Com_Printf ("ERROR: couldn't open.\n");
|
|
return;
|
|
}
|
|
|
|
// skip empty lines
|
|
for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
|
|
{
|
|
line = con.text + (l%con.totallines)*con.linewidth;
|
|
for (x=0 ; x<con.linewidth ; x++)
|
|
if (line[x] != ' ')
|
|
break;
|
|
if (x != con.linewidth)
|
|
break;
|
|
}
|
|
|
|
// write the remaining lines
|
|
buffer[con.linewidth] = 0;
|
|
for ( ; l <= con.current ; l++)
|
|
{
|
|
line = con.text + (l%con.totallines)*con.linewidth;
|
|
strncpy (buffer, line, con.linewidth);
|
|
for (x=con.linewidth-1 ; x>=0 ; x--)
|
|
{
|
|
if (buffer[x] == ' ')
|
|
buffer[x] = 0;
|
|
else
|
|
break;
|
|
}
|
|
for (x=0; buffer[x]; x++)
|
|
buffer[x] &= 0x7f;
|
|
|
|
fprintf (f, "%s\n", buffer);
|
|
}
|
|
|
|
fclose (f);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_ClearNotify
|
|
================
|
|
*/
|
|
void Con_ClearNotify (void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i<NUM_CON_TIMES ; i++)
|
|
con.times[i] = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_MessageMode_f
|
|
================
|
|
*/
|
|
void Con_MessageMode_f (void)
|
|
{
|
|
chat_team = false;
|
|
cls.key_dest = key_message;
|
|
cls.consoleActive = false; // Knightmare added
|
|
}
|
|
|
|
/*
|
|
================
|
|
Con_MessageMode2_f
|
|
================
|
|
*/
|
|
void Con_MessageMode2_f (void)
|
|
{
|
|
chat_team = true;
|
|
cls.key_dest = key_message;
|
|
cls.consoleActive = false; // Knightmare added
|
|
}
|
|
|
|
/*
|
|
================
|
|
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];
|
|
|
|
if (con_font_size)
|
|
width = viddef.width/FONT_SIZE - 2;
|
|
else // (viddef.width / 8) - 2
|
|
width = (viddef.width >> 3) - 2;
|
|
width = min((MAXCMDLINE - 2), width); // clamp width to MAXCMDLINE - 2 to prevent buffer overflow
|
|
|
|
if (width == con.linewidth)
|
|
return;
|
|
|
|
if (width < 1) // video hasn't been initialized yet
|
|
{
|
|
width = 78; // was 38
|
|
con.linewidth = width;
|
|
con.backedit = 0;
|
|
con.totallines = CON_TEXTSIZE / con.linewidth;
|
|
memset (con.text, ' ', CON_TEXTSIZE);
|
|
}
|
|
else
|
|
{
|
|
oldwidth = con.linewidth;
|
|
con.linewidth = width;
|
|
con.backedit = 0;
|
|
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<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.current = con.totallines - 1;
|
|
con.display = con.current;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_Init
|
|
================
|
|
*/
|
|
void Con_Init (void)
|
|
{
|
|
con.linewidth = -1;
|
|
con.backedit = 0;
|
|
|
|
Con_CheckResize ();
|
|
|
|
Com_Printf ("Console initialized.\n");
|
|
|
|
//
|
|
// register our commands
|
|
//
|
|
con_notifytime = Cvar_Get ("con_notifytime", "4", 0); // Knightmare- increased for fade
|
|
Cvar_SetDescription ("con_notifytime", "Time in seconds for console notify messages to fade away.");
|
|
|
|
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
|
|
Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
|
|
Cmd_AddCommand ("messagemode", Con_MessageMode_f);
|
|
Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
|
|
Cmd_AddCommand ("clear", Con_Clear_f);
|
|
Cmd_AddCommand ("condump", Con_Dump_f);
|
|
|
|
// whether to use new-style console background
|
|
newconback_found = false;
|
|
if ( (FS_LoadFile("gfx/ui/newconback.tga", NULL) != -1)
|
|
#ifdef PNG_SUPPORT
|
|
|| (FS_LoadFile("gfx/ui/newconback.png", NULL) != -1)
|
|
#endif // PNG_SUPPORT
|
|
|| (FS_LoadFile("gfx/ui/newconback.jpg", NULL) != -1) )
|
|
newconback_found = true;
|
|
|
|
con.initialized = true;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_Shutdown
|
|
================
|
|
*/
|
|
void Con_Shutdown (void)
|
|
{
|
|
Cmd_RemoveCommand ("toggleconsole");
|
|
Cmd_RemoveCommand ("togglechat");
|
|
Cmd_RemoveCommand ("messagemode");
|
|
Cmd_RemoveCommand ("messagemode2");
|
|
Cmd_RemoveCommand ("clear");
|
|
Cmd_RemoveCommand ("condump");
|
|
|
|
con.initialized = false;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Con_StringSetParams
|
|
===============
|
|
*/
|
|
qboolean Con_StringSetParams (char modifier, char *colorCode, qboolean *bold, qboolean *shadow, qboolean *italic, qboolean *alt)
|
|
{
|
|
// sanity check
|
|
if (!colorCode || !bold || !shadow || !italic || !alt)
|
|
return false;
|
|
|
|
switch (modifier)
|
|
{
|
|
case 'R':
|
|
case 'r':
|
|
*colorCode = 0;
|
|
*bold = *shadow = *italic = *alt = false;
|
|
return true;
|
|
case 'B':
|
|
case 'b':
|
|
if (*bold)
|
|
*bold = false;
|
|
else
|
|
*bold = true;
|
|
return true;
|
|
case 'S':
|
|
case 's':
|
|
if (*shadow)
|
|
*shadow = false;
|
|
else
|
|
*shadow = true;
|
|
return true;
|
|
case 'I':
|
|
case 'i':
|
|
if (*italic)
|
|
*italic = false;
|
|
else
|
|
*italic = true;
|
|
return true;
|
|
case COLOR_RED:
|
|
case COLOR_GREEN:
|
|
case COLOR_YELLOW:
|
|
case COLOR_BLUE:
|
|
case COLOR_CYAN:
|
|
case COLOR_MAGENTA:
|
|
case COLOR_WHITE:
|
|
case COLOR_BLACK:
|
|
case COLOR_ORANGE:
|
|
case COLOR_GRAY:
|
|
*colorCode = modifier;
|
|
return true;
|
|
case 'A': // alt text color
|
|
case 'a':
|
|
*alt = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Con_Linefeed
|
|
===============
|
|
*/
|
|
void Con_Linefeed (char colorCode, qboolean bold, qboolean shadow, qboolean italic, qboolean alt)
|
|
{
|
|
int y;
|
|
|
|
con.x = 0;
|
|
if (con.display == con.current)
|
|
con.display++;
|
|
con.current++;
|
|
memset (&con.text[(con.current%con.totallines)*con.linewidth]
|
|
, ' ', con.linewidth);
|
|
|
|
// add any wrapped formatting
|
|
y = con.current % con.totallines;
|
|
if (colorCode != 0)
|
|
{
|
|
con.text[y*con.linewidth+con.x] = '^';
|
|
con.x++;
|
|
con.text[y*con.linewidth+con.x] = colorCode;
|
|
con.x++;
|
|
}
|
|
if (bold)
|
|
{
|
|
con.text[y*con.linewidth+con.x] = '^';
|
|
con.x++;
|
|
con.text[y*con.linewidth+con.x] = 'b';
|
|
con.x++;
|
|
}
|
|
if (shadow)
|
|
{
|
|
con.text[y*con.linewidth+con.x] = '^';
|
|
con.x++;
|
|
con.text[y*con.linewidth+con.x] = 's';
|
|
con.x++;
|
|
}
|
|
if (italic)
|
|
{
|
|
con.text[y*con.linewidth+con.x] = '^';
|
|
con.x++;
|
|
con.text[y*con.linewidth+con.x] = 'i';
|
|
con.x++;
|
|
}
|
|
if (alt)
|
|
{
|
|
con.text[y*con.linewidth+con.x] = '^';
|
|
con.x++;
|
|
con.text[y*con.linewidth+con.x] = 'a';
|
|
con.x++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
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 text will appear at the top of the game window
|
|
================
|
|
*/
|
|
void Con_Print (char *txt)
|
|
{
|
|
int y, c, l; //, i;
|
|
static int cr;
|
|
int mask;
|
|
// vars for format wrapping
|
|
char modifier, colorCode = 0;
|
|
qboolean nextCharModifierCheck = false, bold = false, shadow = false, italic = false, alt = false;
|
|
|
|
if (!con.initialized)
|
|
return;
|
|
|
|
if (txt[0] == 1 || 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 (colorCode, bold, shadow, italic, alt);
|
|
// mark time for transparent overlay
|
|
if (con.current >= 0)
|
|
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
|
|
}
|
|
|
|
// track formatting codes for word wrap
|
|
modifier = (c & ~128);
|
|
if (nextCharModifierCheck) // last char was a ^
|
|
{
|
|
Con_StringSetParams (modifier, &colorCode, &bold, &shadow, &italic, &alt);
|
|
nextCharModifierCheck = false;
|
|
}
|
|
else {
|
|
// set var to check modifier if char is ^
|
|
nextCharModifierCheck = (modifier == '^') ? true : false;
|
|
}
|
|
|
|
switch (c)
|
|
{
|
|
case '\n':
|
|
con.x = 0;
|
|
colorCode = 0;
|
|
bold = shadow = italic = alt = false;
|
|
break;
|
|
|
|
case '\r':
|
|
con.x = 0;
|
|
cr = 1;
|
|
colorCode = 0;
|
|
bold = shadow = italic = alt = false;
|
|
break;
|
|
|
|
default: // display character and advance
|
|
y = con.current % con.totallines;
|
|
con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
|
|
con.x++;
|
|
if (con.x >= con.linewidth)
|
|
con.x = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
Con_CenteredPrint
|
|
==============
|
|
*/
|
|
void Con_CenteredPrint (char *text)
|
|
{
|
|
int l;
|
|
char buffer[1024];
|
|
|
|
l = (int)strlen(text);
|
|
l = (con.linewidth-l)/2;
|
|
if (l < 0)
|
|
l = 0;
|
|
memset (buffer, ' ', l);
|
|
// strncpy (buffer+l, text);
|
|
// strncat (buffer, "\n");
|
|
Q_strncpyz (buffer+l, sizeof(buffer)-1, text);
|
|
Q_strncatz (buffer, sizeof(buffer), "\n");
|
|
Con_Print (buffer);
|
|
}
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
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, output[2048], addch[8];
|
|
float conLeft = 0;
|
|
|
|
if (!cls.consoleActive && cls.state == ca_active)
|
|
return; // don't draw anything (always draw if not active)
|
|
|
|
SCR_ScaleCoords (&conLeft, NULL, NULL, NULL, ALIGN_STRETCH);
|
|
|
|
/*if (cls.key_dest == key_menu)
|
|
return;
|
|
if (cls.key_dest != key_console && cls.state == ca_active)
|
|
return;*/ // don't draw anything (always draw if not active)
|
|
|
|
text = key_lines[edit_line];
|
|
|
|
// add the cursor frame
|
|
if (con.backedit)
|
|
text[key_linepos] = ' ';
|
|
else
|
|
text[key_linepos] = 10+((int)(cls.realtime>>8)&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-FONT_SIZE*2; // was 16
|
|
|
|
Com_sprintf (output, sizeof(output), "");
|
|
for (i=0; i<con.linewidth; i++)
|
|
{
|
|
if (con.backedit == key_linepos-i && ((int)(cls.realtime>>8)&1)) {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, 11 );
|
|
addch[0] = 11;
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
else {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, text[i]);
|
|
addch[0] = text[i];
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
}
|
|
Con_DrawString ( (int)conLeft + FONT_SIZE/2, con.vislines - (int)(2.75*FONT_SIZE), output, FONT_CONSOLE, 255);
|
|
|
|
// 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;
|
|
char *text, output[2048], addch[8];
|
|
int i, j;
|
|
// int time;
|
|
char *s;
|
|
int alpha, lines;
|
|
float v, time, conLeft, conWidth;
|
|
|
|
lines = 0;
|
|
v = 0;
|
|
|
|
conLeft = 0;
|
|
conWidth = SCREEN_WIDTH;
|
|
SCR_ScaleCoords (&conLeft, NULL, &conWidth, NULL, ALIGN_STRETCH);
|
|
|
|
Com_sprintf (output, sizeof(output), "");
|
|
|
|
// this is the say msg while typeing...
|
|
if (cls.key_dest == key_message)
|
|
{
|
|
if (chat_team)
|
|
Com_sprintf (output, sizeof(output), "%s", " say_team: ");
|
|
else
|
|
Com_sprintf (output, sizeof(output), "%s", " say: ");
|
|
|
|
s = chat_buffer;
|
|
x = 0;
|
|
if (chat_bufferlen > (viddef.width/FONT_SIZE)-(strlen(output)+1))
|
|
x += chat_bufferlen - (int)((viddef.width/FONT_SIZE)-(strlen(output)+1));
|
|
|
|
while (s[x])
|
|
{
|
|
if ( chat_backedit && (chat_backedit == chat_bufferlen-x) && ((int)(cls.realtime>>8)&1) ) {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, 11 );
|
|
addch[0] = 11;
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
else {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, (char)s[x]);
|
|
addch[0] = s[x];
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
|
|
x++;
|
|
}
|
|
|
|
if (!chat_backedit) {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, 10+((int)(cls.realtime>>8)&1) );
|
|
addch[0] = 10+((int)(cls.realtime>>8)&1);
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
|
|
Con_DrawString ((int)conLeft, v, output, FONT_SCREEN, 255);
|
|
|
|
v += FONT_SIZE*2; // make extra space so we have room
|
|
}
|
|
|
|
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 = cls.realtime - time;
|
|
if (time > con_notifytime->value*1000)
|
|
continue;
|
|
|
|
// vertical offset set by closest to dissapearing
|
|
lines++;
|
|
}
|
|
|
|
// v = 0;
|
|
if (lines)
|
|
for (j = 0, i = con.current-NUM_CON_TIMES+1; i <= con.current; i++, j++)
|
|
{
|
|
if (i < 0)
|
|
continue;
|
|
time = con.times[i % NUM_CON_TIMES];
|
|
if (time == 0)
|
|
continue;
|
|
time = cls.realtime - time;
|
|
if (time > con_notifytime->value*1000)
|
|
continue;
|
|
|
|
text = con.text + (i % con.totallines)*con.linewidth;
|
|
|
|
alpha = 255 * sqrt( (1.0-time/(con_notifytime->value*1000.0+1.0)) * (((float)v+8.0)) / (8.0*lines) );
|
|
// alpha = (1-time/(con_notifytime->value*1000.0+2)) * (255*(v+16)) / (4*lines);
|
|
if (alpha < 0) alpha = 0;
|
|
if (alpha > 255) alpha = 255;
|
|
|
|
Com_sprintf (output, sizeof(output), "");
|
|
for (x = 0; x < con.linewidth; x++) {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, (char)text[x]);
|
|
addch[0] = (char)text[x];
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
|
|
Con_DrawString ((int)conLeft + FONT_SIZE/2, v, output, FONT_SCREEN, alpha);
|
|
|
|
v += FONT_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_DrawDownloadProgress
|
|
|
|
Draws a download progress bar
|
|
================
|
|
*/
|
|
void Con_DrawDownloadProgress (float conLeft, float conWidth, float conLineHeight, int verLen, int red, int green, int blue)
|
|
{
|
|
int i, j, x, y, len;
|
|
char *text;
|
|
char dlbar[1024];
|
|
int graph_x, graph_y, graph_h, graph_w;
|
|
|
|
if ((text = strrchr(cls.downloadname, '/')) != NULL)
|
|
text++;
|
|
else
|
|
text = cls.downloadname;
|
|
|
|
memset (dlbar, 0, sizeof(dlbar)); // clear dlbar
|
|
|
|
// make this a little shorter in case of longer version string
|
|
x = con.linewidth - ((con.linewidth * 7) / 40) - (verLen-14);
|
|
|
|
if (cls.downloadrate > 0.0f)
|
|
y = x - (int)strlen(text) - 19;
|
|
else
|
|
y = x - (int)strlen(text) - 8;
|
|
i = con.linewidth/3;
|
|
if (strlen(text) > i)
|
|
{
|
|
y = x - i - 11;
|
|
strncpy(dlbar, text, i);
|
|
dlbar[i] = 0;
|
|
// strncat(dlbar, "...");
|
|
Q_strncatz(dlbar, sizeof(dlbar), "...");
|
|
}
|
|
else
|
|
// strncpy(dlbar, text);
|
|
Q_strncpyz(dlbar, sizeof(dlbar), text);
|
|
// strncat(dlbar, ": ");
|
|
Q_strncatz(dlbar, sizeof(dlbar), ": ");
|
|
i = (int)strlen(dlbar);
|
|
|
|
// init solid color download bar
|
|
graph_x = (i+1)*FONT_SIZE;
|
|
graph_y = con.vislines - (int)(FONT_SIZE*1.5) - (int)conLineHeight; // was -12
|
|
graph_w = y*FONT_SIZE;
|
|
graph_h = FONT_SIZE;
|
|
|
|
for (j = 0; j < y; j++) // add blank spaces
|
|
Com_sprintf(dlbar + strlen(dlbar), sizeof(dlbar)-strlen(dlbar), " ");
|
|
|
|
if (cls.downloadrate > 0.0f)
|
|
Com_sprintf(dlbar + strlen(dlbar), sizeof(dlbar)-strlen(dlbar), " %2d%% (%4.2fKB/s)", cls.downloadpercent, cls.downloadrate);
|
|
else
|
|
Com_sprintf(dlbar + strlen(dlbar), sizeof(dlbar)-strlen(dlbar), " %2d%%", cls.downloadpercent);
|
|
|
|
// draw it
|
|
//y = graph_y;
|
|
len = (int)strlen(dlbar);
|
|
for (i = 0; i < len; i++)
|
|
if (dlbar[i] != ' ')
|
|
R_DrawChar((int)conLeft + (i+1)*FONT_SIZE, graph_y, dlbar[i], FONT_CONSOLE, CON_FONT_SCALE, 255, 255, 255, 255, false, (i==(len-1)) );
|
|
|
|
// new solid color download bar
|
|
graph_x--; graph_y--; graph_w+=2; graph_h+=2;
|
|
R_DrawFill ((int)conLeft + graph_x, graph_y, graph_w, graph_h, 255, 255, 255, 90);
|
|
R_DrawFill ((int)conLeft + (int)(graph_x+graph_h*0.2), (int)(graph_y+graph_h*0.2),
|
|
(int)((graph_w-graph_h*0.4)*cls.downloadpercent*0.01), (int)(graph_h*0.6),
|
|
red, green, blue, 255);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Con_DrawConsole
|
|
Draws the console with the solid background
|
|
================
|
|
*/
|
|
|
|
void Con_DrawConsole (float frac, qboolean trans)
|
|
{
|
|
int i, x, y;
|
|
int rows;
|
|
char *text, output[1024], addch[8];
|
|
int row;
|
|
int lines;
|
|
char version[64];
|
|
float alpha, barheight, conLeft, conWidth, picLeft, picWidth, picHeight, pboxWidth;
|
|
// changeable download bar color
|
|
int red, green, blue;
|
|
vec4_t picColor;
|
|
drawStruct_t ds = { 0 };
|
|
|
|
// CL_TextColor ((int)alt_text_color->value, &red, &green, &blue);
|
|
CL_TextColor (alt_text_color->integer, &red, &green, &blue);
|
|
|
|
// Q3-style console bottom bar
|
|
conLeft = picLeft = 0;
|
|
conWidth = picWidth = SCREEN_WIDTH;
|
|
picHeight = SCREEN_HEIGHT;
|
|
SCR_ScaleCoords (&picLeft, NULL, &picWidth, &picHeight, ALIGN_CENTER);
|
|
|
|
// if ( (newconback_found && scr_newconback->value) || scr_oldconbar->value ) {
|
|
if ( (newconback_found && scr_newconback->integer) || scr_oldconbar->integer ) {
|
|
barheight = 2;
|
|
SCR_ScaleCoords (&conLeft, NULL, &conWidth, &barheight, ALIGN_STRETCH);
|
|
}
|
|
else {
|
|
barheight = 0;
|
|
SCR_ScaleCoords (&conLeft, NULL, &conWidth, NULL, ALIGN_STRETCH);
|
|
}
|
|
|
|
lines = viddef.height * frac;
|
|
if (lines <= 0)
|
|
return;
|
|
|
|
if (lines > viddef.height)
|
|
lines = viddef.height;
|
|
|
|
// Psychospaz's transparent console
|
|
//alpha = (trans) ? ((frac/ (newconback_found?0.5:scr_conheight->value) )*scr_conalpha->value) : 1;
|
|
// alpha = trans ? ((newconback_found && scr_newconback->value) ? scr_conalpha->value : 2*frac*scr_conalpha->value) : 1;
|
|
alpha = trans ? ((newconback_found && scr_newconback->integer) ? scr_conalpha->value : 2*frac*scr_conalpha->value) : 1;
|
|
Vector4Set (picColor, 1.0f, 1.0f, 1.0f, alpha);
|
|
|
|
// draw the background
|
|
//i = newconback_found ? lines - barheight : lines*(1/scr_conheight->value);
|
|
//j = newconback_found ? 0 : (scr_conheight->value-1)*i - barheight;
|
|
y = lines - barheight;
|
|
|
|
Vector2Copy (vec2_origin, ds.offset);
|
|
Vector4Copy (picColor, ds.color);
|
|
|
|
if (y < 1) y = 0;
|
|
/* else if (newconback_found && scr_newconback->integer) // Q3-style console
|
|
R_DrawStretchPic ((int)picLeft, 0, picWidth, lines-barheight, "/gfx/ui/newconback.pcx", alpha);
|
|
else
|
|
R_DrawStretchPic ((int)picLeft, (lines-(int)picHeight-(int)barheight), picWidth, (int)picHeight, "conback", alpha);
|
|
*/
|
|
else if (newconback_found && scr_newconback->integer) { // Q3-style console
|
|
ds.pic = "/gfx/ui/newconback.pcx";
|
|
// ds.x = (int)conLeft; ds.w = conWidth;
|
|
ds.x = (int)picLeft; ds.w = picWidth;
|
|
ds.y = 0; ds.h = lines-(int)barheight;
|
|
R_DrawPic (ds);
|
|
}
|
|
else {
|
|
ds.pic = "conback";
|
|
// ds.x = (int)conLeft; ds.w = conWidth;
|
|
ds.x = (int)picLeft; ds.w = picWidth;
|
|
ds.y = (lines-(int)picHeight-(int)barheight); ds.h = (int)picHeight;
|
|
R_DrawPic (ds);
|
|
}
|
|
|
|
// pillarbox sides if console is wider than scaled pic
|
|
if (conWidth > picWidth)
|
|
{
|
|
pboxWidth = picLeft - conLeft;
|
|
R_DrawFill ((int)conLeft, 0, (int)pboxWidth, lines-(int)barheight, 0, 0, 0, (int)(alpha*255.0f));
|
|
R_DrawFill ((int)picLeft + (int)picWidth, 0, (int)pboxWidth, lines-(int)barheight, 0, 0, 0, (int)(alpha*255.0f));
|
|
}
|
|
|
|
// changed to "KMQuake2 vx.xx"
|
|
#ifdef ERASER_COMPAT_BUILD
|
|
Com_sprintf (version, sizeof(version), S_COLOR_BOLD S_COLOR_SHADOW S_COLOR_ALT"KMQuake2 v%4.2fu%d (Eraser compatible)", VERSION, VERSION_UPDATE);
|
|
#else // ERASER_COMPAT_BUILD
|
|
Com_sprintf (version, sizeof(version), S_COLOR_BOLD S_COLOR_SHADOW S_COLOR_ALT"KMQuake2 v%4.2fu%d", VERSION, VERSION_UPDATE);
|
|
#endif // NEW_ENTITY_STATE_MEMBERS
|
|
|
|
Con_DrawString ((int)(conLeft+conWidth)-FONT_SIZE*(stringLen((const char *)&version))-3, y-(int)(1.25*FONT_SIZE), version, FONT_CONSOLE, 255);
|
|
|
|
// if ( (newconback_found && scr_newconback->value) || scr_oldconbar->value ) // Q3-style console bottom bar
|
|
if ( (newconback_found && scr_newconback->integer) || scr_oldconbar->integer ) // Q3-style console bottom bar
|
|
R_DrawFill ((int)conLeft, y, conWidth, barheight, red, green, blue, 255);
|
|
|
|
// draw the text
|
|
con.vislines = lines;
|
|
rows = (lines-(int)(2.75*FONT_SIZE))/FONT_SIZE; // rows of text to draw
|
|
y = lines - (int)(3.75*FONT_SIZE);
|
|
|
|
// draw from the bottom up
|
|
if (con.display != con.current)
|
|
{
|
|
// draw arrows to show the buffer is backscrolled
|
|
for (x = 0; x < con.linewidth; x+=4)
|
|
R_DrawChar ((int)conLeft + (x+1)*FONT_SIZE, y, '^', FONT_CONSOLE, CON_FONT_SCALE, 255, 0, 0, 255, false, ((x+4)>=con.linewidth) );
|
|
|
|
y -= FONT_SIZE;
|
|
rows--;
|
|
}
|
|
|
|
row = con.display;
|
|
for (i=0; i<rows; i++, y-=FONT_SIZE, row--)
|
|
{
|
|
if (row < 0)
|
|
break;
|
|
if (con.current - row >= con.totallines)
|
|
break; // past scrollback wrap point
|
|
|
|
text = con.text + (row % con.totallines)*con.linewidth;
|
|
|
|
Com_sprintf (output, sizeof(output), "");
|
|
for (x=0; x<con.linewidth; x++) {
|
|
// Com_sprintf (output, sizeof(output), "%s%c", output, text[x]);
|
|
addch[0] = text[x];
|
|
addch[1] = '\0';
|
|
Q_strncatz (output, sizeof(output), addch);
|
|
}
|
|
Con_DrawString ((int)conLeft + 4, y, output, FONT_CONSOLE, 255);
|
|
}
|
|
|
|
// ZOID- draw the download bar
|
|
#ifdef USE_CURL // HTTP downloading from R1Q2
|
|
if ( cls.downloadname[0] && (cls.download || cls.downloadposition) )
|
|
#else
|
|
if (cls.download)
|
|
#endif // USE_CURL
|
|
{
|
|
Con_DrawDownloadProgress (conLeft, conWidth, barheight, stringLen((const char *)&version), red, green, blue);
|
|
}
|
|
//ZOID
|
|
|
|
// draw the input prompt, user text, and cursor if desired
|
|
Con_DrawInput ();
|
|
}
|