|
|
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: }
173:
174: fprintf (f, "%s\n", buffer);
175: }
176:
177: fclose (f);
178: }
179:
180:
181: /*
182: ================
183: Con_ClearNotify
184: ================
185: */
186: void Con_ClearNotify (void)
187: {
188: int i;
189:
190: for (i=0 ; i<NUM_CON_TIMES ; i++)
191: con.times[i] = 0;
192: }
193:
194:
195: /*
196: ================
197: Con_MessageMode_f
198: ================
199: */
200: void Con_MessageMode_f (void)
201: {
202: chat_team = false;
203: cls.key_dest = key_message;
204: }
205:
206: /*
207: ================
208: Con_MessageMode2_f
209: ================
210: */
211: void Con_MessageMode2_f (void)
212: {
213: chat_team = true;
214: cls.key_dest = key_message;
215: }
216:
217: /*
218: ================
219: Con_CheckResize
220:
221: If the line width has changed, reformat the buffer.
222: ================
223: */
224: void Con_CheckResize (void)
225: {
226: int i, j, width, oldwidth, oldtotallines, numlines, numchars;
227: char tbuf[CON_TEXTSIZE];
228:
229: width = (viddef.width >> 3) - 2;
230:
231: if (width == con.linewidth)
232: return;
233:
234: if (width < 1) // video hasn't been initialized yet
235: {
236: width = 38;
237: con.linewidth = width;
238: con.totallines = CON_TEXTSIZE / con.linewidth;
239: memset (con.text, ' ', CON_TEXTSIZE);
240: }
241: else
242: {
243: oldwidth = con.linewidth;
244: con.linewidth = width;
245: oldtotallines = con.totallines;
246: con.totallines = CON_TEXTSIZE / con.linewidth;
247: numlines = oldtotallines;
248:
249: if (con.totallines < numlines)
250: numlines = con.totallines;
251:
252: numchars = oldwidth;
253:
254: if (con.linewidth < numchars)
255: numchars = con.linewidth;
256:
257: memcpy (tbuf, con.text, CON_TEXTSIZE);
258: memset (con.text, ' ', CON_TEXTSIZE);
259:
260: for (i=0 ; i<numlines ; i++)
261: {
262: for (j=0 ; j<numchars ; j++)
263: {
264: con.text[(con.totallines - 1 - i) * con.linewidth + j] =
265: tbuf[((con.current - i + oldtotallines) %
266: oldtotallines) * oldwidth + j];
267: }
268: }
269:
270: Con_ClearNotify ();
271: }
272:
273: con.current = con.totallines - 1;
274: con.display = con.current;
275: }
276:
277:
278: /*
279: ================
280: Con_Init
281: ================
282: */
283: void Con_Init (void)
284: {
285: con.linewidth = -1;
286:
287: Con_CheckResize ();
288:
289: Com_Printf ("Console initialized.\n");
290:
291: //
292: // register our commands
293: //
294: con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
295:
296: Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
297: Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
298: Cmd_AddCommand ("messagemode", Con_MessageMode_f);
299: Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
300: Cmd_AddCommand ("clear", Con_Clear_f);
301: Cmd_AddCommand ("condump", Con_Dump_f);
302: con.initialized = true;
303: }
304:
305:
306: /*
307: ===============
308: Con_Linefeed
309: ===============
310: */
311: void Con_Linefeed (void)
312: {
313: con.x = 0;
314: if (con.display == con.current)
315: con.display++;
316: con.current++;
317: memset (&con.text[(con.current%con.totallines)*con.linewidth]
318: , ' ', con.linewidth);
319: }
320:
321: /*
322: ================
323: Con_Print
324:
325: Handles cursor positioning, line wrapping, etc
326: All console printing must go through this in order to be logged to disk
327: If no console is visible, the text will appear at the top of the game window
328: ================
329: */
330: void Con_Print (char *txt)
331: {
332: int y;
333: int c, l;
334: static int cr;
335: int mask;
336:
337: if (!con.initialized)
338: return;
339:
340: if (txt[0] == 1 || txt[0] == 2)
341: {
342: mask = 128; // go to colored text
343: txt++;
344: }
345: else
346: mask = 0;
347:
348:
349: while ( (c = *txt) )
350: {
351: // count word length
352: for (l=0 ; l< con.linewidth ; l++)
353: if ( txt[l] <= ' ')
354: break;
355:
356: // word wrap
357: if (l != con.linewidth && (con.x + l > con.linewidth) )
358: con.x = 0;
359:
360: txt++;
361:
362: if (cr)
363: {
364: con.current--;
365: cr = false;
366: }
367:
368:
369: if (!con.x)
370: {
371: Con_Linefeed ();
372: // mark time for transparent overlay
373: if (con.current >= 0)
374: con.times[con.current % NUM_CON_TIMES] = cls.realtime;
375: }
376:
377: switch (c)
378: {
379: case '\n':
380: con.x = 0;
381: break;
382:
383: case '\r':
384: con.x = 0;
385: cr = 1;
386: break;
387:
388: default: // display character and advance
389: y = con.current % con.totallines;
390: con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
391: con.x++;
392: if (con.x >= con.linewidth)
393: con.x = 0;
394: break;
395: }
396:
397: }
398: }
399:
400:
401: /*
402: ==============
403: Con_CenteredPrint
404: ==============
405: */
406: void Con_CenteredPrint (char *text)
407: {
408: int l;
409: char buffer[1024];
410:
411: l = strlen(text);
412: l = (con.linewidth-l)/2;
413: if (l < 0)
414: l = 0;
415: memset (buffer, ' ', l);
416: strcpy (buffer+l, text);
417: strcat (buffer, "\n");
418: Con_Print (buffer);
419: }
420:
421: /*
422: ==============================================================================
423:
424: DRAWING
425:
426: ==============================================================================
427: */
428:
429:
430: /*
431: ================
432: Con_DrawInput
433:
434: The input line scrolls horizontally if typing goes beyond the right edge
435: ================
436: */
437: void Con_DrawInput (void)
438: {
439: int y;
440: int i;
441: char *text;
442:
443: if (cls.key_dest == key_menu)
444: return;
445: if (cls.key_dest != key_console && cls.state == ca_active)
446: return; // don't draw anything (always draw if not active)
447:
448: text = key_lines[edit_line];
449:
450: // add the cursor frame
451: text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
452:
453: // fill out remainder with spaces
454: for (i=key_linepos+1 ; i< con.linewidth ; i++)
455: text[i] = ' ';
456:
457: // prestep if horizontally scrolling
458: if (key_linepos >= con.linewidth)
459: text += 1 + key_linepos - con.linewidth;
460:
461: // draw it
462: y = con.vislines-16;
463:
464: for (i=0 ; i<con.linewidth ; i++)
465: re.DrawChar ( (i+1)<<3, con.vislines - 16, text[i]);
466:
467: // remove cursor
468: key_lines[edit_line][key_linepos] = 0;
469: }
470:
471:
472: /*
473: ================
474: Con_DrawNotify
475:
476: Draws the last few lines of output transparently over the game top
477: ================
478: */
479: void Con_DrawNotify (void)
480: {
481: int x, v;
482: char *text;
483: int i;
484: int time;
485: char *s;
486: int skip;
487:
488: v = 0;
489: for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
490: {
491: if (i < 0)
492: continue;
493: time = con.times[i % NUM_CON_TIMES];
494: if (time == 0)
495: continue;
496: time = cls.realtime - time;
497: if (time > con_notifytime->value*1000)
498: continue;
499: text = con.text + (i % con.totallines)*con.linewidth;
500:
501: for (x = 0 ; x < con.linewidth ; x++)
502: re.DrawChar ( (x+1)<<3, v, text[x]);
503:
504: v += 8;
505: }
506:
507:
508: if (cls.key_dest == key_message)
509: {
510: if (chat_team)
511: {
512: DrawString (8, v, "say_team:");
513: skip = 11;
514: }
515: else
516: {
517: DrawString (8, v, "say:");
518: skip = 5;
519: }
520:
521: s = chat_buffer;
522: if (chat_bufferlen > (viddef.width>>3)-(skip+1))
523: s += chat_bufferlen - ((viddef.width>>3)-(skip+1));
524: x = 0;
525: while(s[x])
526: {
527: re.DrawChar ( (x+skip)<<3, v, s[x]);
528: x++;
529: }
530: re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
531: v += 8;
532: }
533:
534: if (v)
535: {
536: SCR_AddDirtyPoint (0,0);
537: SCR_AddDirtyPoint (viddef.width-1, v);
538: }
539: }
540:
541: /*
542: ================
543: Con_DrawConsole
544:
545: Draws the console with the solid background
546: ================
547: */
548: void Con_DrawConsole (float frac)
549: {
550: int i, x, y;
551: int rows;
552: char *text;
553: int row;
554: int lines;
555: char version[64];
556:
557: lines = viddef.height * frac;
558: if (lines <= 0)
559: return;
560:
561: if (lines > viddef.height)
562: lines = viddef.height;
563:
564: // draw the background
565: re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback");
566: SCR_AddDirtyPoint (0,0);
567: SCR_AddDirtyPoint (viddef.width-1,lines-1);
568:
569: Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
570: for (x=0 ; x<5 ; x++)
571: re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version[x] );
572:
573: // draw the text
574: con.vislines = lines;
575:
576: rows = (lines-8)>>3; // rows of text to draw
577:
578: y = lines - 24;
579:
580: // draw from the bottom up
581: if (con.display != con.current)
582: {
583: // draw arrows to show the buffer is backscrolled
584: for (x=0 ; x<con.linewidth ; x+=4)
585: re.DrawChar ( (x+1)<<3, y, '^');
586:
587: y -= 8;
588: rows--;
589: }
590:
591: row = con.display;
592: for (i=0 ; i<rows ; i++, y-=8, row--)
593: {
594: if (row < 0)
595: break;
596: if (con.current - row >= con.totallines)
597: break; // past scrollback wrap point
598:
599: text = con.text + (row % con.totallines)*con.linewidth;
600:
601: for (x=0 ; x<con.linewidth ; x++)
602: re.DrawChar ( (x+1)<<3, y, text[x]);
603: }
604:
605: // draw the input prompt, user text, and cursor if desired
606: Con_DrawInput ();
607: }
608:
609:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.