|
|
1.1 root 1: // console.c
2:
3: #include "client.h"
4:
5: console_t con;
6:
7: cvar_t *con_notifytime;
8:
9:
10: #define MAXCMDLINE 256
11: extern char key_lines[32][MAXCMDLINE];
12: extern int edit_line;
13: extern int key_linepos;
14:
15:
16: void DrawString (int x, int y, char *s)
17: {
18: while (*s)
19: {
20: re.DrawChar (x, y, *s);
21: x+=8;
22: s++;
23: }
24: }
25:
26: void DrawAltString (int x, int y, char *s)
27: {
28: while (*s)
29: {
30: re.DrawChar (x, y, *s ^ 0x80);
31: x+=8;
32: s++;
33: }
34: }
35:
36:
37: void Key_ClearTyping (void)
38: {
39: key_lines[edit_line][1] = 0; // clear any typing
40: key_linepos = 1;
41: }
42:
43: /*
44: ================
45: Con_ToggleConsole_f
46: ================
47: */
48: void Con_ToggleConsole_f (void)
49: {
50: SCR_EndLoadingPlaque (); // get rid of loading plaque
51:
52: if (cl.attractloop)
53: {
54: Cbuf_AddText ("killserver\n");
55: return;
56: }
57:
58: if (cls.state == ca_disconnected)
59: { // start the demo loop again
60: Cbuf_AddText ("d1\n");
61: return;
62: }
63:
64: Key_ClearTyping ();
65: Con_ClearNotify ();
66:
67: if (cls.key_dest == key_console)
68: {
69: M_ForceMenuOff ();
70: Cvar_Set ("paused", "0");
71: }
72: else
73: {
74: M_ForceMenuOff ();
75: cls.key_dest = key_console;
76:
77: if (Cvar_VariableValue ("maxclients") == 1
78: && Com_ServerState ())
79: Cvar_Set ("paused", "1");
80: }
81: }
82:
83: /*
84: ================
85: Con_ToggleChat_f
86: ================
87: */
88: void Con_ToggleChat_f (void)
89: {
90: Key_ClearTyping ();
91:
92: if (cls.key_dest == key_console)
93: {
94: if (cls.state == ca_active)
95: {
96: M_ForceMenuOff ();
97: cls.key_dest = key_game;
98: }
99: }
100: else
101: cls.key_dest = key_console;
102:
103: Con_ClearNotify ();
104: }
105:
106: /*
107: ================
108: Con_Clear_f
109: ================
110: */
111: void Con_Clear_f (void)
112: {
113: memset (con.text, ' ', CON_TEXTSIZE);
114: }
115:
116:
117: /*
118: ================
119: Con_Dump_f
120:
121: Save the console contents out to a file
122: ================
123: */
124: void Con_Dump_f (void)
125: {
126: int l, x;
127: char *line;
128: FILE *f;
129: char buffer[1024];
130: char name[MAX_OSPATH];
131:
132: if (Cmd_Argc() != 2)
133: {
134: Com_Printf ("usage: condump <filename>\n");
135: return;
136: }
137:
138: Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
139:
140: Com_Printf ("Dumped console text to %s.\n", name);
141: FS_CreatePath (name);
142: f = fopen (name, "w");
143: if (!f)
144: {
145: Com_Printf ("ERROR: couldn't open.\n");
146: return;
147: }
148:
149: // skip empty lines
150: for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
151: {
152: line = con.text + (l%con.totallines)*con.linewidth;
153: for (x=0 ; x<con.linewidth ; x++)
154: if (line[x] != ' ')
155: break;
156: if (x != con.linewidth)
157: break;
158: }
159:
160: // write the remaining lines
161: buffer[con.linewidth] = 0;
162: for ( ; l <= con.current ; l++)
163: {
164: line = con.text + (l%con.totallines)*con.linewidth;
165: strncpy (buffer, line, con.linewidth);
166: for (x=con.linewidth-1 ; x>=0 ; x--)
167: {
168: if (buffer[x] == ' ')
169: buffer[x] = 0;
170: else
171: break;
172: }
1.1.1.2 ! root 173: for (x=0; buffer[x]; x++)
! 174: buffer[x] &= 0x7f;
1.1 root 175:
176: fprintf (f, "%s\n", buffer);
177: }
178:
179: fclose (f);
180: }
181:
182:
183: /*
184: ================
185: Con_ClearNotify
186: ================
187: */
188: void Con_ClearNotify (void)
189: {
190: int i;
191:
192: for (i=0 ; i<NUM_CON_TIMES ; i++)
193: con.times[i] = 0;
194: }
195:
196:
197: /*
198: ================
199: Con_MessageMode_f
200: ================
201: */
202: void Con_MessageMode_f (void)
203: {
204: chat_team = false;
205: cls.key_dest = key_message;
206: }
207:
208: /*
209: ================
210: Con_MessageMode2_f
211: ================
212: */
213: void Con_MessageMode2_f (void)
214: {
215: chat_team = true;
216: cls.key_dest = key_message;
217: }
218:
219: /*
220: ================
221: Con_CheckResize
222:
223: If the line width has changed, reformat the buffer.
224: ================
225: */
226: void Con_CheckResize (void)
227: {
228: int i, j, width, oldwidth, oldtotallines, numlines, numchars;
229: char tbuf[CON_TEXTSIZE];
230:
231: width = (viddef.width >> 3) - 2;
232:
233: if (width == con.linewidth)
234: return;
235:
236: if (width < 1) // video hasn't been initialized yet
237: {
238: width = 38;
239: con.linewidth = width;
240: con.totallines = CON_TEXTSIZE / con.linewidth;
241: memset (con.text, ' ', CON_TEXTSIZE);
242: }
243: else
244: {
245: oldwidth = con.linewidth;
246: con.linewidth = width;
247: oldtotallines = con.totallines;
248: con.totallines = CON_TEXTSIZE / con.linewidth;
249: numlines = oldtotallines;
250:
251: if (con.totallines < numlines)
252: numlines = con.totallines;
253:
254: numchars = oldwidth;
255:
256: if (con.linewidth < numchars)
257: numchars = con.linewidth;
258:
259: memcpy (tbuf, con.text, CON_TEXTSIZE);
260: memset (con.text, ' ', CON_TEXTSIZE);
261:
262: for (i=0 ; i<numlines ; i++)
263: {
264: for (j=0 ; j<numchars ; j++)
265: {
266: con.text[(con.totallines - 1 - i) * con.linewidth + j] =
267: tbuf[((con.current - i + oldtotallines) %
268: oldtotallines) * oldwidth + j];
269: }
270: }
271:
272: Con_ClearNotify ();
273: }
274:
275: con.current = con.totallines - 1;
276: con.display = con.current;
277: }
278:
279:
280: /*
281: ================
282: Con_Init
283: ================
284: */
285: void Con_Init (void)
286: {
287: con.linewidth = -1;
288:
289: Con_CheckResize ();
290:
291: Com_Printf ("Console initialized.\n");
292:
293: //
294: // register our commands
295: //
296: con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
297:
298: Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
299: Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
300: Cmd_AddCommand ("messagemode", Con_MessageMode_f);
301: Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
302: Cmd_AddCommand ("clear", Con_Clear_f);
303: Cmd_AddCommand ("condump", Con_Dump_f);
304: con.initialized = true;
305: }
306:
307:
308: /*
309: ===============
310: Con_Linefeed
311: ===============
312: */
313: void Con_Linefeed (void)
314: {
315: con.x = 0;
316: if (con.display == con.current)
317: con.display++;
318: con.current++;
319: memset (&con.text[(con.current%con.totallines)*con.linewidth]
320: , ' ', con.linewidth);
321: }
322:
323: /*
324: ================
325: Con_Print
326:
327: Handles cursor positioning, line wrapping, etc
328: All console printing must go through this in order to be logged to disk
329: If no console is visible, the text will appear at the top of the game window
330: ================
331: */
332: void Con_Print (char *txt)
333: {
334: int y;
335: int c, l;
336: static int cr;
337: int mask;
338:
339: if (!con.initialized)
340: return;
341:
342: if (txt[0] == 1 || txt[0] == 2)
343: {
344: mask = 128; // go to colored text
345: txt++;
346: }
347: else
348: mask = 0;
349:
350:
351: while ( (c = *txt) )
352: {
353: // count word length
354: for (l=0 ; l< con.linewidth ; l++)
355: if ( txt[l] <= ' ')
356: break;
357:
358: // word wrap
359: if (l != con.linewidth && (con.x + l > con.linewidth) )
360: con.x = 0;
361:
362: txt++;
363:
364: if (cr)
365: {
366: con.current--;
367: cr = false;
368: }
369:
370:
371: if (!con.x)
372: {
373: Con_Linefeed ();
374: // mark time for transparent overlay
375: if (con.current >= 0)
376: con.times[con.current % NUM_CON_TIMES] = cls.realtime;
377: }
378:
379: switch (c)
380: {
381: case '\n':
382: con.x = 0;
383: break;
384:
385: case '\r':
386: con.x = 0;
387: cr = 1;
388: break;
389:
390: default: // display character and advance
391: y = con.current % con.totallines;
392: con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
393: con.x++;
394: if (con.x >= con.linewidth)
395: con.x = 0;
396: break;
397: }
398:
399: }
400: }
401:
402:
403: /*
404: ==============
405: Con_CenteredPrint
406: ==============
407: */
408: void Con_CenteredPrint (char *text)
409: {
410: int l;
411: char buffer[1024];
412:
413: l = strlen(text);
414: l = (con.linewidth-l)/2;
415: if (l < 0)
416: l = 0;
417: memset (buffer, ' ', l);
418: strcpy (buffer+l, text);
419: strcat (buffer, "\n");
420: Con_Print (buffer);
421: }
422:
423: /*
424: ==============================================================================
425:
426: DRAWING
427:
428: ==============================================================================
429: */
430:
431:
432: /*
433: ================
434: Con_DrawInput
435:
436: The input line scrolls horizontally if typing goes beyond the right edge
437: ================
438: */
439: void Con_DrawInput (void)
440: {
441: int y;
442: int i;
443: char *text;
444:
445: if (cls.key_dest == key_menu)
446: return;
447: if (cls.key_dest != key_console && cls.state == ca_active)
448: return; // don't draw anything (always draw if not active)
449:
450: text = key_lines[edit_line];
451:
452: // add the cursor frame
453: text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
454:
455: // fill out remainder with spaces
456: for (i=key_linepos+1 ; i< con.linewidth ; i++)
457: text[i] = ' ';
458:
459: // prestep if horizontally scrolling
460: if (key_linepos >= con.linewidth)
461: text += 1 + key_linepos - con.linewidth;
462:
463: // draw it
464: y = con.vislines-16;
465:
466: for (i=0 ; i<con.linewidth ; i++)
1.1.1.2 ! root 467: re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
1.1 root 468:
469: // remove cursor
470: key_lines[edit_line][key_linepos] = 0;
471: }
472:
473:
474: /*
475: ================
476: Con_DrawNotify
477:
478: Draws the last few lines of output transparently over the game top
479: ================
480: */
481: void Con_DrawNotify (void)
482: {
483: int x, v;
484: char *text;
485: int i;
486: int time;
487: char *s;
488: int skip;
489:
490: v = 0;
491: for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
492: {
493: if (i < 0)
494: continue;
495: time = con.times[i % NUM_CON_TIMES];
496: if (time == 0)
497: continue;
498: time = cls.realtime - time;
499: if (time > con_notifytime->value*1000)
500: continue;
501: text = con.text + (i % con.totallines)*con.linewidth;
502:
503: for (x = 0 ; x < con.linewidth ; x++)
504: re.DrawChar ( (x+1)<<3, v, text[x]);
505:
506: v += 8;
507: }
508:
509:
510: if (cls.key_dest == key_message)
511: {
512: if (chat_team)
513: {
514: DrawString (8, v, "say_team:");
515: skip = 11;
516: }
517: else
518: {
519: DrawString (8, v, "say:");
520: skip = 5;
521: }
522:
523: s = chat_buffer;
524: if (chat_bufferlen > (viddef.width>>3)-(skip+1))
525: s += chat_bufferlen - ((viddef.width>>3)-(skip+1));
526: x = 0;
527: while(s[x])
528: {
529: re.DrawChar ( (x+skip)<<3, v, s[x]);
530: x++;
531: }
532: re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
533: v += 8;
534: }
535:
536: if (v)
537: {
538: SCR_AddDirtyPoint (0,0);
539: SCR_AddDirtyPoint (viddef.width-1, v);
540: }
541: }
542:
543: /*
544: ================
545: Con_DrawConsole
546:
547: Draws the console with the solid background
548: ================
549: */
550: void Con_DrawConsole (float frac)
551: {
1.1.1.2 ! root 552: int i, j, x, y, n;
1.1 root 553: int rows;
554: char *text;
555: int row;
556: int lines;
557: char version[64];
1.1.1.2 ! root 558: char dlbar[1024];
1.1 root 559:
560: lines = viddef.height * frac;
561: if (lines <= 0)
562: return;
563:
564: if (lines > viddef.height)
565: lines = viddef.height;
566:
567: // draw the background
568: re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback");
569: SCR_AddDirtyPoint (0,0);
570: SCR_AddDirtyPoint (viddef.width-1,lines-1);
571:
572: Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
573: for (x=0 ; x<5 ; x++)
574: re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version[x] );
575:
576: // draw the text
577: con.vislines = lines;
578:
1.1.1.2 ! root 579: #if 0
1.1 root 580: rows = (lines-8)>>3; // rows of text to draw
581:
582: y = lines - 24;
1.1.1.2 ! root 583: #else
! 584: rows = (lines-22)>>3; // rows of text to draw
! 585:
! 586: y = lines - 30;
! 587: #endif
1.1 root 588:
589: // draw from the bottom up
590: if (con.display != con.current)
591: {
592: // draw arrows to show the buffer is backscrolled
593: for (x=0 ; x<con.linewidth ; x+=4)
594: re.DrawChar ( (x+1)<<3, y, '^');
595:
596: y -= 8;
597: rows--;
598: }
599:
600: row = con.display;
601: for (i=0 ; i<rows ; i++, y-=8, row--)
602: {
603: if (row < 0)
604: break;
605: if (con.current - row >= con.totallines)
606: break; // past scrollback wrap point
607:
608: text = con.text + (row % con.totallines)*con.linewidth;
609:
610: for (x=0 ; x<con.linewidth ; x++)
611: re.DrawChar ( (x+1)<<3, y, text[x]);
612: }
613:
1.1.1.2 ! root 614: //ZOID
! 615: // draw the download bar
! 616: // figure out width
! 617: if (cls.download) {
! 618: if ((text = strrchr(cls.downloadname, '/')) != NULL)
! 619: text++;
! 620: else
! 621: text = cls.downloadname;
! 622:
! 623: x = con.linewidth - ((con.linewidth * 7) / 40);
! 624: y = x - strlen(text) - 8;
! 625: i = con.linewidth/3;
! 626: if (strlen(text) > i) {
! 627: y = x - i - 11;
! 628: strncpy(dlbar, text, i);
! 629: dlbar[i] = 0;
! 630: strcat(dlbar, "...");
! 631: } else
! 632: strcpy(dlbar, text);
! 633: strcat(dlbar, ": ");
! 634: i = strlen(dlbar);
! 635: dlbar[i++] = '\x80';
! 636: // where's the dot go?
! 637: if (cls.downloadpercent == 0)
! 638: n = 0;
! 639: else
! 640: n = y * cls.downloadpercent / 100;
! 641:
! 642: for (j = 0; j < y; j++)
! 643: if (j == n)
! 644: dlbar[i++] = '\x83';
! 645: else
! 646: dlbar[i++] = '\x81';
! 647: dlbar[i++] = '\x82';
! 648: dlbar[i] = 0;
! 649:
! 650: sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
! 651:
! 652: // draw it
! 653: y = con.vislines-12;
! 654: for (i = 0; i < strlen(dlbar); i++)
! 655: re.DrawChar ( (i+1)<<3, y, dlbar[i]);
! 656: }
! 657: //ZOID
! 658:
1.1 root 659: // draw the input prompt, user text, and cursor if desired
660: Con_DrawInput ();
661: }
662:
663:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.