/* * Copyright (C) 1997-2001 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. * * ======================================================================= * * This file implements the console * * ======================================================================= */ #include "../header/client.h" #include console_t con; cvar_t *con_notifytime; #define MAXCMDLINE 256 extern char key_lines[32][MAXCMDLINE]; extern int edit_line; extern int key_linepos; void DrawString (int x, int y, char *s) { while (*s) { re.DrawChar (x, y, *s); x+=8; s++; } } void DrawAltString (int x, int y, char *s) { while (*s) { re.DrawChar (x, y, *s ^ 0x80); x+=8; s++; } } void Key_ClearTyping (void) { key_lines[edit_line][1] = 0; /* clear any typing */ key_linepos = 1; } void Con_ToggleConsole_f (void) { SCR_EndLoadingPlaque (); /* get rid of loading plaque */ if (cl.attractloop) { Cvar_SetValue("windowed_mouse", 0); Cbuf_AddText("killserver\n"); return; } if (cls.state == ca_disconnected) { /* start the demo loop again */ Cvar_SetValue("windowed_mouse", 1); Cbuf_AddText ("d1\n"); return; } Key_ClearTyping (); Con_ClearNotify (); if (cls.key_dest == key_console) { M_ForceMenuOff (); Cvar_Set ("paused", "0"); } else { M_ForceMenuOff (); cls.key_dest = key_console; if (Cvar_VariableValue ("maxclients") == 1 && Com_ServerState ()) Cvar_Set ("paused", "1"); } } void Con_ToggleChat_f (void) { Key_ClearTyping (); if (cls.key_dest == key_console) { if (cls.state == ca_active) { M_ForceMenuOff (); cls.key_dest = key_game; } } else cls.key_dest = key_console; Con_ClearNotify (); } void Con_Clear_f (void) { memset (con.text, ' ', CON_TEXTSIZE); } /* * 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 \n"); return; } Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1)); 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=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); } void Con_ClearNotify (void) { int i; for (i=0 ; i> 3) - 2; if (width == con.linewidth) return; /* video hasn't been initialized yet */ if (width < 1) { 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] = cls.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.ormask; con.x++; if (con.x >= con.linewidth) con.x = 0; break; } } } void Con_CenteredPrint (char *text) { int l; char buffer[1024]; l = strlen(text); l = (con.linewidth-l)/2; if (l < 0) l = 0; memset (buffer, ' ', l); strcpy (buffer+l, text); strcat (buffer, "\n"); Con_Print (buffer); } /* * The input line scrolls horizontally if * typing goes beyond the right edge */ void Con_DrawInput (void) { int y; int i; char *text; if (cls.key_dest == key_menu) return; /* don't draw anything (always draw if not active) */ if (cls.key_dest != key_console && cls.state == ca_active) return; text = key_lines[edit_line]; /* add the cursor frame */ 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-16; for (i=0 ; i con_notifytime->value*1000) continue; text = con.text + (i % con.totallines)*con.linewidth; for (x = 0 ; x < con.linewidth ; x++) re.DrawChar ( (x+1)<<3, v, text[x]); v += 8; } if (cls.key_dest == key_message) { if (chat_team) { DrawString (8, v, "say_team:"); skip = 11; } else { DrawString (8, v, "say:"); skip = 5; } s = chat_buffer; if (chat_bufferlen > (viddef.width>>3)-(skip+1)) s += chat_bufferlen - ((viddef.width>>3)-(skip+1)); x = 0; while(s[x]) { re.DrawChar ( (x+skip)<<3, v, s[x]); x++; } re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1)); v += 8; } if (v) { SCR_AddDirtyPoint (0,0); SCR_AddDirtyPoint (viddef.width-1, v); } } /* * Draws the console with the solid background */ void Con_DrawConsole (float frac) { int i, j, x, y, n; int rows; char *text; int row; int lines; char version[48]; char dlbar[1024]; char timebuf[48]; char tmpbuf[48]; time_t t; struct tm *today; lines = viddef.height * frac; if (lines <= 0) return; if (lines > viddef.height) lines = viddef.height; /* draw the background */ re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback"); SCR_AddDirtyPoint (0,0); SCR_AddDirtyPoint (viddef.width-1,lines-1); Com_sprintf (version, sizeof(version), "Yamagi Quake II v%4.2f",VERSION); for (x=0 ; x<21 ; x++) re.DrawChar (viddef.width-173+x*8, lines-35, 128 + version[x] ); t = time(NULL); today = localtime(&t); strftime (timebuf, sizeof(timebuf), "%H:%M:%S - %m/%d/%Y", today); Com_sprintf (tmpbuf, sizeof(tmpbuf), "%s",timebuf); for (x=0 ; x<21 ; x++) re.DrawChar (viddef.width-173+x*8, lines-25, 128 + tmpbuf[x] ); /* draw the text */ con.vislines = lines; rows = (lines-22)>>3; /* rows of text to draw */ y = lines - 30; /* draw from the bottom up */ if (con.display != con.current) { /* draw arrows to show the buffer is backscrolled */ for (x=0 ; x= con.totallines) break; /* past scrollback wrap point */ text = con.text + (row % con.totallines)*con.linewidth; for (x=0 ; x i) { y = x - i - 11; strncpy(dlbar, text, i); dlbar[i] = 0; strcat(dlbar, "..."); } else strcpy(dlbar, text); strcat(dlbar, ": "); i = strlen(dlbar); dlbar[i++] = '\x80'; /* where's the dot gone? */ if (cls.downloadpercent == 0) n = 0; else n = y * cls.downloadpercent / 100; for (j = 0; j < y; j++) if (j == n) dlbar[i++] = '\x83'; else dlbar[i++] = '\x81'; dlbar[i++] = '\x82'; dlbar[i] = 0; sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent); /* draw it */ y = con.vislines-12; for (i = 0; i < strlen(dlbar); i++) re.DrawChar ( (i+1)<<3, y, dlbar[i]); } /* draw the input prompt, user text, and cursor if desired */ Con_DrawInput (); }