1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 // console.c
23
24 #include "client.h"
25
26
27 int g_console_field_width = 78;
28
29
30 #define NUM_CON_TIMES 4
31
32 #define CON_TEXTSIZE 32768
33 typedef struct {
34 qboolean initialized;
35
36 short text[CON_TEXTSIZE];
37 int current; // line where next message will be printed
38 int x; // offset in current line for next print
39 int display; // bottom of console displays this line
40
41 int linewidth; // characters across screen
42 int totallines; // total lines in console scrollback
43
44 float xadjust; // for wide aspect screens
45
46 float displayFrac; // aproaches finalFrac at scr_conspeed
47 float finalFrac; // 0.0 to 1.0 lines of console to display
48 float userFrac; // 0.0 to 1.0 - for user Configurations. Don't want to mess with finalFrac - marky
49 int vislines; // in scanlines
50
51 int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
52 // for transparent notify lines
53 vec4_t color;
54 } console_t;
55
56 extern console_t con;
57
58 console_t con;
59
60 cvar_t *con_conspeed;
61 cvar_t *con_notifytime;
62
63 #define DEFAULT_CONSOLE_WIDTH 78
64
65 vec4_t console_color = {1.0, 1.0, 1.0, 1.0};
66
67
68 /*
69 ================
70 Con_ToggleConsole_f
71 ================
72 */
Con_ToggleConsole_f(void)73 void Con_ToggleConsole_f (void) {
74 // Can't toggle the console when it's the only thing available
75 if ( cls.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) {
76 return;
77 }
78
79 Field_Clear( &g_consoleField );
80 g_consoleField.widthInChars = g_console_field_width;
81
82 Con_ClearNotify ();
83 Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE );
84 }
85
86 /*
87 ================
88 Con_MessageMode_f
89 ================
90 */
Con_MessageMode_f(void)91 void Con_MessageMode_f (void) {
92 chat_playerNum = -1;
93 chat_team = qfalse;
94 Field_Clear( &chatField );
95 chatField.widthInChars = 30;
96
97 Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
98 }
99
100 /*
101 ================
102 Con_MessageMode2_f
103 ================
104 */
Con_MessageMode2_f(void)105 void Con_MessageMode2_f (void) {
106 chat_playerNum = -1;
107 chat_team = qtrue;
108 Field_Clear( &chatField );
109 chatField.widthInChars = 25;
110 Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
111 }
112
113 /*
114 ================
115 Con_MessageMode3_f
116 ================
117 */
Con_MessageMode3_f(void)118 void Con_MessageMode3_f (void) {
119 chat_playerNum = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
120 if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
121 chat_playerNum = -1;
122 return;
123 }
124 chat_team = qfalse;
125 Field_Clear( &chatField );
126 chatField.widthInChars = 30;
127 Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
128 }
129
130 /*
131 ================
132 Con_MessageMode4_f
133 ================
134 */
Con_MessageMode4_f(void)135 void Con_MessageMode4_f (void) {
136 chat_playerNum = VM_Call( cgvm, CG_LAST_ATTACKER );
137 if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) {
138 chat_playerNum = -1;
139 return;
140 }
141 chat_team = qfalse;
142 Field_Clear( &chatField );
143 chatField.widthInChars = 30;
144 Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
145 }
146
147 /*
148 ================
149 Con_Clear_f
150 ================
151 */
Con_Clear_f(void)152 void Con_Clear_f (void) {
153 int i;
154
155 for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
156 con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
157 }
158
159 Con_Bottom(); // go to end
160 }
161
162
163 /*
164 ================
165 Con_Dump_f
166
167 Save the console contents out to a file
168 ================
169 */
Con_Dump_f(void)170 void Con_Dump_f (void)
171 {
172 int l, x, i;
173 short *line;
174 fileHandle_t f;
175 int bufferlen;
176 char *buffer;
177 char filename[MAX_QPATH];
178
179 if (Cmd_Argc() != 2)
180 {
181 Com_Printf ("usage: condump <filename>\n");
182 return;
183 }
184
185 Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) );
186 COM_DefaultExtension( filename, sizeof( filename ), ".txt" );
187
188 if (!COM_CompareExtension(filename, ".txt"))
189 {
190 Com_Printf("Con_Dump_f: Only the \".txt\" extension is supported by this command!\n");
191 return;
192 }
193
194 f = FS_FOpenFileWrite( filename );
195 if (!f)
196 {
197 Com_Printf ("ERROR: couldn't open %s.\n", filename);
198 return;
199 }
200
201 Com_Printf ("Dumped console text to %s.\n", filename );
202
203 // skip empty lines
204 for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
205 {
206 line = con.text + (l%con.totallines)*con.linewidth;
207 for (x=0 ; x<con.linewidth ; x++)
208 if ((line[x] & 0xff) != ' ')
209 break;
210 if (x != con.linewidth)
211 break;
212 }
213
214 // write the remaining lines
215 buffer[con.linewidth] = 0;
216 for ( ; l <= con.current ; l++)
217 {
218 line = con.text + (l%con.totallines)*con.linewidth;
219 for(i=0; i<con.linewidth; i++)
220 buffer[i] = line[i] & 0xff;
221 for (x=con.linewidth-1 ; x>=0 ; x--)
222 {
223 if (buffer[x] == ' ')
224 buffer[x] = 0;
225 else
226 break;
227 }
228 #ifdef _WIN32
229 Q_strcat(buffer, bufferlen, "\r\n");
230 #else
231 Q_strcat(buffer, bufferlen, "\n");
232 #endif
233 FS_Write(buffer, strlen(buffer), f);
234 }
235
236 Hunk_FreeTempMemory( buffer );
237 FS_FCloseFile( f );
238 }
239
240
241 /*
242 ================
243 Con_ClearNotify
244 ================
245 */
Con_ClearNotify(void)246 void Con_ClearNotify( void ) {
247 int i;
248
249 for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
250 con.times[i] = 0;
251 }
252 }
253
254
255
256 /*
257 ================
258 Con_CheckResize
259
260 If the line width has changed, reformat the buffer.
261 ================
262 */
Con_CheckResize(void)263 void Con_CheckResize (void)
264 {
265 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
266 short tbuf[CON_TEXTSIZE];
267
268 width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2;
269
270 if (width == con.linewidth)
271 return;
272
273 if (width < 1) // video hasn't been initialized yet
274 {
275 width = DEFAULT_CONSOLE_WIDTH;
276 con.linewidth = width;
277 con.totallines = CON_TEXTSIZE / con.linewidth;
278 for(i=0; i<CON_TEXTSIZE; i++)
279
280 con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
281 }
282 else
283 {
284 oldwidth = con.linewidth;
285 con.linewidth = width;
286 oldtotallines = con.totallines;
287 con.totallines = CON_TEXTSIZE / con.linewidth;
288 numlines = oldtotallines;
289
290 if (con.totallines < numlines)
291 numlines = con.totallines;
292
293 numchars = oldwidth;
294
295 if (con.linewidth < numchars)
296 numchars = con.linewidth;
297
298 Com_Memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));
299 for(i=0; i<CON_TEXTSIZE; i++)
300
301 con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
302
303
304 for (i=0 ; i<numlines ; i++)
305 {
306 for (j=0 ; j<numchars ; j++)
307 {
308 con.text[(con.totallines - 1 - i) * con.linewidth + j] =
309 tbuf[((con.current - i + oldtotallines) %
310 oldtotallines) * oldwidth + j];
311 }
312 }
313
314 Con_ClearNotify ();
315 }
316
317 con.current = con.totallines - 1;
318 con.display = con.current;
319 }
320
321 /*
322 ==================
323 Cmd_CompleteTxtName
324 ==================
325 */
Cmd_CompleteTxtName(char * args,int argNum)326 void Cmd_CompleteTxtName( char *args, int argNum ) {
327 if( argNum == 2 ) {
328 Field_CompleteFilename( "", "txt", qfalse, qtrue );
329 }
330 }
331
332
333 /*
334 ================
335 Con_Init
336 ================
337 */
Con_Init(void)338 void Con_Init (void) {
339 int i;
340
341 con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
342 con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
343
344 Field_Clear( &g_consoleField );
345 g_consoleField.widthInChars = g_console_field_width;
346 for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
347 Field_Clear( &historyEditLines[i] );
348 historyEditLines[i].widthInChars = g_console_field_width;
349 }
350 CL_LoadConsoleHistory( );
351
352 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
353 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
354 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
355 Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
356 Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
357 Cmd_AddCommand ("clear", Con_Clear_f);
358 Cmd_AddCommand ("condump", Con_Dump_f);
359 Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName );
360 }
361
362
363 /*
364 ===============
365 Con_Linefeed
366 ===============
367 */
Con_Linefeed(qboolean skipnotify)368 void Con_Linefeed (qboolean skipnotify)
369 {
370 int i;
371
372 // mark time for transparent overlay
373 if (con.current >= 0)
374 {
375 if (skipnotify)
376 con.times[con.current % NUM_CON_TIMES] = 0;
377 else
378 con.times[con.current % NUM_CON_TIMES] = cls.realtime;
379 }
380
381 con.x = 0;
382 if (con.display == con.current)
383 con.display++;
384 con.current++;
385 for(i=0; i<con.linewidth; i++)
386 con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
387 }
388
389 /*
390 ================
391 CL_ConsolePrint
392
393 Handles cursor positioning, line wrapping, etc
394 All console printing must go through this in order to be logged to disk
395 If no console is visible, the text will appear at the top of the game window
396 ================
397 */
CL_ConsolePrint(char * txt)398 void CL_ConsolePrint( char *txt ) {
399 int y;
400 int c, l;
401 int color;
402 qboolean skipnotify = qfalse; // NERVE - SMF
403 int prev; // NERVE - SMF
404
405 // TTimo - prefix for text that shows up in console but not in notify
406 // backported from RTCW
407 if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) {
408 skipnotify = qtrue;
409 txt += 12;
410 }
411
412 // for some demos we don't want to ever show anything on the console
413 if ( cl_noprint && cl_noprint->integer ) {
414 return;
415 }
416
417 if (!con.initialized) {
418 con.color[0] =
419 con.color[1] =
420 con.color[2] =
421 con.color[3] = 1.0f;
422 con.linewidth = -1;
423 Con_CheckResize ();
424 con.initialized = qtrue;
425 }
426
427 color = ColorIndex(COLOR_WHITE);
428
429 while ( (c = *txt) != 0 ) {
430 if ( Q_IsColorString( txt ) ) {
431 color = ColorIndex( *(txt+1) );
432 txt += 2;
433 continue;
434 }
435
436 // count word length
437 for (l=0 ; l< con.linewidth ; l++) {
438 if ( txt[l] <= ' ') {
439 break;
440 }
441
442 }
443
444 // word wrap
445 if (l != con.linewidth && (con.x + l >= con.linewidth) ) {
446 Con_Linefeed(skipnotify);
447
448 }
449
450 txt++;
451
452 switch (c)
453 {
454 case '\n':
455 Con_Linefeed (skipnotify);
456 break;
457 case '\r':
458 con.x = 0;
459 break;
460 default: // display character and advance
461 y = con.current % con.totallines;
462 con.text[y*con.linewidth+con.x] = (color << 8) | c;
463 con.x++;
464 if(con.x >= con.linewidth)
465 Con_Linefeed(skipnotify);
466 break;
467 }
468 }
469
470
471 // mark time for transparent overlay
472 if (con.current >= 0) {
473 // NERVE - SMF
474 if ( skipnotify ) {
475 prev = con.current % NUM_CON_TIMES - 1;
476 if ( prev < 0 )
477 prev = NUM_CON_TIMES - 1;
478 con.times[prev] = 0;
479 }
480 else
481 // -NERVE - SMF
482 con.times[con.current % NUM_CON_TIMES] = cls.realtime;
483 }
484 }
485
486
487 /*
488 ==============================================================================
489
490 DRAWING
491
492 ==============================================================================
493 */
494
495
496 /*
497 ================
498 Con_DrawInput
499
500 Draw the editline after a ] prompt
501 ================
502 */
Con_DrawInput(void)503 void Con_DrawInput (void) {
504 int y;
505
506 if ( cls.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) {
507 return;
508 }
509
510 y = con.vislines - ( SMALLCHAR_HEIGHT * 2 );
511
512 re.SetColor( con.color );
513
514 SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' );
515
516 Field_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y,
517 SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue, qtrue );
518 }
519
520
521 /*
522 ================
523 Con_DrawNotify
524
525 Draws the last few lines of output transparently over the game top
526 ================
527 */
Con_DrawNotify(void)528 void Con_DrawNotify (void)
529 {
530 int x, v;
531 short *text;
532 int i;
533 int time;
534 int skip;
535 int currentColor;
536
537 currentColor = 7;
538 re.SetColor( g_color_table[currentColor] );
539
540 v = 0;
541 for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
542 {
543 if (i < 0)
544 continue;
545 time = con.times[i % NUM_CON_TIMES];
546 if (time == 0)
547 continue;
548 time = cls.realtime - time;
549 if (time > con_notifytime->value*1000)
550 continue;
551 text = con.text + (i % con.totallines)*con.linewidth;
552
553 if (cl.snap.ps.pm_type != PM_INTERMISSION && Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
554 continue;
555 }
556
557 for (x = 0 ; x < con.linewidth ; x++) {
558 if ( ( text[x] & 0xff ) == ' ' ) {
559 continue;
560 }
561 if ( ( (text[x]>>8)% NUMBER_OF_COLORS ) != currentColor ) {
562 currentColor = (text[x]>>8) % NUMBER_OF_COLORS;
563 re.SetColor( g_color_table[currentColor] );
564 }
565 SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff );
566 }
567
568 v += SMALLCHAR_HEIGHT;
569 }
570
571 re.SetColor( NULL );
572
573 if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
574 return;
575 }
576
577 // draw the chat line
578 if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
579 {
580 if (chat_team)
581 {
582 SCR_DrawBigString (8, v, "say_team:", 1.0f, qfalse );
583 skip = 10;
584 }
585 else
586 {
587 SCR_DrawBigString (8, v, "say:", 1.0f, qfalse );
588 skip = 5;
589 }
590
591 Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
592 SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue );
593
594 v += BIGCHAR_HEIGHT;
595 }
596
597 }
598
599 /*
600 ================
601 Con_DrawSolidConsole
602
603 Draws the console with the solid background
604 ================
605 */
Con_DrawSolidConsole(float frac)606 void Con_DrawSolidConsole( float frac ) {
607 int i, x, y;
608 int rows;
609 short *text;
610 int row;
611 int lines;
612 // qhandle_t conShader;
613 int currentColor;
614 vec4_t color;
615
616 lines = cls.glconfig.vidHeight * frac;
617 if (lines <= 0)
618 return;
619
620 if (lines > cls.glconfig.vidHeight )
621 lines = cls.glconfig.vidHeight;
622
623 // on wide screens, we will center the text
624 con.xadjust = 0;
625 SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
626
627 // draw the background
628 y = frac * SCREEN_HEIGHT;
629 if ( y < 1 ) {
630 y = 0;
631 }
632 else {
633 if ( cl_consoleType->integer ) {
634 color[0] = cl_consoleType->integer > 1 ? cl_consoleColor[0]->value : 1.0f ;
635 color[1] = cl_consoleType->integer > 1 ? cl_consoleColor[1]->value : 1.0f ;
636 color[2] = cl_consoleType->integer > 1 ? cl_consoleColor[2]->value : 1.0f ;
637 color[3] = cl_consoleColor[3]->value;
638 re.SetColor( color );
639 }
640 if ( cl_consoleType->integer == 2 ) {
641 SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.whiteShader );
642 } else {
643 SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
644 }
645 }
646
647 color[0] = 1;
648 color[1] = 0;
649 color[2] = 0;
650 // color[3] = 1;
651 if( !cl_consoleType->integer )
652 color[3] = 1;
653 SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
654
655
656 // draw the version number
657
658 re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
659
660 i = strlen( Q3_VERSION );
661
662 for (x=0 ; x<i ; x++) {
663 SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x + 1 ) * SMALLCHAR_WIDTH,
664 lines - SMALLCHAR_HEIGHT, Q3_VERSION[x] );
665 }
666
667
668 // draw the text
669 con.vislines = lines;
670 rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw
671
672 y = lines - (SMALLCHAR_HEIGHT*3);
673
674 // draw from the bottom up
675 if (con.display != con.current)
676 {
677 // draw arrows to show the buffer is backscrolled
678 re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
679 for (x=0 ; x<con.linewidth ; x+=4)
680 SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, '^' );
681 y -= SMALLCHAR_HEIGHT;
682 rows--;
683 }
684
685 row = con.display;
686
687 if ( con.x == 0 ) {
688 row--;
689 }
690
691 currentColor = 7;
692 re.SetColor( g_color_table[currentColor] );
693
694 for (i=0 ; i<rows ; i++, y -= SMALLCHAR_HEIGHT, row--)
695 {
696 if (row < 0)
697 break;
698 if (con.current - row >= con.totallines) {
699 // past scrollback wrap point
700 continue;
701 }
702
703 text = con.text + (row % con.totallines)*con.linewidth;
704
705 for (x=0 ; x<con.linewidth ; x++) {
706 if ( ( text[x] & 0xff ) == ' ' ) {
707 continue;
708 }
709
710 if ( ( (text[x]>>8) % NUMBER_OF_COLORS ) != currentColor ) {
711 currentColor = (text[x]>>8) % NUMBER_OF_COLORS;
712 re.SetColor( g_color_table[currentColor] );
713 }
714 SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff );
715 }
716 }
717
718 // draw the input prompt, user text, and cursor if desired
719 Con_DrawInput ();
720
721 re.SetColor( NULL );
722 }
723
724
725
726 /*
727 ==================
728 Con_DrawConsole
729 ==================
730 */
Con_DrawConsole(void)731 void Con_DrawConsole( void ) {
732 // check for console width changes from a vid mode change
733 Con_CheckResize ();
734
735 // if disconnected, render console full screen
736 if ( cls.state == CA_DISCONNECTED ) {
737 if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {
738 Con_DrawSolidConsole( 1.0 );
739 return;
740 }
741 }
742
743 if ( con.displayFrac ) {
744 Con_DrawSolidConsole( con.displayFrac );
745 } else {
746 // draw notify lines
747 if ( cls.state == CA_ACTIVE ) {
748 Con_DrawNotify ();
749 }
750 }
751 }
752
753 //================================================================
754
755 /*
756 ==================
757 Con_RunConsole
758
759 Scroll it up or down
760 ==================
761 */
Con_RunConsole(void)762 void Con_RunConsole (void) {
763 // decide on the destination height of the console
764 if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
765 con.finalFrac = con.userFrac;
766 else
767 con.finalFrac = 0; // none visible
768
769 // scroll towards the destination height
770 if (con.finalFrac < con.displayFrac)
771 {
772 con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
773 if (con.finalFrac > con.displayFrac)
774 con.displayFrac = con.finalFrac;
775
776 }
777 else if (con.finalFrac > con.displayFrac)
778 {
779 con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
780 if (con.finalFrac < con.displayFrac)
781 con.displayFrac = con.finalFrac;
782 }
783
784 }
785
786
787 /*
788 ==================
789 Con_SetFrac
790 ==================
791 */
Con_SetFrac(const float conFrac)792 void Con_SetFrac(const float conFrac)
793 {
794 // clamp the cvar value
795 if (conFrac < .1f) { // don't let the console be hidden
796 con.userFrac = .1f;
797 } else if (conFrac > 1.0f) {
798 con.userFrac = 1.0f;
799 } else {
800 con.userFrac = conFrac;
801 }
802 }
803
Con_PageUp(void)804 void Con_PageUp( void ) {
805 con.display -= 2;
806 if ( con.current - con.display >= con.totallines ) {
807 con.display = con.current - con.totallines + 1;
808 }
809 }
810
Con_PageDown(void)811 void Con_PageDown( void ) {
812 con.display += 2;
813 if (con.display > con.current) {
814 con.display = con.current;
815 }
816 }
817
Con_Top(void)818 void Con_Top( void ) {
819 con.display = con.totallines;
820 if ( con.current - con.display >= con.totallines ) {
821 con.display = con.current - con.totallines + 1;
822 }
823 }
824
Con_Bottom(void)825 void Con_Bottom( void ) {
826 con.display = con.current;
827 }
828
829
Con_Close(void)830 void Con_Close( void ) {
831 if ( !com_cl_running->integer ) {
832 return;
833 }
834 Field_Clear( &g_consoleField );
835 Con_ClearNotify ();
836 Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CONSOLE );
837 con.finalFrac = 0; // none visible
838 con.displayFrac = 0;
839 }
840