// // Allegro-based routines // #include #include #include #include "media.h" #include "ithelib.h" #include "console.h" #include "loadfile.h" #include "sound.h" // Defines #define CONSOLE_MAX 128 // Maximum 128 lines (would be 1024 pixels high) #define MAX_FONTS 16 // Variables //extern FONT *font; extern int buggy; // Were warnings detected? FONT *curfont; DATAFILE *ire_font[MAX_FONTS]; static char *ire_fontfile[MAX_FONTS]; static BITMAP *console_backing; static int ire_textcolour,console_on=0,printline=0,MouseActivated=0,prevcol=0; static int console_x,console_y,console_w,console_h,console_w8,console_h8; static int conpos; char *lastvrmcall=NULL; char *blametrace=NULL; int ilog_break=1; struct CONSOLELINE { unsigned int colour; FONT *font; char text[256]; }; static struct CONSOLELINE console_line[CONSOLE_MAX]; extern int mapx,mapy; // Functions void irecon_init(int x, int y, int w, int h); void irecon_term(); void irecon_update(); void irecon_cls(); void irecon_clearline(); void irecon_newline(); void irecon_colour(int r, int g, int b); void irecon_print(const char *msg); void irecon_printxy(int x, int y, const char *msg); void irecon_mouse(int on); void irecon_loadcol(); void irecon_savecol(); void Show(); void ithe_userexitfunction(); static void ilog_console(const char *msg, ...); static void irecon_printf_core(const char *linebuf); // Code void irecon_savecol() { prevcol=ire_textcolour; } void irecon_loadcol() { ire_textcolour=prevcol; } void irecon_mouse(int on) { if(on) { if(!MouseActivated) show_mouse(swapscreen); } else { if(MouseActivated) show_mouse(NULL); } MouseActivated=on; } /* * Start up the console, set desired width and height */ void irecon_init(int x, int y, int w, int h) { if(console_on) return; console_on = 1; ilog_quiet("Create console %d,%d at %d,%d\n",w*8,h*8,x,y); if(h > CONSOLE_MAX) h = CONSOLE_MAX; h--; // 80 = 0 to 79 console_x=x; console_y=y; console_w=w; console_h=h; console_w8=w*8; console_h8=(h+1)*8; printline=h; curfont = font; console_backing = create_bitmap(console_w8,console_h8); // Make the restore buffer blit(swapscreen,console_backing,x,y,0,0,console_w8,console_h8); // Grab it irecon_cls(); // Flush the system irecon_colour(255,255,255); // Default to white ilog_printf = ilog_console; // Use as default debugging output henceforth conpos=0; } /* * Shut down the console, stop using the backing bitmap */ void irecon_term() { if(!console_on) return; console_on = 0; ilog_printf = ilog_text; destroy_bitmap(console_backing); } /* * Redraw the console */ void irecon_update() { int ctr; if(!console_on) return; blit(console_backing,swapscreen,0,0,console_x,console_y,console_w8,console_h8); for(ctr=0;ctr<=console_h;ctr++) textprintf_ex(swapscreen, console_line[ctr].font, console_x, console_y+(ctr*8), console_line[ctr].colour, -1, "%s",console_line[ctr].text); #ifndef _WIN32 ShowPartial(console_x,console_y,console_w8,console_h8); #else Show(); // Update entire screen to fix a bug in Windows XP #endif } /* * Clear the current line and start again */ void irecon_clearline() { if(!console_on) return; strcpy(console_line[printline].text,""); console_line[printline].font = font; console_line[printline].colour = (unsigned int)ire_textcolour; conpos=0; } /* * Clear the entire console */ void irecon_cls() { int ctr; if(!console_on) return; for(ctr=0;ctr<=console_h;ctr++) { strcpy(console_line[ctr].text,""); console_line[ctr].font = font; } irecon_newline(); // Hack: this 'primes' the system after a CLS } /* * Scroll the console for end-of-line, by moving everything up one */ void irecon_newline() { int ctr; if(!console_on) return; for(ctr=0;ctr<=console_h;ctr++) console_line[ctr]=console_line[ctr+1]; irecon_clearline(); } /* * Set the current text colour */ void irecon_colour(int r, int g, int b) { ire_textcolour = makecol((unsigned int)r,(unsigned int)g,(unsigned int)b); } /* * Set the current text colour for multicoloured fonts */ void irecon_colourfont() { } /* * Add a simple line of text (no formatting) */ void irecon_print(const char *msg) { if(!console_on) return; //if(conlog) // ilog_quiet("PRN: %s",msg); // If there is a CR, the logger will know if(!msg[0]) // If it's blank, don't bother { irecon_newline(); irecon_update(); return; } strcat(console_line[printline].text,msg); // Stop a little '^' from appearing at the end of the line.. strdeck(console_line[printline].text,'\n'); strdeck(console_line[printline].text,'\r'); conpos=strlen(console_line[printline].text); // Register the colour we're going to use console_line[printline].colour = (unsigned int)ire_textcolour; if(strchr(msg,'\n') != NULL) // If there is a CR, act upon it { irecon_newline(); irecon_update(); conpos=0; } } /* * printf - Printf on the console and split the string if it won't fit. * I've never done word splits before, so I'm making this up * as I go along.. I presume there is a 'proper' way to do it? */ void irecon_printf(const char *msg, ...) { char linebuf[MAX_LINE_LEN]; char *ptr,*ptr2; va_list ap; if(!console_on) return; va_start(ap, msg); #ifdef _WIN32 _vsnprintf(linebuf,MAX_LINE_LEN,msg,ap); // Temp is now the message #else #ifdef __DJGPP__ vsprintf(linebuf,msg,ap); #else vsnprintf(linebuf,MAX_LINE_LEN,msg,ap); #endif #endif // Replace '~' with " do { ptr=strchr(linebuf,'~'); if(ptr) *ptr='\"'; } while(ptr); // If it has any pipe characters (line break) split it into chunks, // otherwise just print it if(!strchr(linebuf,'|')) { irecon_printf_core(linebuf); va_end(ap); return; } // Okay, there are some pipes, split it up ptr=linebuf; do { ptr2=strchr(ptr,'|'); if(ptr2) { *ptr2=0; irecon_printf_core(ptr); irecon_newline(); ptr=ptr2+1; } else irecon_printf_core(ptr); } while(ptr2); va_end(ap); } /* * printf - Printf on the console and split the string if it won't fit. * I've never done word splits before, so I'm making this up * as I go along.. I presume there is a 'proper' way to do it? */ void irecon_printf_core(const char *linebuf) { char line[MAX_LINE_LEN]; char oldchar; int len,pos; char *ptr; len=strlen(linebuf); pos = conpos; //ilog_quiet("%d,%d\n[%s]\n",pos,len,linebuf); // Check for simple case if(pos+len<=console_w) { irecon_print(linebuf); return; } SAFE_STRCPY(line,linebuf); do { // Punch a hole. oldchar=line[console_w-pos]; line[console_w-pos]=0; ptr=strrchr(line,' '); if(ptr) { *ptr=0; // Okay, punch the hole here instead, fix old hole line[console_w-pos]=oldchar; // ilog_quiet("{%s}\n",line); irecon_print(line); irecon_newline(); irecon_update(); pos=0; } else { // If there's something in front, start a new line instead if(pos>0) { irecon_newline(); irecon_printf(linebuf); irecon_update(); return; } else // otherwise do emergency break { ptr=&line[console_w-pos]; irecon_print(line); irecon_newline(); irecon_update(); pos=0; } } ptr++; strcpy(line,ptr); len=strlen(line); } while(len > console_w); } /* * Write a string direct to screen, not via the console */ void irecon_printxy(int x,int y,const char *msg) { char line[MAX_LINE_LEN]; SAFE_STRCPY(line,msg); strdeck(line,'\n'); strdeck(line,'\r'); textout_ex(swapscreen,curfont,line,x,y,(unsigned int)ire_textcolour,-1); } /* * Set font to use */ int irecon_font(int fnum) { int ctr,got_font; // Default to system font curfont=font; // If the font is out of range, abort if(fnum<1 || fnum>MAX_FONTS) { if(fnum != 0) ilog_quiet("Font %d: doesn't exist\n",fnum); return text_height(curfont); } // If the font seems to exist but doesn't, abort if(!ire_font[fnum]) { ilog_quiet("Font %d: doesn't really exist\n",fnum); ilog_quiet("Font %d: fname = %s\n",fnum,ire_fontfile[fnum]); return text_height(curfont); } // The datafile is an array, terminated by a DAT_END object ctr=0; got_font=0; while(ire_font[fnum][ctr].type != DAT_END) { // Look for font data if(ire_font[fnum][ctr].type == DAT_FONT) { curfont = (FONT *)ire_font[fnum][ctr].dat; got_font=1; } // Look for palette data if(ire_font[fnum][ctr].type == DAT_PALETTE) { // Switch to full colour mode (use font's own internal colours) ire_textcolour = -1; // And set the palette to the one for this font select_palette(ire_font[fnum][ctr].dat); } ctr++; } return text_height(curfont); } /* * Master screen update function. Copies swap screen to the physical screen. */ void Show() { if(MouseActivated) { //printf("SH: SHM\n"); fflush(stdout); show_mouse(swapscreen); //printf("SH: ACQ\n"); fflush(stdout); // acquire_screen(); //printf("SH: BLI\n"); fflush(stdout); blit(swapscreen,screen,0,0,0,0,640,480); //printf("SH: REL\n"); fflush(stdout); // release_screen(); //printf("SH: SH2\n"); fflush(stdout); show_mouse(screen); //printf("SH: FIN\n"); fflush(stdout); } else { // acquire_screen(); blit(swapscreen,screen,0,0,0,0,640,480); // release_screen(); } } /* * Screen update function. Copies swap screen to the physical screen. * This version does a 'dirty-rectangle' update instead of the whole screen */ void ShowPartial(int x, int y, int w, int h) { if(MouseActivated) { show_mouse(swapscreen); acquire_bitmap(screen); // draw_sprite(screen,swapscreen,0,0); blit(swapscreen,screen,x,y,x,y,w,h); show_mouse(screen); release_bitmap(screen); } else { acquire_bitmap(screen); // draw_sprite(screen,swapscreen,0,0); blit(swapscreen,screen,x,y,x,y,w,h); release_bitmap(screen); } } /* * Simple screen update function. Same as Show, but without mouse support. */ void ShowSimple() { acquire_screen(); blit(swapscreen,screen,0,0,0,0,640,480); release_screen(); } /* * User-level logging function for the debugger */ void ilog_console(const char *msg, ...) { char buffer[MAX_LINE_LEN]; va_list ap; va_start(ap, msg); vsprintf(buffer,msg,ap); va_end(ap); if(ilog_break) if(key[KEY_ESC]) { ilog_break=0; ithe_userexitfunction(); exit(1); } ilog_quiet(buffer); irecon_print(buffer); irecon_update(); } /* * Register a font for later loading */ void irecon_registerfont(const char *filename, int no) { int len; // Too many fonts if(no>MAX_FONTS) { printf("Error loading font %d - max font no is %d\n",no,MAX_FONTS); return; } // System font! if(no<1) { // printf("Error loading font %d - font 0 is reserved\n",no); return; } len=strlen(filename)+1; ire_fontfile[no]=M_get(1,len); strcpy(ire_fontfile[no],filename); //printf("Registered font %d:%s\n",no,filename); return; } /* * Load in a font */ int irecon_loadfont(int no) { // Too many fonts if(no>MAX_FONTS) { ilog_quiet("Error loading font %d - max font no is %d\n",no,MAX_FONTS); return 0; } // System font! if(no<1) { ilog_quiet("Error loading font %d - font 0 is reserved\n",no); return 0; } // Font not registered! if(!ire_fontfile[no]) { ilog_quiet("Error loading font %d - internal error\n",no); return 0; } // Already used if(ire_font[no]) { ilog_quiet("Error loading font %d:%s - already loaded\n",no,ire_fontfile[no]); return 0; } ire_font[no] = iload_datafile(ire_fontfile[no]); //printf("zRegistering font %d:%s, result = %x\n",no,ire_fontfile[no],ire_font[no]); return 1; } /* * Load all fonts in */ void irecon_loadfonts() { int ctr; for(ctr=0;ctr127) maxlen=127; strcpy(buf,buffer); bufpos=strlen(buf); buf[bufpos]=0; do { irecon_clearline(); if(buf[0] != 0) irecon_print(buf); // Printing an empty line makes a newline irecon_print("_"); // Cursor irecon_update(); Show(); if(keypressed()) { input = readkey(); if(isprint(input&0xff)) // If printable { if(bufpos>8) == KEY_DEL || (input>>8) == KEY_BACKSPACE) if(bufpos>0) { bufpos--; buf[bufpos]=0; } } else input=0; } while((input>>8) != KEY_ESC && (input>>8) != KEY_ENTER); irecon_clearline(); irecon_print(buf); irecon_print("\n"); if((input>>8) == KEY_ESC) return 0; strcpy(buffer,buf); return 1; } /* * Report a minor error */ void Bug(const char *msg, ...) { char buffer[MAX_LINE_LEN]; unsigned int colour; va_list ap; va_start(ap, msg); vsprintf(buffer,msg,ap); va_end(ap); ilog_quiet("BUG: %s",buffer); colour = (unsigned int)ire_textcolour; ire_textcolour = makecol(200,0,0); irecon_print("BUG: "); irecon_print(buffer); ire_textcolour = colour; irecon_update(); buggy=1; } /* * Kill the graphics and take us back to text mode */ void KillGFX() { static int c=0; if(c) return; c=1; ilog_quiet("Kill GFX:\n"); set_gfx_mode(GFX_TEXT,80,25,0,0); #ifdef __linux__ c=system("reset"); #endif ilog_quiet("Irecon-Term\n"); irecon_term(); } // Function needed for ithelib void ithe_userexitfunction() { static int c=0; if(c) { ilog_quiet("iUser Exit: already done\n"); return; } ilog_quiet("iUser Exit\n"); c=1; ilog_quiet("Stopping graphics\n"); KillGFX(); ilog_quiet("Graphics stopped\n"); S_Term(); ilog_quiet("Sound stopped\n"); if(lastvrmcall) ilog_quiet("Crashed in VRM %s\n",lastvrmcall); if(blametrace) ilog_quiet("%s was called by %s\n",lastvrmcall,blametrace); }