]> icculus.org git repositories - btb/d2x.git/blob - main/console.c
no more CONSOLE macro
[btb/d2x.git] / main / console.c
1 /*
2  * Code for controlling the console
3  *  Based on an old version of SDL_Console
4  *
5  *  Written By: Garrett Banuk <mongoose@mongeese.org>
6  *  Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
7  *  Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
8  *
9  *  This is free, just be sure to give us credit when using it
10  *  in any of your programs.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include <conf.h>
15 #endif
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdarg.h>
21
22 #include "console.h"
23 #include "u_mem.h"
24 #include "gr.h"
25 #include "timer.h"
26
27
28 #define FG_COLOR    grd_curcanv->cv_font_fg_color
29 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
30
31
32 static ConsoleInformation *Console;
33
34 /* Pointer to our one console */
35 static ConsoleInformation *console;
36
37 /* Internals */
38 void CON_UpdateOffset(void);
39 /*! Calls CON_Free */
40 void CON_Destroy(void);
41 /*! Frees all the memory loaded by the console */
42 void CON_Free(void);
43 #if 0
44 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
45  255 - opaque). Use this function also for OpenGL. */
46 void CON_Alpha(unsigned char alpha);
47 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
48  Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
49 void CON_AlphaGL(SDL_Surface *s, int alpha);
50 /*! Sets a background image for the console */
51 #endif
52 int CON_Background(grs_bitmap *image);
53 /*! Sets font info for the console */
54 void CON_Font(grs_font *font, int fg, int bg);
55 /*! Changes current position of the console */
56 void CON_Position(int x, int y);
57 /*! Beams a console to another screen surface. Needed if you want to make a Video restart in your program. This
58  function first changes the OutputScreen Pointer then calls CON_Resize to adjust the new size. */
59 int CON_Transfer(grs_screen* new_outputscreen, int x, int y, int w, int h);
60 /*! Modify the prompt of the console */
61 void CON_SetPrompt(char* newprompt);
62 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
63  ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
64 void CON_SetHideKey(int key);
65 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
66 void CON_SetHideFunction(void(*HideFunction)(void));
67 /*! Sets the callback function that is called after a console has been hidden */
68 void CON_Execute(char* command);
69 /*! Sets the callback function that is called if a command was typed in. The function could look like this:
70  void my_command_handler(char* command). @param console: the console the command
71  came from. @param command: the command string that was typed in. */
72 void CON_SetExecuteFunction(void(*CmdFunction)(char* command));
73 /*! Sets the callback tabulator completion function. char* my_tabcompletion(char* command). If Tab is
74  pressed, the function gets called with the already typed in command. my_tabcompletion then checks if if can
75  complete the command or if it should display a list of all matching commands (with CON_Out()). Returns the
76  completed command or NULL if no completion was made. */
77 void CON_SetTabCompletion(char*(*TabFunction)(char* command));
78 /*! Internal: Gets called when TAB was pressed */
79 void CON_TabCompletion(void);
80 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
81 void CON_NewLineConsole(void);
82 /*! Internal: shift command history (the one you can switch with the up/down keys) */
83 void CON_NewLineCommand(void);
84 /*! Internal: updates console after resize etc. */
85 void CON_UpdateConsole(void);
86
87
88 /*! Internal: Default Execute callback */
89 void Default_CmdFunction(char* command);
90 /*! Internal: Default TabCompletion callback */
91 char* Default_TabFunction(char* command);
92 /*! Internal: Default Hide callback */
93 void Default_HideFunction(void);
94
95 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
96 void DrawCommandLine();
97
98 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
99 void Cursor_Left(void);
100 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
101 void Cursor_Right(void);
102 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
103         of the line */
104 void Cursor_Home(void);
105 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
106 void Cursor_End(void);
107 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
108 void Cursor_Del(void);
109 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
110 void Cursor_BSpace(void);
111 /*! Internal: Called if you type in a character (add the char to the command) */
112 void Cursor_Add(int event);
113
114 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
115 void Clear_Command(void);
116 /*! Internal: Called if you press Ctrl-L (deletes the History) */
117 void Clear_History(void);
118
119 /*! Internal: Called if you press UP key (switches through recent typed in commands */
120 void Command_Up(void);
121 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
122 void Command_Down(void);
123
124
125 /*  Takes keys from the keyboard and inputs them to the console
126  If the event was not handled (i.e. WM events or unknown ctrl-shift
127  sequences) the function returns the event for further processing. */
128 int CON_Events(int event)
129 {
130         if(!CON_isVisible())
131                 return event;
132         
133         if(event & KEY_CTRLED)
134         {
135                 //CTRL pressed
136                 switch(event & ~KEY_CTRLED)
137                 {
138                         case KEY_A:
139                                 Cursor_Home();
140                                 break;
141                         case KEY_E:
142                                 Cursor_End();
143                                 break;
144                         case KEY_C:
145                                 Clear_Command();
146                                 break;
147                         case KEY_L:
148                                 Clear_History();
149                                 CON_UpdateConsole();
150                                 break;
151                         default:
152                                 return event;
153                 }
154         }
155         else if(event & KEY_ALTED)
156         {
157                 //the console does not handle ALT combinations!
158                 return event;
159         }
160         else
161         {
162                 //first of all, check if the console hide key was pressed
163                 if(event == console->HideKey)
164                 {
165                         CON_Hide();
166                         return 0;
167                 }
168                 switch (event & 0xff)
169                 {
170                         case KEY_LSHIFT:
171                         case KEY_RSHIFT:
172                                 return event;
173                         case KEY_HOME:
174                                 if(event & KEY_SHIFTED)
175                                 {
176                                         console->ConsoleScrollBack = console->LineBuffer-1;
177                                         CON_UpdateConsole();
178                                 } else {
179                                         Cursor_Home();
180                                 }
181                                 break;
182                         case KEY_END:
183                                 if(event & KEY_SHIFTED)
184                                 {
185                                         console->ConsoleScrollBack = 0;
186                                         CON_UpdateConsole();
187                                 } else {
188                                         Cursor_End();
189                                 }
190                                 break;
191                         case KEY_PAGEUP:
192                                 console->ConsoleScrollBack += CON_LINE_SCROLL;
193                                 if(console->ConsoleScrollBack > console->LineBuffer-1)
194                                         console->ConsoleScrollBack = console->LineBuffer-1;
195                                 
196                                 CON_UpdateConsole();
197                                 break;
198                         case KEY_PAGEDOWN:
199                                 console->ConsoleScrollBack -= CON_LINE_SCROLL;
200                                 if(console->ConsoleScrollBack < 0)
201                                         console->ConsoleScrollBack = 0;
202                                 CON_UpdateConsole();
203                                 break;
204                         case KEY_UP:
205                                 Command_Up();
206                                 break;
207                         case KEY_DOWN:
208                                 Command_Down();
209                                 break;
210                         case KEY_LEFT:
211                                 Cursor_Left();
212                                 break;
213                         case KEY_RIGHT:
214                                 Cursor_Right();
215                                 break;
216                         case KEY_BACKSP:
217                                 Cursor_BSpace();
218                                 break;
219                         case KEY_DELETE:
220                                 Cursor_Del();
221                                 break;
222                         case KEY_INSERT:
223                                 console->InsMode = 1-console->InsMode;
224                                 break;
225                         case KEY_TAB:
226                                 CON_TabCompletion();
227                                 break;
228                         case KEY_ENTER:
229                                 if(strlen(console->Command) > 0) {
230                                         CON_NewLineCommand();
231                                         
232                                         // copy the input into the past commands strings
233                                         strcpy(console->CommandLines[0], console->Command);
234                                         
235                                         // display the command including the prompt
236                                         CON_Out("%s%s", console->Prompt, console->Command);
237                                         CON_UpdateConsole();
238                                         
239                                         CON_Execute(console->Command);
240                                         //printf("Command: %s\n", console->Command);
241                                         
242                                         Clear_Command();
243                                         console->CommandScrollBack = -1;
244                                 }
245                                 break;
246                         case KEY_LAPOSTRO:
247                                 //deactivate Console
248                                 CON_Hide();
249                                 return 0;
250                         default:
251                                 if (key_to_ascii(event) == 255)
252                                         break;
253                                 if(console->InsMode)
254                                         Cursor_Add(event);
255                                 else {
256                                         Cursor_Add(event);
257                                         Cursor_Del();
258                                 }
259                 }
260         }
261         return 0;
262 }
263
264 #if 0
265 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
266  * specified value.  Preconditions: the surface in question is RGBA.
267  * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
268 void CON_AlphaGL(SDL_Surface *s, int alpha) {
269         Uint8 val;
270         int x, y, w, h;
271         Uint32 pixel;
272         Uint8 r, g, b, a;
273         SDL_PixelFormat *format;
274         static char errorPrinted = 0;
275         
276         
277         /* debugging assertions -- these slow you down, but hey, crashing sucks */
278         if(!s) {
279                 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
280                 return;
281         }
282         
283         /* clamp alpha value to 0...255 */
284         if(alpha < SDL_ALPHA_TRANSPARENT)
285                 val = SDL_ALPHA_TRANSPARENT;
286         else if(alpha > SDL_ALPHA_OPAQUE)
287                 val = SDL_ALPHA_OPAQUE;
288         else
289                 val = alpha;
290         
291         /* loop over alpha channels of each pixel, setting them appropriately. */
292         w = s->w;
293         h = s->h;
294         format = s->format;
295         switch (format->BytesPerPixel) {
296                 case 2:
297                         /* 16-bit surfaces don't seem to support alpha channels. */
298                         if(!errorPrinted) {
299                                 errorPrinted = 1;
300                                 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
301                         }
302                         break;
303                 case 4: {
304                         /* we can do this very quickly in 32-bit mode.  24-bit is more
305                          * difficult.  And since 24-bit mode is reall the same as 32-bit,
306                          * so it usually ends up taking this route too.  Win!  Unroll loop
307                          * and use pointer arithmetic for extra speed. */
308                         int numpixels = h * (w << 2);
309                         Uint8 *pix = (Uint8 *) (s->pixels);
310                         Uint8 *last = pix + numpixels;
311                         Uint8 *pixel;
312                         if((numpixels & 0x7) == 0)
313                                 for(pixel = pix + 3; pixel < last; pixel += 32)
314                                         *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
315                         else
316                                 for(pixel = pix + 3; pixel < last; pixel += 4)
317                                         *pixel = val;
318                         break;
319                 }
320                 default:
321                         /* we have no choice but to do this slowly.  <sigh> */
322                         for(y = 0; y < h; ++y)
323                                 for(x = 0; x < w; ++x) {
324                                         char print = 0;
325                                         /* Lock the surface for direct access to the pixels */
326                                         if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
327                                                 PRINT_ERROR("Can't lock surface: ");
328                                                 fprintf(stderr, "%s\n", SDL_GetError());
329                                                 return;
330                                         }
331                                         pixel = DT_GetPixel(s, x, y);
332                                         if(x == 0 && y == 0)
333                                                 print = 1;
334                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
335                                         pixel = SDL_MapRGBA(format, r, g, b, val);
336                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
337                                         DT_PutPixel(s, x, y, pixel);
338                                         
339                                         /* unlock surface again */
340                                         if(SDL_MUSTLOCK(s))
341                                                 SDL_UnlockSurface(s);
342                                 }
343                         break;
344         }
345 }
346 #endif
347
348
349 /* Updates the console buffer */
350 void CON_UpdateConsole(void) {
351         int loop;
352         int loop2;
353         int Screenlines;
354         grs_canvas *canv_save;
355         short orig_color;
356         
357         if(!console)
358                 return;
359         
360         /* Due to the Blits, the update is not very fast: So only update if it's worth it */
361         if(!CON_isVisible())
362                 return;
363         
364         Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
365         
366         canv_save = grd_curcanv;
367         gr_set_current_canvas(console->ConsoleSurface);
368         
369 #if 0
370         SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
371 #else
372         //gr_rect(0,0,
373 #endif
374         
375 #if 0
376         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
377                 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
378 #endif
379         
380         /* draw the background image if there is one */
381         if(console->BackgroundImage)
382                 gr_bitmap(0, 0, console->BackgroundImage);
383         
384         /* Draw the text from the back buffers, calculate in the scrollback from the user
385          * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
386          * for the font, and then clear it when we're done.
387          */
388 #if 0
389         if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
390                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
391                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
392         }
393 #endif
394         
395         //now draw text from last but second line to top
396         for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
397                 if(console->ConsoleScrollBack != 0 && loop == 0)
398                         for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
399                         {
400                                 orig_color = FG_COLOR;
401                                 gr_string(CON_CHAR_BORDER + (loop2*5*console->ConsoleSurface->cv_font->ft_w), (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), CON_SCROLL_INDICATOR);
402                                 FG_COLOR = orig_color;
403                         }
404                 else
405                 {
406                         orig_color = FG_COLOR;
407                         gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
408                         FG_COLOR = orig_color;
409                 }
410         }
411         
412         gr_set_current_canvas(canv_save);
413         
414 #if 0
415         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
416                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
417 #endif
418 }
419
420 void CON_UpdateOffset(void) {
421         if(!console)
422                 return;
423         
424         switch(console->Visible) {
425                 case CON_CLOSING:
426                         console->RaiseOffset -= CON_OPENCLOSE_SPEED;
427                         if(console->RaiseOffset <= 0) {
428                                 console->RaiseOffset = 0;
429                                 console->Visible = CON_CLOSED;
430                         }
431                         break;
432                 case CON_OPENING:
433                         console->RaiseOffset += CON_OPENCLOSE_SPEED;
434                         if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
435                                 console->RaiseOffset = console->ConsoleSurface->cv_h;
436                                 console->Visible = CON_OPEN;
437                         }
438                         break;
439                 case CON_OPEN:
440                 case CON_CLOSED:
441                         break;
442         }
443 }
444
445 /* Draws the console buffer to the screen if the console is "visible" */
446 void CON_DrawConsole(void) {
447         grs_canvas *canv_save;
448         grs_bitmap *clip;
449         
450         if(!console)
451                 return;
452         
453         /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
454         if(console->Visible == CON_CLOSED)
455                 return;
456         
457         /* Update the scrolling offset */
458         CON_UpdateOffset();
459         
460         /* Update the command line since it has a blinking cursor */
461         DrawCommandLine();
462         
463 #if 0
464         /* before drawing, make sure the alpha channel of the console surface is set
465          * properly.  (sigh) I wish we didn't have to do this every frame... */
466         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
467                 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
468 #endif
469         
470         canv_save = grd_curcanv;
471         gr_set_current_canvas(&console->OutputScreen->sc_canvas);
472         
473         clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
474         
475         gr_bitmap(console->DispX, console->DispY, clip);
476         gr_free_sub_bitmap(clip);
477         
478 #if 0
479         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
480                 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
481 #endif
482         
483         gr_set_current_canvas(canv_save);
484 }
485
486
487 /* Initializes the console */
488 ConsoleInformation *CON_Init(grs_font *Font, grs_screen *DisplayScreen, int lines, int x, int y, int w, int h)
489 {
490         int loop;
491         ConsoleInformation *newinfo;
492         
493         
494         /* Create a new console struct and init it. */
495         if((newinfo = (ConsoleInformation *) d_malloc(sizeof(ConsoleInformation))) == NULL) {
496                 //PRINT_ERROR("Could not allocate the space for a new console info struct.\n");
497                 return NULL;
498         }
499         newinfo->Visible = CON_CLOSED;
500         newinfo->RaiseOffset = 0;
501         newinfo->ConsoleLines = NULL;
502         newinfo->CommandLines = NULL;
503         newinfo->TotalConsoleLines = 0;
504         newinfo->ConsoleScrollBack = 0;
505         newinfo->TotalCommands = 0;
506         newinfo->BackgroundImage = NULL;
507 #if 0
508         newinfo->ConsoleAlpha = SDL_ALPHA_OPAQUE;
509 #endif
510         newinfo->Offset = 0;
511         newinfo->InsMode = 1;
512         newinfo->CursorPos = 0;
513         newinfo->CommandScrollBack = 0;
514         newinfo->OutputScreen = DisplayScreen;
515         newinfo->Prompt = CON_DEFAULT_PROMPT;
516         newinfo->HideKey = CON_DEFAULT_HIDEKEY;
517         
518         CON_SetExecuteFunction(Default_CmdFunction);
519         CON_SetTabCompletion(Default_TabFunction);
520         CON_SetHideFunction(Default_HideFunction);
521         
522         /* make sure that the size of the console is valid */
523         if(w > newinfo->OutputScreen->sc_w || w < Font->ft_w * 32)
524                 w = newinfo->OutputScreen->sc_w;
525         if(h > newinfo->OutputScreen->sc_h || h < Font->ft_h)
526                 h = newinfo->OutputScreen->sc_h;
527         if(x < 0 || x > newinfo->OutputScreen->sc_w - w)
528                 newinfo->DispX = 0;
529         else
530                 newinfo->DispX = x;
531         if(y < 0 || y > newinfo->OutputScreen->sc_h - h)
532                 newinfo->DispY = 0;
533         else
534                 newinfo->DispY = y;
535         
536         /* load the console surface */
537         newinfo->ConsoleSurface = gr_create_canvas(w, h);
538         
539         /* Load the consoles font */
540         {
541                 grs_canvas *canv_save;
542                 
543                 canv_save = grd_curcanv;
544                 gr_set_current_canvas(newinfo->ConsoleSurface);
545                 gr_set_curfont(Font);
546                 gr_set_fontcolor(gr_getcolor(63,63,63), -1);
547                 gr_set_current_canvas(canv_save);
548         }
549         
550         
551         /* Load the dirty rectangle for user input */
552         newinfo->InputBackground = gr_create_bitmap(w, newinfo->ConsoleSurface->cv_font->ft_h);
553 #if 0
554         SDL_FillRect(newinfo->InputBackground, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
555 #endif
556         
557         /* calculate the number of visible characters in the command line */
558         newinfo->VChars = (w - CON_CHAR_BORDER) / newinfo->ConsoleSurface->cv_font->ft_w;
559         if(newinfo->VChars > CON_CHARS_PER_LINE)
560                 newinfo->VChars = CON_CHARS_PER_LINE;
561         
562         /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
563         if(h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h) > lines)
564                 newinfo->LineBuffer = h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h);
565         else
566                 newinfo->LineBuffer = lines;
567         
568         
569         newinfo->ConsoleLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
570         newinfo->CommandLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
571         for(loop = 0; loop <= newinfo->LineBuffer - 1; loop++) {
572                 newinfo->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
573                 newinfo->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
574         }
575         memset(newinfo->Command, 0, CON_CHARS_PER_LINE);
576         memset(newinfo->LCommand, 0, CON_CHARS_PER_LINE);
577         memset(newinfo->RCommand, 0, CON_CHARS_PER_LINE);
578         memset(newinfo->VCommand, 0, CON_CHARS_PER_LINE);
579         
580         
581         CON_Out("Console initialised.");
582         CON_NewLineConsole();
583         //CON_ListCommands();
584         
585         return newinfo;
586 }
587
588 /* Makes the console visible */
589 void CON_Show(void) {
590         if(console) {
591                 console->Visible = CON_OPENING;
592                 CON_UpdateConsole();
593         }
594 }
595
596 /* Hides the console (make it invisible) */
597 void CON_Hide(void) {
598         if(console)
599                 console->Visible = CON_CLOSING;
600         console->HideFunction();
601 }
602
603 /* tells wether the console is visible or not */
604 int CON_isVisible(void) {
605         if(!console)
606                 return CON_CLOSED;
607         return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
608 }
609
610 /* Frees all the memory loaded by the console */
611 void CON_Destroy(void) {
612         CON_Free();
613 }
614
615 /* Frees all the memory loaded by the console */
616 void CON_Free(void) {
617         int i;
618         
619         if(!console)
620                 return;
621         
622         //CON_DestroyCommands();
623         for(i = 0; i <= console->LineBuffer - 1; i++) {
624                 d_free(console->ConsoleLines[i]);
625                 d_free(console->CommandLines[i]);
626         }
627         d_free(console->ConsoleLines);
628         d_free(console->CommandLines);
629         
630         console->ConsoleLines = NULL;
631         console->CommandLines = NULL;
632         
633         gr_free_canvas(console->ConsoleSurface);
634         console->ConsoleSurface = NULL;
635         
636         if (console->BackgroundImage)
637                 gr_free_bitmap(console->BackgroundImage);
638         console->BackgroundImage = NULL;
639         
640         gr_free_bitmap(console->InputBackground);
641         console->InputBackground = NULL;
642         
643         d_free(console);
644 }
645
646
647 /* Increments the console lines */
648 void CON_NewLineConsole(void) {
649         int loop;
650         char* temp;
651         
652         if(!console)
653                 return;
654         
655         temp = console->ConsoleLines[console->LineBuffer - 1];
656         
657         for(loop = console->LineBuffer - 1; loop > 0; loop--)
658                 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
659         
660         console->ConsoleLines[0] = temp;
661         
662         memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
663         if(console->TotalConsoleLines < console->LineBuffer - 1)
664                 console->TotalConsoleLines++;
665         
666         //Now adjust the ConsoleScrollBack
667         //dont scroll if not at bottom
668         if(console->ConsoleScrollBack != 0)
669                 console->ConsoleScrollBack++;
670         //boundaries
671         if(console->ConsoleScrollBack > console->LineBuffer-1)
672                 console->ConsoleScrollBack = console->LineBuffer-1;
673         
674 }
675
676
677 /* Increments the command lines */
678 void CON_NewLineCommand(void) {
679         int loop;
680         char *temp;
681         
682         if(!console)
683                 return;
684         
685         temp  = console->CommandLines[console->LineBuffer - 1];
686         
687         
688         for(loop = console->LineBuffer - 1; loop > 0; loop--)
689                 console->CommandLines[loop] = console->CommandLines[loop - 1];
690         
691         console->CommandLines[0] = temp;
692         
693         memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
694         if(console->TotalCommands < console->LineBuffer - 1)
695                 console->TotalCommands++;
696 }
697
698 /* Draws the command line the user is typing in to the screen */
699 /* completely rewritten by C.Wacha */
700 void DrawCommandLine() {
701         int x;
702         int commandbuffer;
703 #if 0
704         grs_font* CurrentFont;
705 #endif
706         static unsigned int LastBlinkTime = 0;  /* Last time the consoles cursor blinked */
707         static int LastCursorPos = 0;           // Last Cursor Position
708         static int Blink = 0;                   /* Is the cursor currently blinking */
709         grs_canvas *canv_save;
710         short orig_color;
711         
712         commandbuffer = console->VChars - strlen(console->Prompt)-1; // -1 to make cursor visible
713         
714 #if 0
715         CurrentFont = console->ConsoleSurface->cv_font;
716 #endif
717         
718         //Concatenate the left and right side to command
719         strcpy(console->Command, console->LCommand);
720         strncat(console->Command, console->RCommand, strlen(console->RCommand));
721         
722         //calculate display offset from current cursor position
723         if(console->Offset < console->CursorPos - commandbuffer)
724                 console->Offset = console->CursorPos - commandbuffer;
725         if(console->Offset > console->CursorPos)
726                 console->Offset = console->CursorPos;
727         
728         //first add prompt to visible part
729         strcpy(console->VCommand, console->Prompt);
730         
731         //then add the visible part of the command
732         strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
733         
734         //now display the result
735         
736 #if 0
737         //once again we're drawing text, so in OpenGL context we need to temporarily set up
738         //software-mode transparency.
739         if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
740                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
741                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
742         }
743 #endif
744         
745         canv_save = grd_curcanv;
746         gr_set_current_canvas(console->ConsoleSurface);
747         
748         //first of all restore InputBackground
749         gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
750         
751         //now add the text
752         orig_color = FG_COLOR;
753         gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
754         FG_COLOR = orig_color;
755         
756         //at last add the cursor
757         //check if the blink period is over
758         if(get_msecs() > LastBlinkTime) {
759                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
760                 if(Blink)
761                         Blink = 0;
762                 else
763                         Blink = 1;
764         }
765         
766         //check if cursor has moved - if yes display cursor anyway
767         if(console->CursorPos != LastCursorPos) {
768                 LastCursorPos = console->CursorPos;
769                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
770                 Blink = 1;
771         }
772         
773         if(Blink) {
774                 int prompt_width, cmd_width, h, w;
775                 
776                 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
777                 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
778                 x = CON_CHAR_BORDER + prompt_width + cmd_width;
779                 orig_color = FG_COLOR;
780                 if(console->InsMode)
781                         gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
782                 else
783                         gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
784                 FG_COLOR = orig_color;
785         }
786         
787         gr_set_current_canvas(canv_save);
788         
789         
790 #if 0
791         if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
792                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
793         }
794 #endif
795 }
796
797 #ifdef _MSC_VER
798 # define vsnprintf _vsnprintf
799 #endif
800
801 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
802 void CON_Out(const char *str, ...) {
803         va_list marker;
804         //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
805         char temp[CON_CHARS_PER_LINE + 128];
806         char* ptemp;
807         
808         if(!console)
809                 return;
810         
811         va_start(marker, str);
812         vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
813         va_end(marker);
814         
815         ptemp = temp;
816         
817         //temp now contains the complete string we want to output
818         // the only problem is that temp is maybe longer than the console
819         // width so we have to cut it into several pieces
820         
821         if(console->ConsoleLines) {
822                 while(strlen(ptemp) > console->VChars) {
823                         CON_NewLineConsole();
824                         strncpy(console->ConsoleLines[0], ptemp, console->VChars);
825                         console->ConsoleLines[0][console->VChars] = '\0';
826                         ptemp = &ptemp[console->VChars];
827                 }
828                 CON_NewLineConsole();
829                 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
830                 console->ConsoleLines[0][console->VChars] = '\0';
831                 CON_UpdateConsole();
832         }
833         
834         /* And print to stdout */
835         //printf("%s\n", temp);
836 }
837
838
839 #if 0
840 /* Sets the alpha level of the console, 0 turns off alpha blending */
841 void CON_Alpha(unsigned char alpha) {
842         if(!console)
843                 return;
844         
845         /* store alpha as state! */
846         console->ConsoleAlpha = alpha;
847         
848         if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
849                 if(alpha == 0)
850                         SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
851                 else
852                         SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
853         }
854         
855         //      CON_UpdateConsole();
856 }
857 #endif
858
859
860 /* Adds  background image to the console, scaled to size of console*/
861 int CON_Background(grs_bitmap *image)
862 {
863         if(!console)
864                 return 1;
865         
866         /* Free the background from the console */
867         if (image == NULL) {
868                 if (console->BackgroundImage)
869                         gr_free_bitmap(console->BackgroundImage);
870                 console->BackgroundImage = NULL;
871 #if 0
872                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
873 #endif
874                 return 0;
875         }
876         
877         /* Load a new background */
878         if (console->BackgroundImage)
879                 gr_free_bitmap(console->BackgroundImage);
880         console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
881         gr_bitmap_scale_to(image, console->BackgroundImage);
882         
883 #if 0
884         SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
885 #endif
886         gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
887         
888         return 0;
889 }
890
891 /* Sets font info for the console */
892 void CON_Font(grs_font *font, int fg, int bg)
893 {
894         grs_canvas *canv_save;
895         
896         canv_save = grd_curcanv;
897         gr_set_current_canvas(console->ConsoleSurface);
898         gr_set_curfont(font);
899         gr_set_fontcolor(fg, bg);
900         gr_set_current_canvas(canv_save);
901 }
902
903 /* takes a new x and y of the top left of the console window */
904 void CON_Position(int x, int y) {
905         if(!console)
906                 return;
907         
908         if(x < 0 || x > console->OutputScreen->sc_w - console->ConsoleSurface->cv_w)
909                 console->DispX = 0;
910         else
911                 console->DispX = x;
912         
913         if(y < 0 || y > console->OutputScreen->sc_h - console->ConsoleSurface->cv_h)
914                 console->DispY = 0;
915         else
916                 console->DispY = y;
917 }
918
919 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
920 /* resizes the console, has to reset alot of stuff
921  * returns 1 on error */
922 int CON_Resize(int x, int y, int w, int h)
923 {
924         if(!console)
925                 return 1;
926         
927         /* make sure that the size of the console is valid */
928         if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
929                 w = console->OutputScreen->sc_w;
930         if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
931                 h = console->OutputScreen->sc_h;
932         if(x < 0 || x > console->OutputScreen->sc_w - w)
933                 console->DispX = 0;
934         else
935                 console->DispX = x;
936         if(y < 0 || y > console->OutputScreen->sc_h - h)
937                 console->DispY = 0;
938         else
939                 console->DispY = y;
940         
941         /* resize console surface */
942         gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
943         gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
944         
945         /* Load the dirty rectangle for user input */
946         gr_free_bitmap(console->InputBackground);
947         console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
948         
949         /* Now reset some stuff dependent on the previous size */
950         console->ConsoleScrollBack = 0;
951         
952         /* Reload the background image (for the input text area) in the console */
953         if(console->BackgroundImage) {
954 #if 0
955                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
956 #endif
957                 gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
958         }
959         
960 #if 0
961         /* restore the alpha level */
962         CON_Alpha(console->ConsoleAlpha);
963 #endif
964         return 0;
965 }
966
967 /* Transfers the console to another screen surface, and adjusts size */
968 int CON_Transfer(grs_screen *new_outputscreen, int x, int y, int w, int h)
969 {
970         if(!console)
971                 return 1;
972         
973         console->OutputScreen = new_outputscreen;
974         
975         return(CON_Resize(x, y, w, h));
976 }
977
978 /* Sets the Prompt for console */
979 void CON_SetPrompt(char* newprompt) {
980         if(!console)
981                 return;
982         
983         //check length so we can still see at least 1 char :-)
984         if(strlen(newprompt) < console->VChars)
985                 console->Prompt = d_strdup(newprompt);
986         else
987                 CON_Out("prompt too long. (max. %i chars)", console->VChars - 1);
988 }
989
990 /* Sets the key that deactivates (hides) the console. */
991 void CON_SetHideKey(int key) {
992         if(console)
993                 console->HideKey = key;
994 }
995
996 void CON_SetHideFunction(void(*HideFunction)(void)) {
997         if(console)
998                 console->HideFunction = HideFunction;
999 }
1000
1001 void Default_HideFunction(void) {
1002 }
1003
1004 /* Executes the command entered */
1005 void CON_Execute(char* command) {
1006         if(console)
1007                 console->CmdFunction(command);
1008 }
1009
1010 void CON_SetExecuteFunction(void(*CmdFunction)(char* command)) {
1011         if(console)
1012                 console->CmdFunction = CmdFunction;
1013 }
1014
1015 void Default_CmdFunction(char* command) {
1016         CON_Out("     No CommandFunction registered");
1017         CON_Out("     use 'CON_SetExecuteFunction' to register one");
1018         CON_Out(" ");
1019         CON_Out("Unknown Command \"%s\"", command);
1020 }
1021
1022 void CON_SetTabCompletion(char*(*TabFunction)(char* command)) {
1023         if(console)
1024                 console->TabFunction = TabFunction;
1025 }
1026
1027 void CON_TabCompletion(void) {
1028         int i,j;
1029         char* command;
1030         
1031         if(!console)
1032                 return;
1033         
1034         command = d_strdup(console->LCommand);
1035         command = console->TabFunction(command);
1036         
1037         if(!command)
1038                 return; //no tab completion took place so return silently
1039         
1040         j = strlen(command);
1041         if(j > CON_CHARS_PER_LINE - 2)
1042                 j = CON_CHARS_PER_LINE-1;
1043         
1044         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1045         console->CursorPos = 0;
1046         
1047         for(i = 0; i < j; i++) {
1048                 console->CursorPos++;
1049                 console->LCommand[i] = command[i];
1050         }
1051         //add a trailing space
1052         console->CursorPos++;
1053         console->LCommand[j] = ' ';
1054         console->LCommand[j+1] = '\0';
1055 }
1056
1057 char* Default_TabFunction(char* command) {
1058         CON_Out("     No TabFunction registered");
1059         CON_Out("     use 'CON_SetTabCompletion' to register one");
1060         CON_Out(" ");
1061         return NULL;
1062 }
1063
1064 void Cursor_Left(void) {
1065         char temp[CON_CHARS_PER_LINE];
1066         
1067         if(console->CursorPos > 0) {
1068                 console->CursorPos--;
1069                 strcpy(temp, console->RCommand);
1070                 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
1071                 strcat(console->RCommand, temp);
1072                 console->LCommand[strlen(console->LCommand)-1] = '\0';
1073                 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1074         }
1075 }
1076
1077 void Cursor_Right(void) {
1078         char temp[CON_CHARS_PER_LINE];
1079         
1080         if(console->CursorPos < strlen(console->Command)) {
1081                 console->CursorPos++;
1082                 strncat(console->LCommand, console->RCommand, 1);
1083                 strcpy(temp, console->RCommand);
1084                 strcpy(console->RCommand, &temp[1]);
1085                 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1086         }
1087 }
1088
1089 void Cursor_Home(void) {
1090         char temp[CON_CHARS_PER_LINE];
1091         
1092         console->CursorPos = 0;
1093         strcpy(temp, console->RCommand);
1094         strcpy(console->RCommand, console->LCommand);
1095         strncat(console->RCommand, temp, strlen(temp));
1096         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1097 }
1098
1099 void Cursor_End(void) {
1100         console->CursorPos = strlen(console->Command);
1101         strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
1102         memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1103 }
1104
1105 void Cursor_Del(void) {
1106         char temp[CON_CHARS_PER_LINE];
1107         
1108         if(strlen(console->RCommand) > 0) {
1109                 strcpy(temp, console->RCommand);
1110                 strcpy(console->RCommand, &temp[1]);
1111         }
1112 }
1113
1114 void Cursor_BSpace(void) {
1115         if(console->CursorPos > 0) {
1116                 console->CursorPos--;
1117                 console->Offset--;
1118                 if(console->Offset < 0)
1119                         console->Offset = 0;
1120                 console->LCommand[strlen(console->LCommand)-1] = '\0';
1121         }
1122 }
1123
1124 void Cursor_Add(int event)
1125 {
1126         if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
1127         {
1128                 console->CursorPos++;
1129                 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
1130                 console->LCommand[strlen(console->LCommand)] = '\0';
1131         }
1132 }
1133
1134 void Clear_Command(void) {
1135         console->CursorPos = 0;
1136         memset(console->VCommand, 0, CON_CHARS_PER_LINE);
1137         memset(console->Command, 0, CON_CHARS_PER_LINE);
1138         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1139         memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1140 }
1141
1142 void Clear_History(void) {
1143         int loop;
1144         
1145         for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1146                 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1147 }
1148
1149 void Command_Up(void) {
1150         if(console->CommandScrollBack < console->TotalCommands - 1) {
1151                 /* move back a line in the command strings and copy the command to the current input string */
1152                 console->CommandScrollBack++;
1153                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1154                 console->Offset = 0;
1155                 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1156                 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1157                 CON_UpdateConsole();
1158         }
1159 }
1160
1161 void Command_Down(void) {
1162         if(console->CommandScrollBack > -1) {
1163                 /* move forward a line in the command strings and copy the command to the current input string */
1164                 console->CommandScrollBack--;
1165                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1166                 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1167                 console->Offset = 0;
1168                 if(console->CommandScrollBack > -1)
1169                         strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1170                 console->CursorPos = strlen(console->LCommand);
1171                 CON_UpdateConsole();
1172         }
1173 }
1174
1175 #include <stdio.h>
1176 #include <stdlib.h>
1177 #include <stdarg.h>
1178 #include <string.h>
1179 #ifndef _WIN32_WCE
1180 #include <fcntl.h>
1181 #endif
1182 #include <ctype.h>
1183
1184 #include "pstypes.h"
1185 #include "u_mem.h"
1186 #include "error.h"
1187 #include "console.h"
1188 #include "cmd.h"
1189 #include "cvar.h"
1190 #include "gr.h"
1191 #include "gamefont.h"
1192 #include "pcx.h"
1193 #include "cfile.h"
1194
1195 #ifndef __MSDOS__
1196 int text_console_enabled = 1;
1197 #else
1198 int isvga();
1199 #define text_console_enabled (!isvga())
1200 #endif
1201
1202 int Console_open = 0;
1203
1204 /* Console specific cvars */
1205 /* How discriminating we are about which messages are displayed */
1206 cvar_t con_threshold = {"con_threshold", "0",};
1207
1208 /* Private console stuff */
1209 #define CON_NUM_LINES 40
1210
1211 static int con_initialized;
1212
1213 void con_parse(char *command);
1214 void con_hide();
1215
1216
1217 /* Free the console */
1218 void con_free(void)
1219 {
1220         if (con_initialized)
1221                 CON_Free();
1222         con_initialized = 0;
1223 }
1224
1225
1226 /* Initialise the console */
1227 void con_init(void)
1228 {
1229         grs_screen fake_screen;
1230         grs_font   fake_font;
1231
1232         fake_screen.sc_w = 320;
1233         fake_screen.sc_h = 200;
1234         fake_font.ft_w = 5;
1235         fake_font.ft_h = 5;
1236
1237         Console = CON_Init(&fake_font, &fake_screen, CON_NUM_LINES, 0, 0, 320, 200);
1238         console = Console;
1239
1240         CON_SetExecuteFunction(con_parse);
1241         CON_SetHideFunction(con_hide);
1242
1243
1244         cmd_init();
1245
1246         /* Initialise the cvars */
1247         cvar_registervariable (&con_threshold);
1248
1249         con_initialized = 1;
1250
1251         atexit(con_free);
1252 }
1253
1254
1255 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
1256 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
1257 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
1258
1259 void con_background(char *filename)
1260 {
1261         int pcx_error;
1262         grs_bitmap bmp;
1263         ubyte pal[256*3];
1264
1265         gr_init_bitmap_data(&bmp);
1266         pcx_error = pcx_read_bitmap(filename, &bmp, BM_LINEAR, pal);
1267         Assert(pcx_error == PCX_ERROR_NONE);
1268         gr_remap_bitmap_good(&bmp, pal, -1, -1);
1269         CON_Background(&bmp);
1270         gr_free_bitmap_data(&bmp);
1271 }
1272
1273
1274 void con_init_gfx(void)
1275 {
1276         CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1277         CON_Transfer(grd_curscreen, 0, 0, SWIDTH, SHEIGHT / 2);
1278
1279         con_background(CON_BG);
1280 }
1281
1282
1283 void con_resize(void)
1284 {
1285         CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1286         CON_Resize(0, 0, SWIDTH, SHEIGHT / 2);
1287         con_background(CON_BG);
1288 }
1289
1290 /* Print a message to the console */
1291 void con_printf(int priority, char *fmt, ...)
1292 {
1293         va_list arglist;
1294         char buffer[2048];
1295
1296         if (priority <= ((int)con_threshold.value))
1297         {
1298                 va_start (arglist, fmt);
1299                 vsprintf (buffer,  fmt, arglist);
1300                 va_end (arglist);
1301
1302                 if (con_initialized)
1303                         CON_Out(buffer);
1304
1305 /*              for (i=0; i<l; i+=CON_LINE_LEN,con_line++)
1306                 {
1307                         memcpy(con_display, &buffer[i], min(80, l-i));
1308                 }*/
1309
1310                 if (text_console_enabled)
1311                 {
1312                         /* Produce a sanitised version and send it to the standard output */
1313                         char *p1, *p2;
1314
1315                         p1 = p2 = buffer;
1316                         do
1317                                 switch (*p1)
1318                                 {
1319                                 case CC_COLOR:
1320                                 case CC_LSPACING:
1321                                         p1++;
1322                                 case CC_UNDERLINE:
1323                                         p1++;
1324                                         break;
1325                                 default:
1326                                         *p2++ = *p1++;
1327                                 }
1328                         while (*p1);
1329                         *p2 = 0;
1330
1331                         printf("%s", buffer);
1332                 }
1333         }
1334 }
1335
1336 /* Check for new console input. If it's there, use it */
1337 void con_update(void)
1338 {
1339         con_draw();
1340 }
1341
1342
1343 int con_events(int key)
1344 {
1345         return CON_Events(key);
1346 }
1347
1348
1349 /* Draw the console */
1350 void con_draw(void)
1351 {
1352         CON_DrawConsole();
1353 }
1354
1355 /* Show the console */
1356 void con_show(void)
1357 {
1358         Console_open = 1;
1359         CON_Show();
1360 }
1361
1362 void con_hide(void)
1363 {
1364         Console_open = 0;
1365 }
1366
1367 void con_parse(char *command)
1368 {
1369         cmd_parse(command);
1370 }