• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
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.
8 
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.
12 
13 See the GNU General Public License for more details.
14 
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.
18 
19 */
20 // console.c
21 
22 #include "quakedef.h"
23 
24 int			con_ormask;
25 console_t	con_main;
26 console_t	con_chat;
27 console_t	*con;			// point to either con_main or con_chat
28 
29 int 		con_linewidth;	// characters across screen
30 int			con_totallines;		// total lines in console scrollback
31 
32 float		con_cursorspeed = 4;
33 
34 
35 cvar_t		con_notifytime = CVAR2("con_notifytime","3");		//seconds
36 
37 #define	NUM_CON_TIMES 4
38 float		con_times[NUM_CON_TIMES];	// realtime time the line was generated
39 								// for transparent notify lines
40 
41 int			con_vislines;
42 int			con_notifylines;		// scan lines to clear for notify lines
43 
44 qboolean	con_debuglog;
45 
46 #define		MAXCMDLINE	256
47 extern	char	key_lines[32][MAXCMDLINE];
48 extern	int		edit_line;
49 extern	int		key_linepos;
50 
51 
52 qboolean	con_initialized;
53 
54 
Key_ClearTyping(void)55 void Key_ClearTyping (void)
56 {
57 	key_lines[edit_line][1] = 0;	// clear any typing
58 	key_linepos = 1;
59 }
60 
61 /*
62 ================
63 Con_ToggleConsole_f
64 ================
65 */
Con_ToggleConsole_f(void)66 void Con_ToggleConsole_f (void)
67 {
68 	Key_ClearTyping ();
69 
70 	if (key_dest == key_console)
71 	{
72 		if (cls.state == ca_active)
73 			key_dest = key_game;
74 	}
75 	else
76 		key_dest = key_console;
77 
78 	Con_ClearNotify ();
79 }
80 
81 /*
82 ================
83 Con_ToggleChat_f
84 ================
85 */
Con_ToggleChat_f(void)86 void Con_ToggleChat_f (void)
87 {
88 	Key_ClearTyping ();
89 
90 	if (key_dest == key_console)
91 	{
92 		if (cls.state == ca_active)
93 			key_dest = key_game;
94 	}
95 	else
96 		key_dest = key_console;
97 
98 	Con_ClearNotify ();
99 }
100 
101 /*
102 ================
103 Con_Clear_f
104 ================
105 */
Con_Clear_f(void)106 void Con_Clear_f (void)
107 {
108 	Q_memset (con_main.text, ' ', CON_TEXTSIZE);
109 	Q_memset (con_chat.text, ' ', CON_TEXTSIZE);
110 }
111 
112 
113 /*
114 ================
115 Con_ClearNotify
116 ================
117 */
Con_ClearNotify(void)118 void Con_ClearNotify (void)
119 {
120 	int		i;
121 
122 	for (i=0 ; i<NUM_CON_TIMES ; i++)
123 		con_times[i] = 0;
124 }
125 
126 
127 /*
128 ================
129 Con_MessageMode_f
130 ================
131 */
Con_MessageMode_f(void)132 void Con_MessageMode_f (void)
133 {
134 	chat_team = false;
135 	key_dest = key_message;
136 }
137 
138 /*
139 ================
140 Con_MessageMode2_f
141 ================
142 */
Con_MessageMode2_f(void)143 void Con_MessageMode2_f (void)
144 {
145 	chat_team = true;
146 	key_dest = key_message;
147 }
148 
149 /*
150 ================
151 Con_Resize
152 
153 ================
154 */
Con_Resize(console_t * con)155 void Con_Resize (console_t *con)
156 {
157 	int		i, j, width, oldwidth, oldtotallines, numlines, numchars;
158 	char	tbuf[CON_TEXTSIZE];
159 
160 	width = (vid.width >> 3) - 2;
161 
162 	if (width == con_linewidth)
163 		return;
164 
165 	if (width < 1)			// video hasn't been initialized yet
166 	{
167 		width = 38;
168 		con_linewidth = width;
169 		con_totallines = CON_TEXTSIZE / con_linewidth;
170 		Q_memset (con->text, ' ', CON_TEXTSIZE);
171 	}
172 	else
173 	{
174 		oldwidth = con_linewidth;
175 		con_linewidth = width;
176 		oldtotallines = con_totallines;
177 		con_totallines = CON_TEXTSIZE / con_linewidth;
178 		numlines = oldtotallines;
179 
180 		if (con_totallines < numlines)
181 			numlines = con_totallines;
182 
183 		numchars = oldwidth;
184 
185 		if (con_linewidth < numchars)
186 			numchars = con_linewidth;
187 
188 		Q_memcpy (tbuf, con->text, CON_TEXTSIZE);
189 		Q_memset (con->text, ' ', CON_TEXTSIZE);
190 
191 		for (i=0 ; i<numlines ; i++)
192 		{
193 			for (j=0 ; j<numchars ; j++)
194 			{
195 				con->text[(con_totallines - 1 - i) * con_linewidth + j] =
196 						tbuf[((con->current - i + oldtotallines) %
197 							  oldtotallines) * oldwidth + j];
198 			}
199 		}
200 
201 		Con_ClearNotify ();
202 	}
203 
204 	con->current = con_totallines - 1;
205 	con->display = con->current;
206 }
207 
208 
209 /*
210 ================
211 Con_CheckResize
212 
213 If the line width has changed, reformat the buffer.
214 ================
215 */
Con_CheckResize(void)216 void Con_CheckResize (void)
217 {
218 	Con_Resize (&con_main);
219 	Con_Resize (&con_chat);
220 }
221 
222 
223 /*
224 ================
225 Con_Init
226 ================
227 */
Con_Init(void)228 void Con_Init (void)
229 {
230 	con_debuglog = COM_CheckParm("-condebug");
231 
232 	con = &con_main;
233 	con_linewidth = -1;
234 	Con_CheckResize ();
235 
236 	Con_Printf ("Console initialized.\n");
237 
238 //
239 // register our commands
240 //
241 	Cvar_RegisterVariable (&con_notifytime);
242 
243 	Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
244 	Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
245 	Cmd_AddCommand ("messagemode", Con_MessageMode_f);
246 	Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
247 	Cmd_AddCommand ("clear", Con_Clear_f);
248 	con_initialized = true;
249 }
250 
251 
252 /*
253 ===============
254 Con_Linefeed
255 ===============
256 */
Con_Linefeed(void)257 void Con_Linefeed (void)
258 {
259 	con->x = 0;
260 	if (con->display == con->current)
261 		con->display++;
262 	con->current++;
263 	Q_memset (&con->text[(con->current%con_totallines)*con_linewidth]
264 	, ' ', con_linewidth);
265 }
266 
267 /*
268 ================
269 Con_Print
270 
271 Handles cursor positioning, line wrapping, etc
272 All console printing must go through this in order to be logged to disk
273 If no console is visible, the notify window will pop up.
274 ================
275 */
Con_Print(char * txt)276 void Con_Print (char *txt)
277 {
278 	int		y;
279 	int		c, l;
280 	static int	cr;
281 	int		mask;
282 
283 	if (txt[0] == 1 || txt[0] == 2)
284 	{
285 		mask = 128;		// go to colored text
286 		txt++;
287 	}
288 	else
289 		mask = 0;
290 
291 
292 	while ( (c = *txt) )
293 	{
294 	// count word length
295 		for (l=0 ; l< con_linewidth ; l++)
296 			if ( txt[l] <= ' ')
297 				break;
298 
299 	// word wrap
300 		if (l != con_linewidth && (con->x + l > con_linewidth) )
301 			con->x = 0;
302 
303 		txt++;
304 
305 		if (cr)
306 		{
307 			con->current--;
308 			cr = false;
309 		}
310 
311 
312 		if (!con->x)
313 		{
314 			Con_Linefeed ();
315 		// mark time for transparent overlay
316 			if (con->current >= 0)
317 				con_times[con->current % NUM_CON_TIMES] = realtime;
318 		}
319 
320 		switch (c)
321 		{
322 		case '\n':
323 			con->x = 0;
324 			break;
325 
326 		case '\r':
327 			con->x = 0;
328 			cr = 1;
329 			break;
330 
331 		default:	// display character and advance
332 			y = con->current % con_totallines;
333 			con->text[y*con_linewidth+con->x] = c | mask | con_ormask;
334 			con->x++;
335 			if (con->x >= con_linewidth)
336 				con->x = 0;
337 			break;
338 		}
339 
340 	}
341 }
342 
343 
344 /*
345 ================
346 Con_Printf
347 
348 Handles cursor positioning, line wrapping, etc
349 ================
350 */
351 #define	MAXPRINTMSG	4096
352 // FIXME: make a buffer size safe vsprintf?
Con_Printf(char * fmt,...)353 void Con_Printf (char *fmt, ...)
354 {
355 	va_list		argptr;
356 	char		msg[MAXPRINTMSG];
357 	static qboolean	inupdate;
358 
359 	va_start (argptr,fmt);
360 	vsprintf (msg,fmt,argptr);
361 	va_end (argptr);
362 
363 // also echo to debugging console
364 	Sys_Printf ("%s", msg);	// also echo to debugging console
365 
366 // log all messages to file
367 	if (con_debuglog)
368 		Sys_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
369 
370 	if (!con_initialized)
371 		return;
372 
373 // write it to the scrollable buffer
374 	Con_Print (msg);
375 
376 // update the screen immediately if the console is displayed
377 	if (cls.state != ca_active)
378 	{
379 	// protect against infinite loop if something in SCR_UpdateScreen calls
380 	// Con_Printd
381 		if (!inupdate)
382 		{
383 			inupdate = true;
384 			SCR_UpdateScreen ();
385 			inupdate = false;
386 		}
387 	}
388 }
389 
390 /*
391 ================
392 Con_DPrintf
393 
394 A Con_Printf that only shows up if the "developer" cvar is set
395 ================
396 */
Con_DPrintf(char * fmt,...)397 void Con_DPrintf (char *fmt, ...)
398 {
399 	va_list		argptr;
400 	char		msg[MAXPRINTMSG];
401 
402 	if (!developer.value)
403 		return;			// don't confuse non-developers with techie stuff...
404 
405 	va_start (argptr,fmt);
406 	vsprintf (msg,fmt,argptr);
407 	va_end (argptr);
408 
409 	Con_Printf ("%s", msg);
410 }
411 
412 /*
413 ==============================================================================
414 
415 DRAWING
416 
417 ==============================================================================
418 */
419 
420 
421 /*
422 ================
423 Con_DrawInput
424 
425 The input line scrolls horizontally if typing goes beyond the right edge
426 ================
427 */
Con_DrawInput(void)428 void Con_DrawInput (void)
429 {
430 	int		y;
431 	int		i;
432 	char	*text;
433 
434 	if (key_dest != key_console && cls.state == ca_active)
435 		return;		// don't draw anything (allways draw if not active)
436 
437 	text = key_lines[edit_line];
438 
439 // add the cursor frame
440 	text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
441 
442 // fill out remainder with spaces
443 	for (i=key_linepos+1 ; i< con_linewidth ; i++)
444 		text[i] = ' ';
445 
446 //	prestep if horizontally scrolling
447 	if (key_linepos >= con_linewidth)
448 		text += 1 + key_linepos - con_linewidth;
449 
450 // draw it
451 	y = con_vislines-22;
452 
453 	for (i=0 ; i<con_linewidth ; i++)
454 		Draw_Character ( (i+1)<<3, con_vislines - 22, text[i]);
455 
456 // remove cursor
457 	key_lines[edit_line][key_linepos] = 0;
458 }
459 
460 
461 /*
462 ================
463 Con_DrawNotify
464 
465 Draws the last few lines of output transparently over the game top
466 ================
467 */
Con_DrawNotify(void)468 void Con_DrawNotify (void)
469 {
470 	int		x, v;
471 	char	*text;
472 	int		i;
473 	float	time;
474 	char	*s;
475 	int		skip;
476 
477 	v = 0;
478 	for (i= con->current-NUM_CON_TIMES+1 ; i<=con->current ; i++)
479 	{
480 		if (i < 0)
481 			continue;
482 		time = con_times[i % NUM_CON_TIMES];
483 		if (time == 0)
484 			continue;
485 		time = realtime - time;
486 		if (time > con_notifytime.value)
487 			continue;
488 		text = con->text + (i % con_totallines)*con_linewidth;
489 
490 		clearnotify = 0;
491 		scr_copytop = 1;
492 
493 		for (x = 0 ; x < con_linewidth ; x++)
494 			Draw_Character ( (x+1)<<3, v, text[x]);
495 
496 		v += 8;
497 	}
498 
499 
500 	if (key_dest == key_message)
501 	{
502 		clearnotify = 0;
503 		scr_copytop = 1;
504 
505 		if (chat_team)
506 		{
507 			Draw_String (8, v, "say_team:");
508 			skip = 11;
509 		}
510 		else
511 		{
512 			Draw_String (8, v, "say:");
513 			skip = 5;
514 		}
515 
516 		s = chat_buffer;
517 		if (chat_bufferlen > (int) ((vid.width>>3)-(skip+1)))
518 			s += chat_bufferlen - ((vid.width>>3)-(skip+1));
519 		x = 0;
520 		while(s[x])
521 		{
522 			Draw_Character ( (x+skip)<<3, v, s[x]);
523 			x++;
524 		}
525 		Draw_Character ( (x+skip)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
526 		v += 8;
527 	}
528 
529 	if (v > con_notifylines)
530 		con_notifylines = v;
531 }
532 
533 /*
534 ================
535 Con_DrawConsole
536 
537 Draws the console with the solid background
538 ================
539 */
Con_DrawConsole(int lines)540 void Con_DrawConsole (int lines)
541 {
542 	int				i, j, x, y, n;
543 	int				rows;
544 	char			*text;
545 	int				row;
546 	char			dlbar[1024];
547 
548 	if (lines <= 0)
549 		return;
550 
551 // draw the background
552 	Draw_ConsoleBackground (lines);
553 
554 // draw the text
555 	con_vislines = lines;
556 
557 // changed to line things up better
558 	rows = (lines-22)>>3;		// rows of text to draw
559 
560 	y = lines - 30;
561 
562 // draw from the bottom up
563 	if (con->display != con->current)
564 	{
565 	// draw arrows to show the buffer is backscrolled
566 		for (x=0 ; x<con_linewidth ; x+=4)
567 			Draw_Character ( (x+1)<<3, y, '^');
568 
569 		y -= 8;
570 		rows--;
571 	}
572 
573 	row = con->display;
574 	for (i=0 ; i<rows ; i++, y-=8, row--)
575 	{
576 		if (row < 0)
577 			break;
578 		if (con->current - row >= con_totallines)
579 			break;		// past scrollback wrap point
580 
581 		text = con->text + (row % con_totallines)*con_linewidth;
582 
583 		for (x=0 ; x<con_linewidth ; x++)
584 			Draw_Character ( (x+1)<<3, y, text[x]);
585 	}
586 
587 	// draw the download bar
588 	// figure out width
589 	if (cls.download) {
590 		if ((text = strrchr(cls.downloadname, '/')) != NULL)
591 			text++;
592 		else
593 			text = cls.downloadname;
594 
595 		x = con_linewidth - ((con_linewidth * 7) / 40);
596 		y = x - strlen(text) - 8;
597 		i = con_linewidth/3;
598 		if ((int) strlen(text) > i) {
599 			y = x - i - 11;
600 			strncpy(dlbar, text, i);
601 			dlbar[i] = 0;
602 			strcat(dlbar, "...");
603 		} else
604 			strcpy(dlbar, text);
605 		strcat(dlbar, ": ");
606 		i = strlen(dlbar);
607 		dlbar[i++] = '\x80';
608 		// where's the dot go?
609 		if (cls.downloadpercent == 0)
610 			n = 0;
611 		else
612 			n = y * cls.downloadpercent / 100;
613 
614 		for (j = 0; j < y; j++)
615 			if (j == n)
616 				dlbar[i++] = '\x83';
617 			else
618 				dlbar[i++] = '\x81';
619 		dlbar[i++] = '\x82';
620 		dlbar[i] = 0;
621 
622 		sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
623 
624 		// draw it
625 		y = con_vislines-22 + 8;
626 		for (i = 0; i < (int) strlen(dlbar); i++)
627 			Draw_Character ( (i+1)<<3, y, dlbar[i]);
628 	}
629 
630 
631 // draw the input prompt, user text, and cursor if desired
632 	Con_DrawInput ();
633 }
634 
635 
636 /*
637 ==================
638 Con_NotifyBox
639 ==================
640 */
Con_NotifyBox(char * text)641 void Con_NotifyBox (char *text)
642 {
643 	double		t1, t2;
644 
645 // during startup for sound / cd warnings
646 	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");
647 
648 	Con_Printf (text);
649 
650 	Con_Printf ("Press a key.\n");
651 	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");
652 
653 	key_count = -2;		// wait for a key down and up
654 	key_dest = key_console;
655 
656 	do
657 	{
658 		t1 = Sys_DoubleTime ();
659 		SCR_UpdateScreen ();
660 		Sys_SendKeyEvents ();
661 		t2 = Sys_DoubleTime ();
662 		realtime += t2-t1;		// make the cursor blink
663 	} while (key_count < 0);
664 
665 	Con_Printf ("\n");
666 	key_dest = key_game;
667 	realtime = 0;				// put the cursor back to invisible
668 }
669 
670 
671 /*
672 ==================
673 Con_SafePrintf
674 
675 Okay to call even when the screen can't be updated
676 ==================
677 */
Con_SafePrintf(char * fmt,...)678 void Con_SafePrintf (char *fmt, ...)
679 {
680 	va_list		argptr;
681 	char		msg[1024];
682 	int			temp;
683 
684 	va_start (argptr,fmt);
685 	vsprintf (msg,fmt,argptr);
686 	va_end (argptr);
687 
688 	temp = scr_disabled_for_loading;
689 	scr_disabled_for_loading = true;
690 	Con_Printf ("%s", msg);
691 	scr_disabled_for_loading = temp;
692 }
693 
694