//
// Allegro-based routines
//
#include <ctype.h>
#include <string.h>
#include <allegro.h>
#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;ctr<MAX_FONTS;ctr++)
if(ire_fontfile[ctr])
{
ilog_quiet("Font %d: %s\n",ctr,ire_fontfile[ctr]);
irecon_loadfont(ctr);
}
}
/*
* get_num - User types in a number, animate things in the background
*/
int irecon_getinput(char *buffer, int maxlen)
{
int input=0;
int bufpos=0;
char buf[128];
if(maxlen>127)
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<maxlen)
{
buf[bufpos++]=input&0xff;
buf[bufpos]=0;
}
}
if((input>>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);
}