|
|
1.1 root 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 = {"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:
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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?
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: */
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: */
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: */
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 > (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: */
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 (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 < 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: */
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: */
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.