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