//  AMIGA graphics package for UMoria 5.4   Henrik Harmsen 920509.
// Note to anyone who reads this: This sourcecode is quite raw and
// unrefined. It needs some cleaning up concerning readability.
// I didn't have time for this, so you get what you get...

// The two functions FastLineClear and FastMemCpy are written in assembler.
// If you ever change the size of the screen or the position of the 
// graphics you will have to rewrite these.

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/iff.h>
#include "amiga.h"

#define CTRL(x) (x & 0x1F)

UBYTE * convert_menunum_to_str(int,int);

UBYTE *vers = "\0$VER: Amiga_Moria_Graphics 1.1"__DATE__;
int shifted_command = FALSE;
int control_command = FALSE;
extern int rogue_like_commands;
extern struct Menu project_menu;
struct ConsoleDevice *ConsoleDevice = NULL;
static struct IOStdReq ioreq;

static UBYTE screen[66][22]; // array that holds current graphics of screen map

static void CleanExit(int);
static void CleanUp();

static int curx, cury; // Current x, y position of cursor on screen

static struct TextAttr my_font =  {
	"topaz.font",
	TOPAZ_EIGHTY,
	FS_NORMAL,
	FPF_ROMFONT
};

static int color_trans[16] =  {
	0,1,2,3,4,5,7,12,8,9,10,11,12,13,6,15
};

/* Main background screen */
static struct NewScreen NewScreen = {
  0,                        /* LeftEdge */
  0,                        /* TopEdge */
  0,                        /* Width */
  0,                        /* Height */
  4,                        /* No. Bitplanes */
  0, 1,                     /* DetailPen, BlockPen */
  HIRES,                    /* ViewModes */
  CUSTOMSCREEN,             /* Screen type */
  &my_font,  				/* my font */
  "Amiga screen",          /* Screen Title */
  (struct Gadget *)NULL,    /* Gadget list */
  (struct BitMap *)NULL     /* custom bitmap */
};

/* Main background window */
static struct NewWindow NewWindow = {
  0,                      /* Left edge */
  0,                      /* Top edge */
  0,                      /* Width */
  0,                      /* Height */
  -1, -1,                 /* Pens */
  RAWKEY | MOUSEBUTTONS | MENUPICK,                 /* IDCMP flags */
  ACTIVATE | BORDERLESS,  /* Window flags */
  NULL,                   /* First gadget */
  NULL,                   /* Image data */
  NULL,                   /* Title */
  NULL,                   /* Pointer to screen structure */
  NULL,                   /* Super BitMap ? */
  0,0,0,0,                /* MIN/MAX sizing */
  CUSTOMSCREEN            /* Type of screen */
};


/*
 * Should initialise all of these to NULL to be certain that
 * CleanExit() will function correctly. Most compilers will do this
 * anyway, but better safe than GURUed.
 */

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Library *IFFBase = NULL;

IFFFILE gfxfile = NULL;
IFFFILE gfxfilesmall = NULL;

static struct Screen *AmigaScreen = NULL;
static struct Window *AmigaWindow = NULL;

static struct RastPort *RPort;
static struct ViewPort *VPort;

static unsigned char Flags;  /* Global flags */
static struct MsgPort *port;
static ULONG device;


// this array describes what graphics should be printed in respect to ASCII character
// of monster etc.
int GFX_CORR[2][256];

static UBYTE spare[64000];


struct BitMap gfxdatabm;
struct BitMap gfxdatasmallbm;

struct IMAGE  {
	int width, height;
	int bitplanes;
};

static struct IMAGE GfxData = { 320, 56, 4 };
static struct IMAGE GfxDataSmall = { 80, 14, 4 }; // width must be multiple of 16!
     
//extern UBYTE GFX_SMALL[];
//extern UBYTE GFX[];

#define NCOLOURS 16

static UWORD ColourTableTitle[16];

static UWORD ColourTable[16] =
{
	0x0000,		/* Color 0 */
	0x0DCA,		/* Color 1 */
	0x0843,		/* Color 2 */
	0x0888,		/* Color 3 */
	0x0C86,		/* Color 4 */
	0x0EB0,		/* Color 5 */
	0x08F5,		/* Color 6 */
	0x0080,		/* Color 7 */
	0x0040,		/* Color 8 */
	0x0332,		/* Color 9 */
	0x00AF,		/* Color 10 */
	0x0007,		/* Color 11 */
	0x000F,		/* Color 12 */
	0x0800,		/* Color 13 */
	0x0555,		/* Color 14 */
	0x0F22		/* Color 15 */
};


int LINES=24, COLS=80;  /* Defaults */
int direct_more;
int direct_more_time;


/*
 *  Start of code. 
 */

initscr()
{
	int i,x,y;

	struct BitMapHeader *bmhd;

	static BOOL AmigaGfxStarted = FALSE;
	
	init_GFX_CORR(); // Initialize relation between ASCII character and GFX

	setmem(screen,66*22,0);

	if(AmigaGfxStarted)
		return ERR;

	AmigaGfxStarted = TRUE;



	for(i=0;i<4;i++) {
		gfxdatabm.Planes[i] = NULL;
	}

	for(i=0;i<4;i++) {
		gfxdatasmallbm.Planes[i] = NULL;
	}

	if((IntuitionBase = (struct IntuitionBase *)
	    OpenLibrary("intuition.library", 0)) == NULL) {
		fprintf(stderr, "Failed to open Intuition library");
		CleanExit(10);
	}

	NewScreen.Height = NewWindow.Height = 200;
	NewScreen.Width = NewWindow.Width = 640;

	LINES = 25;
	COLS = 80;

	/* Open graphics library */
	if((GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library", 0))==NULL) {
		fprintf(stderr, "Failed to open Graphics library \n");
		CleanExit(10);
	}

	if(OpenDevice("console.device",-1L,(struct IORequest *)&ioreq,0L))
		CleanExit(10);
	ConsoleDevice=(struct ConsoleDevice *)ioreq.io_Device;


	if(!(IFFBase =(struct Library *) OpenLibrary(IFFNAME,IFFVERSION))) {
		fprintf(stderr,"Failed to open iff.library, Please copy iff.library >= v18.5 to your LIBS: \n");
		CleanExit(10);
	}


// open gfxdata picture

	if(!(gfxfile=OpenIFF("moria:moria_gfx.iff"))) {
		fprintf(stderr,"Error opening file moria:moria_gfx.iff\n");
		CleanExit(10);
	}

	if(!(bmhd=GetBMHD(gfxfile))) {
		fprintf(stderr,"BitMapHeader not found in file moria:moria_gfx.iff\n");
		CleanExit(10);
	}

	if (((GfxData.width) != (bmhd->w)) || ((GfxData.height) != (bmhd->h)) || ((GfxData.bitplanes) != (bmhd->nPlanes))) {
		fprintf(stderr,"moria:moria_gfx.iff has wrong dimensions !\nIt should have a width of %d pixels, ",GfxData.width);
		fprintf(stderr,"and a height of %d pixels\n", GfxData.height);
		fprintf(stderr,"It should use 16 colours, no more, no less!\n");
		CleanExit(10);
	}

	GetColorTab(gfxfile,ColourTable);

	gfxdatabm.BytesPerRow = GfxData.width/8;
	gfxdatabm.Rows = GfxData.height;
	gfxdatabm.Flags = 0;
	gfxdatabm.Depth = 4;
	for (i=0; i<4; i++) {
		gfxdatabm.Planes[i] = (PLANEPTR) AllocMem((GfxData.width*GfxData.height)/8,MEMF_ANY);
		if (!(gfxdatabm.Planes[i])) {
			fprintf(stderr,"Not enough memory to allocate bitmap!\n");
			CleanExit(10);
		}
	}


	if(!DecodePic(gfxfile,&gfxdatabm)) {
		fprintf(stderr,"Can't decode picture moria:moria_gfx.iff");
		CleanExit(10);
	}

	CloseIFF(gfxfile);
	
	gfxfile = NULL;


// open small gfxdata picture


	if(!(gfxfilesmall=OpenIFF("moria:moria_gfxsmall.iff"))) {
		fprintf(stderr,"Error opening file moria:moria_gfxsmall.iff\n");
		CleanExit(10);
	}
	if(!(bmhd=GetBMHD(gfxfilesmall))) {
		fprintf(stderr,"BitMapHeader not found in file moria:moria_gfxsmall.iff\n");
		CleanExit(10);
	}
	
	if (((GfxDataSmall.width) != (bmhd->w)) || ((GfxDataSmall.height) != (bmhd->h)) || ((GfxDataSmall.bitplanes) != (bmhd->nPlanes))) {
		fprintf(stderr,
		"moria:moria_gfxsmall.iff has wrong dimensions !\nIt should have a width of %d pixels, ",
		GfxDataSmall.width);
		fprintf(stderr,"and a height of %d pixels\n", GfxDataSmall.height);
		fprintf(stderr,"It should use 16 colours, no more, no less!\n");
		CleanExit(10);
	}

	gfxdatasmallbm.BytesPerRow = GfxDataSmall.width/8;
	gfxdatasmallbm.Rows = GfxDataSmall.height;
	gfxdatasmallbm.Flags = 0;
	gfxdatasmallbm.Depth = 4;
	for (i=0; i<4; i++) {
		gfxdatasmallbm.Planes[i] = (PLANEPTR) AllocMem((GfxDataSmall.width*GfxDataSmall.height)/8,MEMF_ANY);
		if (!gfxdatasmallbm.Planes[i]) {
			fprintf(stderr,"Not enough memory to allocate bitmap!\n");
			CleanExit(10);
		}
	}


	if(!DecodePic(gfxfilesmall,&gfxdatasmallbm)) {
		fprintf(stderr,"Can't decode picture moria:moria_gfxsmall.iff");
		CleanExit(10);
	}

	CloseIFF(gfxfilesmall);

	gfxfilesmall = NULL;

// Open Screen and window.

	if((AmigaScreen=(struct Screen *)OpenScreen(&NewScreen)) == NULL) {
		fprintf(stderr, "Failed to open Screen");
		CleanExit(10);
	}

	RPort = &(AmigaScreen->RastPort);
	VPort = &(AmigaScreen->ViewPort);

	SetDrMd(RPort, JAM2);
	SetAPen(RPort, 1);

	NewWindow.Screen = AmigaScreen;  /* Must do this !! */
		
	if((AmigaWindow=(struct Window *)OpenWindow(&NewWindow)) == NULL) {
		fprintf(stderr, "Failed to open Window\n");
		CleanExit(10);
	}
	
	SetMenuStrip(AmigaWindow, &project_menu);

// open Title picture and display.

	if(!(gfxfile=OpenIFF("moria:moria_title.iff"))) {
		fprintf(stderr,"Error opening file moria:moria_title.iff\n");
		CleanExit(10);
	}

	if(!(bmhd=GetBMHD(gfxfile))) {
		fprintf(stderr,"BitMapHeader not found in file moria:moria_title.iff\n");
		CleanExit(10);
	}

	if ((640 != bmhd->w) || (200 != bmhd->h) || (4 != bmhd->nPlanes)) {
		fprintf(stderr,"moria:moria_title.iff has wrong dimensions !\nIt should have a width of %d pixels, ",640);
		fprintf(stderr,"and a height of %d pixels\n", 200);
		fprintf(stderr,"It should use 16 colours, no more, no less!\n");
		CleanExit(10);
	}

	GetColorTab(gfxfile,ColourTableTitle);

	LoadRGB4(VPort, ColourTableTitle, NCOLOURS);

	if(!DecodePic(gfxfile,&(AmigaScreen->BitMap))) {
		fprintf(stderr,"Can't decode picture moria:moria_title.iff");
		CleanExit(10);
	}

	CloseIFF(gfxfile);

	gfxfile = NULL;

	inkey();
	clear();
	LoadRGB4(VPort, ColourTable, NCOLOURS);
	return OK;
}


/*
 *  Close the screen and libraries.
 */

exit_curses()                  /* called from main prior to exit. */
{
	CleanUp();
	return OK;
}

static void CleanExit(RetCode)
	int RetCode;
{
	CleanUp();
	exit(RetCode);
}

static void CleanUp()
{
	int i;
	if(AmigaWindow) {
		ClearMenuStrip(AmigaWindow);
		CloseWindow(AmigaWindow);
		AmigaWindow = NULL;
	}
	if(AmigaScreen) {
		CloseScreen(AmigaScreen);
		AmigaScreen = NULL;
	}
	if(gfxfile) {
		CloseIFF(gfxfile);
		gfxfile = NULL;
	}
	if(gfxfilesmall) {
		CloseIFF(gfxfile);
		gfxfilesmall = NULL;
	}
	if(IFFBase) {
		CloseLibrary(IFFBase);
		IFFBase = NULL;
	}
	for (i=0 ; i < 4 ; i++) {
		if(gfxdatabm.Planes[i]) {
			FreeMem(gfxdatabm.Planes[i],(GfxData.width*GfxData.height)/8);
			gfxdatabm.Planes[i] = NULL;
		}
	}
	for (i=0 ; i < 4 ; i++) {
		if(gfxdatasmallbm.Planes[i]) {
			FreeMem(gfxdatasmallbm.Planes[i],(GfxDataSmall.width*GfxDataSmall.height)/8);
			gfxdatasmallbm.Planes[i] = NULL;
		}
	}
	if(ConsoleDevice) {
		CloseDevice((struct IORequest *)&ioreq);
		ConsoleDevice = NULL;
	}
	if(GfxBase) {
		CloseLibrary((struct Library *)GfxBase);
		GfxBase = NULL;
	}
	if(IntuitionBase) {
		CloseLibrary((struct Library *)IntuitionBase);
		IntuitionBase = NULL;
	}

}

void
set_color(n, r, g, b)
	short n;
	unsigned int r, g, b;
{
	SetRGB4(VPort, n, r, g, b);
}

mvaddstr(row,col,str) 
	int row, col;
	char *str;
{
	static UBYTE tmparr[80];
	int len;
	int i,j,k;

	k=0;
	len = strlen(str);

	if (str[len-1] == '\n') len--;

	for (i=0; i<len; i++) {
		if (str[i] == '\t') {
			for (j = 0; j < 8; j++) {
				tmparr[k++] = ' ';
			}
		} else {
			tmparr[k++] = str[i];
		}
	}

	SetSoftStyle(RPort, FS_NORMAL, ~0L);
	SetDrMd(RPort, JAM2);
	SetAPen(RPort, 1);
	Move(RPort, col * 8, 6+row * 8);
	Text(RPort, tmparr, k);
	WaitBlit();
	cury = row;
	curx = col + k;
}

mvaddstrc(row,col,str,color) 
	int row, col,color;
	char *str;
{
	static UBYTE tmparr[80];
	int len;
	int i,j,k;


	k=0;
	len = strlen(str);

	if (str[len-1] == '\n') len--;

	for (i=0; i<len; i++) {
		if (str[i] == '\t') {
			for (j = 0; j < 8; j++) {
				tmparr[k++] = ' ';
			}
		} else {
			tmparr[k++] = str[i];
		}
	}

	if (color > 15 ) color = 15;
	if (color < 0 ) color = 0;
	
	color = color_trans[color];

	SetSoftStyle(RPort, FS_NORMAL, ~0L);
	SetDrMd(RPort, JAM2);
	SetAPen(RPort, color);
	Move(RPort, col * 8, 6+row * 8);
	Text(RPort, tmparr, k);
	WaitBlit();
	cury = row;
	curx = col + k;
}


mvaddstrg(row,col,str) // special lazy hack for the original screen map fuction 
	int row, col;
	UBYTE *str;
{
	int len;
	int i,j,k;


	len = strlen(str);
	
	mvaddch(row,0,str[0]);

	for (i = 1; i < len-1; i++)  {
		if (str[i] != ' ')
			putgfx(i,row,str[i]);
	}

	mvaddch(row,i,str[i]);

	cury = row;
	curx = col + k;
}

mvaddch(row,col,c) 
	int row, col;
	char c;
{
	SetSoftStyle(RPort, FS_NORMAL, ~0L);
	SetDrMd(RPort, JAM2);
	SetAPen(RPort, 1);
	Move(RPort, col * 8, 6 + row * 8);
	Text(RPort, &c, 1);
	WaitBlit();
	curx = col + 1;
	cury = row;
}


addch(c) 
	char c;
{
	int x,y;

	x = curx;
	y = cury;

	SetSoftStyle(RPort, FS_NORMAL, ~0L);
	Move(RPort, x * 8, 6 + y * 8);
	Text(RPort, &c, 1);
	WaitBlit();
	curx++;
}

mvaddchg(row,col,c) 
	int row, col;
	UBYTE c;
{
	if (screen[col-13][row-1] != c)
		putgfx(col,row,c);
	curx = col + 1;
	cury = row;
	screen[col-13][row-1] = c;
}

clear() {
    SetAPen(RPort, 0);
    SetDrMd(RPort, JAM2);
    RectFill(RPort, 0, 0, 639, 199);
    WaitBlit();
}

zap_map() {
	setmem(screen,66*22,0); // reset info-screen.
}

clear_line_fast(ULONG row) {
	ULONG tmp = row*640+13;
	FastLineClear((ULONG)AmigaScreen->BitMap.Planes[0]+tmp);
	FastLineClear((ULONG)AmigaScreen->BitMap.Planes[1]+tmp);
	FastLineClear((ULONG)AmigaScreen->BitMap.Planes[2]+tmp);
	FastLineClear((ULONG)AmigaScreen->BitMap.Planes[3]+tmp);
}

clrtoeol(row,col) 
	int row, col;
{
    int x,y;
    SetAPen(RPort, 0);
    SetDrMd(RPort, JAM2);
    RectFill(RPort, col*8,row*8, 639, row*8+7);
    WaitBlit();
}

clrtobot(row) 
	int row;
{
    SetAPen(RPort, 0);
    SetDrMd(RPort, JAM2);
    RectFill(RPort, 0, row*8, 639, 199);
    WaitBlit();
}

UBYTE
from_mouse_to_map_to_command(xx,yy) 
	int *xx,*yy;
{
	struct IntuiMessage *Message;
	int x,y;
	int mouseevent = FALSE;
	getch(TRUE); // flush the input buffer.
	flushallmessages(0);
	while (1) {
		Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort);
		while(!Message) {
			Wait(1<<AmigaWindow->UserPort->mp_SigBit);
			Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort);
		}
		if (Message->Class == MOUSEBUTTONS) {
			ReplyMsg(Message);
			*xx = AmigaScreen->MouseX / 8-13;
			*yy = AmigaScreen->MouseY / 8-1;
			x = *xx;
			y = *yy;
			if ( x<0 || x>65 || y<0 || y>21 )
				return 0;
			return ((screen[x][y]==' ') ? 0 : screen[x][y]);
		}
		ReplyMsg((struct Message *)Message);
	}
}

flushallmessages(usecs)
	int usecs;
{
	struct IntuiMessage *Message;
	while(Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort))
		ReplyMsg(Message);
}


check_input(microsecs)
int microsecs;
{
	struct IntuiMessage *Message;
	if (microsecs) {
		sendtimer(microsecs);
		waittimer();
	}
	Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort);
	// react to everything EXCEPT a key release.
	if(Message) {
		if((Message->Class == RAWKEY) && (Message->Code & 0x80)) {
			ReplyMsg(Message);
			return FALSE;
		}
		ReplyMsg(Message);
		return TRUE;
	}
	return FALSE;
}

int
wontprint(int code) {
	if ((code <= 0x59) & (code >= 0x4c))
		return TRUE;

	switch(code) {
	case 0x5f:
		return TRUE;
	}
	return FALSE;
}

int 
getch(flush)
	int flush;
{

#define BUFFERSIZE 1000
#define RAWBUFSIZ 50

	static unsigned char buffer[RAWBUFSIZ];
	static struct {
		UBYTE c;
		USHORT qual;
	} cbuf[BUFFERSIZE];
	static UBYTE *menupickstr;
	int i,len,k,numchars;
	ULONG qual;
	static int rpos = 0;
	static int wpos = 0;
	struct IntuiMessage *Message;
	static struct InputEvent ievent = { NULL, IECLASS_RAWKEY, 0, 0, 0 };
	static BOOL bufferfull = FALSE;
	int c;
	struct MenuItem *item;
	int menunum,itemnum;

// Flush all.
	if (flush == TRUE) {
		rpos = wpos = 0;
		bufferfull = FALSE;
		return 0;
	}
	// !! note: order of evaluation on || is guaranteed to be left-to-right,
	// this is exploited here !!
	while((Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort)) || ((wpos == rpos) && (!bufferfull))) {
		while(!Message) {
			Wait(1<<AmigaWindow->UserPort->mp_SigBit);
			Message = (struct IntuiMessage *)GetMsg(AmigaWindow->UserPort);
		}
		switch(Message->Class) {
		case RAWKEY:
			if(wontprint(Message->Code)) {
				ReplyMsg(Message);
				break;
			}
			ievent.ie_Code = Message->Code;
			ievent.ie_Qualifier = qual = Message->Qualifier;
			ievent.ie_position.ie_addr = *((APTR*)Message->IAddress);
			numchars = RawKeyConvert(&ievent, buffer, RAWBUFSIZ, NULL);
			ReplyMsg((struct Message *)Message);
			if(numchars == -1) {
				DisplayBeep(AmigaScreen);
				fprintf(stderr,"getch(): Raw buffer overflow !\n");
				fflush(stderr);
				numchars = 0;
			}
			len = numchars;
			for (k=0;k<len;k++) {
				if (bufferfull) {
					DisplayBeep(AmigaScreen);
					fprintf(stderr,"getch(): character buffer overflow !\n");
					fflush(stderr);
				} else {
					if (buffer[k] == '\r') {
						buffer[k] == '\n'; // we want NL's instead of CR's.
					}
					cbuf[wpos].c = buffer[k];
					cbuf[wpos].qual = qual;
					wpos = (wpos + 1) % BUFFERSIZE;
					if (wpos == rpos)
						bufferfull = TRUE;
				}
			}
			break;
		case MENUPICK:
			c = Message->Code;
			ReplyMsg(Message);
			while( c != MENUNULL ) {
				item = (struct MenuItem *) ItemAddress( &project_menu, c );
				if ((MENUNUM(c) != NOMENU) && (ITEMNUM(c) != NOITEM)) {
					menupickstr = convert_menunum_to_str(MENUNUM(c),ITEMNUM(c));
					len = strlen(menupickstr);
					for (k=0;k<len;k++) {
						if (bufferfull) {
							DisplayBeep(AmigaScreen);
							fprintf(stderr,"getch(): character buffer overflow !\n");
							fflush(stderr);
						} else {
							cbuf[wpos].c = menupickstr[k];
							cbuf[wpos].qual = qual;
							wpos = (wpos + 1) % BUFFERSIZE;
							if (wpos == rpos)
								bufferfull = TRUE;
						}
					}
				}
				c = item->NextSelect;
			}
			break;
		default:
			ReplyMsg(Message); 
			break;
		}
	}

	// Now we KNOW at least one character is in the buffer and no more 
	// messages are pending.

	// pop a character from the buffer and return it

	bufferfull = FALSE; // We read a character thus creating space in the buffer.
	c = cbuf[rpos].c;
	shifted_command = cbuf[rpos].qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT);
	control_command = cbuf[rpos].qual & IEQUALIFIER_CONTROL;
	rpos = (rpos + 1) % BUFFERSIZE;
	return c;
}

move(row, col) 
	int row, col;
{
	cury = row;
	curx = col;
	return;
}


move_low(row, col) 
	int row, col;
{
	int i,j;

	cury = row;
	curx = col;

	SetDrMd(RPort, COMPLEMENT);
	SetAPen(RPort, 1);
	for (i=0; i<8;i++) {
		WritePixel(RPort, i+col * 8, row * 8);
	}
	for (i=1; i<7;i++) {
		WritePixel(RPort, col * 8, i +row * 8);
		WritePixel(RPort, 1+col * 8, i +row * 8);
	}
	for (i=0; i<8;i++) {
		WritePixel(RPort, i+col * 8, 7+ row * 8);
	}
	for (i=1; i<7;i++) {
		WritePixel(RPort,  7+col * 8, i + row * 8);
		WritePixel(RPort, -1+7+col * 8, i + row * 8);
	}
	return;
}


move_high(row, col) 
	int row, col;
{
	int i,j;

	cury = row;
	curx = col;

	SetDrMd(RPort, COMPLEMENT);
	SetAPen(RPort, 1);
	for (i=0; i<8;i++) {
		WritePixel(RPort, i+col * 8, row * 8);
	}
	for (i=1; i<7;i++) {
		WritePixel(RPort, col * 8, i +row * 8);
		WritePixel(RPort, 1+col * 8, i +row * 8);
	}
	for (i=0; i<8;i++) {
		WritePixel(RPort, i+col * 8, 7+ row * 8);
	}
	for (i=1; i<7;i++) {
		WritePixel(RPort,  7+col * 8, i + row * 8);
		WritePixel(RPort, -1+7+col * 8, i + row * 8);
	}
	return;
}

get_x_cur()
{
	return curx;
}

get_y_cur()
{
	return cury;
}

refresh()
{
	return;
}


int
max(int x, int y) {
	if (x>y) {
		return x;
	}
	return y;
}


int
min(int x, int y) {
	if (x<y) {
		return x;
	}
	return y;
}


save_stdscr() 
{
	int k = 0;
	UBYTE *adr2;
	int pl,i;
	int size;

	size = AmigaScreen->BitMap.BytesPerRow * AmigaScreen->BitMap.Rows;
	for (pl = 0; pl <= 3; pl++) {
		adr2 = AmigaScreen->BitMap.Planes[pl];
		FastMemCpy(spare+k,adr2); // This copies EXACTLY 16000 bytes
		k += size;
	}
}


restore_stdscr() 
{
	int k = 0;
	UBYTE *adr2;
	int pl,i;
	int size;

	size = AmigaScreen->BitMap.BytesPerRow * AmigaScreen->BitMap.Rows;
	for (pl = 0; pl <= 3; pl++) {
		adr2 = AmigaScreen->BitMap.Planes[pl];
		FastMemCpy(adr2,spare+k); // This copies EXACTLY 16000 bytes
		k += size;
	}
}


putgfx(x, y, c)
	int x,y,c;
{
	int i, pl;

	ULONG adr,adr2,tmp1,tmp2,tmp3,tmp4;

//	if (c == ' ') {
//		mvaddch(y,x,c);
//		return;
//	}

	if (GFX_CORR[0][c] == -1 ) {
		mvaddch(y,x,c); /*// Could not find corresponding gfx for this ASCII*/
		return;
	}

// To the casual reader: This is a mess, but it's an optimised and
// FAST mess... :-)

	tmp1 = GFX_CORR[0][c] + GFX_CORR[1][c] * GfxData.width; 
	tmp2 = x+y*8*AmigaScreen->BitMap.BytesPerRow;
	tmp3 = GfxData.width/8;
	tmp4 = AmigaScreen->BitMap.BytesPerRow;

	adr = tmp1 + (ULONG)gfxdatabm.Planes[0];
	adr2 = tmp2 + (ULONG)AmigaScreen->BitMap.Planes[0];

	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;

	adr = tmp1+(ULONG)gfxdatabm.Planes[1];
	adr2 =tmp2+(ULONG)AmigaScreen->BitMap.Planes[1];

	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;


	adr = tmp1+(ULONG)gfxdatabm.Planes[2];
	adr2 = tmp2+(ULONG)AmigaScreen->BitMap.Planes[2];

	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;


	adr = tmp1+(ULONG)gfxdatabm.Planes[3];
	adr2 = tmp2+(ULONG)AmigaScreen->BitMap.Planes[3];

	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
	*(UBYTE *)adr2 = *(UBYTE *)adr;
	adr += tmp3;
	adr2 += tmp4;
}

print_screen_map(height,width) {

	int x,y;
	int i, pl;
	UBYTE c;
	ULONG adr11, adr21;
	ULONG adr12, adr22;
	ULONG tmp1;
	ULONG tmp2;
	ULONG tmp3;
	ULONG tmp4;
	ULONG tmp5;
	ULONG tmp6;

	int x_screen,y_screen,x_off,y_off;
	UBYTE data1,data2;
	int pos_modulo1, pos_modulo2;

	x_off = 122;
	y_off = 34;

	for (x=0; x<width;x++) {
		for (y=0; y<height;y++) {
		
			c = loc_symbol(y,x);

			if (GFX_CORR[0][c] == -1 ) {
				fprintf(stderr,"print_screen_map tries to print a non gfx char!\n");
				return;
			}

			if (c != ' ') {
				x_screen = x_off+x*2;
				y_screen = y_off+y*2;

// To the casual reader: This is a mess, but it's an optimised and
// FAST mess... :-)

				tmp1 = GFX_CORR[1][c]*GfxDataSmall.width/4+GFX_CORR[0][c]/4;
				tmp2 = y_screen*AmigaScreen->BitMap.BytesPerRow+x_screen/8;
				tmp3 = GfxDataSmall.width/8;
				tmp4 = AmigaScreen->BitMap.BytesPerRow;
				tmp5 = GFX_CORR[0][c] % 4;
				tmp6 = (x_screen % 8)/2;


				adr11 = (ULONG)gfxdatasmallbm.Planes[0]+tmp1;
					
				adr21 = (ULONG)AmigaScreen->BitMap.Planes[0]+tmp2;
		
				adr12 = adr11+tmp3;
				adr22 = adr21+tmp4; 
				
				pos_modulo1 = tmp5;
				pos_modulo2 = tmp6;
	
				switch(pos_modulo1) {
					case 0:
						data1 = 192 & *(UBYTE *)adr11;
						data2 = 192 & *(UBYTE *)adr12;
						break;
					case 1:
						data1 = 48 & *(UBYTE *)adr11;
						data2 = 48 & *(UBYTE *)adr12;
						break;
					case 2:
						data1 = 12 & *(UBYTE *)adr11;
						data2 = 12 & *(UBYTE *)adr12;
						break;
					case 3:
						data1 = 3 & *(UBYTE *)adr11;
						data2 = 3 & *(UBYTE *)adr12;
				}

				if (pos_modulo2 < pos_modulo1) {
				data1 <<= (2*(pos_modulo1 - pos_modulo2));
				data2 <<= (2*(pos_modulo1 - pos_modulo2));
				} else { 
					if (pos_modulo2 > pos_modulo1) {
						data1 >>= (2*(pos_modulo2 - pos_modulo1));
						data2 >>= (2*(pos_modulo2 - pos_modulo1));
					}
				}

				*(UBYTE *)adr21 |= data1;
				*(UBYTE *)adr22 |= data2;

				adr11 = (ULONG)gfxdatasmallbm.Planes[1]+tmp1;
					
				adr21 = (ULONG)AmigaScreen->BitMap.Planes[1]+tmp2;
		
				adr12 = adr11+tmp3;
				adr22 = adr21+tmp4; 
				
				pos_modulo1 = tmp5;
				pos_modulo2 = tmp6;
	
				switch(pos_modulo1) {
					case 0:
						data1 = 192 & *(UBYTE *)adr11;
						data2 = 192 & *(UBYTE *)adr12;
						break;
					case 1:
						data1 = 48 & *(UBYTE *)adr11;
						data2 = 48 & *(UBYTE *)adr12;
						break;
					case 2:
						data1 = 12 & *(UBYTE *)adr11;
						data2 = 12 & *(UBYTE *)adr12;
						break;
					case 3:
						data1 = 3 & *(UBYTE *)adr11;
						data2 = 3 & *(UBYTE *)adr12;
				}

				if (pos_modulo2 < pos_modulo1) {
				data1 <<= (2*(pos_modulo1 - pos_modulo2));
				data2 <<= (2*(pos_modulo1 - pos_modulo2));
				} else { 
					if (pos_modulo2 > pos_modulo1) {
						data1 >>= (2*(pos_modulo2 - pos_modulo1));
						data2 >>= (2*(pos_modulo2 - pos_modulo1));
					}
				}
				*(UBYTE *)adr21 |= data1;
				*(UBYTE *)adr22 |= data2;
				adr11 = (ULONG)gfxdatasmallbm.Planes[2]+tmp1;
					
				adr21 = (ULONG)AmigaScreen->BitMap.Planes[2]+tmp2;
		
				adr12 = adr11+tmp3;
				adr22 = adr21+tmp4; 
				
				pos_modulo1 = tmp5;
				pos_modulo2 = tmp6;
	
				switch(pos_modulo1) {
					case 0:
						data1 = 192 & *(UBYTE *)adr11;
						data2 = 192 & *(UBYTE *)adr12;
						break;
					case 1:
						data1 = 48 & *(UBYTE *)adr11;
						data2 = 48 & *(UBYTE *)adr12;
						break;
					case 2:
						data1 = 12 & *(UBYTE *)adr11;
						data2 = 12 & *(UBYTE *)adr12;
						break;
					case 3:
						data1 = 3 & *(UBYTE *)adr11;
						data2 = 3 & *(UBYTE *)adr12;
				}

				if (pos_modulo2 < pos_modulo1) {
				data1 <<= (2*(pos_modulo1 - pos_modulo2));
				data2 <<= (2*(pos_modulo1 - pos_modulo2));
				} else { 
					if (pos_modulo2 > pos_modulo1) {
						data1 >>= (2*(pos_modulo2 - pos_modulo1));
						data2 >>= (2*(pos_modulo2 - pos_modulo1));
					}
				}
				*(UBYTE *)adr21 |= data1;
				*(UBYTE *)adr22 |= data2;

				adr11 = (ULONG)gfxdatasmallbm.Planes[3]+tmp1;
					
				adr21 = (ULONG)AmigaScreen->BitMap.Planes[3]+tmp2;
		
				adr12 = adr11+tmp3;
				adr22 = adr21+tmp4; 
				
				pos_modulo1 = tmp5;
				pos_modulo2 = tmp6;
	
				switch(pos_modulo1) {
					case 0:
						data1 = 192 & *(UBYTE *)adr11;
						data2 = 192 & *(UBYTE *)adr12;
						break;
					case 1:
						data1 = 48 & *(UBYTE *)adr11;
						data2 = 48 & *(UBYTE *)adr12;
						break;
					case 2:
						data1 = 12 & *(UBYTE *)adr11;
						data2 = 12 & *(UBYTE *)adr12;
						break;
					case 3:
						data1 = 3 & *(UBYTE *)adr11;
						data2 = 3 & *(UBYTE *)adr12;
				}
				if (pos_modulo2 < pos_modulo1) {
				data1 <<= (2*(pos_modulo1 - pos_modulo2));
				data2 <<= (2*(pos_modulo1 - pos_modulo2));
				} else { 
					if (pos_modulo2 > pos_modulo1) {
						data1 >>= (2*(pos_modulo2 - pos_modulo1));
						data2 >>= (2*(pos_modulo2 - pos_modulo1));
					}
				}
				*(UBYTE *)adr21 |= data1;
				*(UBYTE *)adr22 |= data2;
			}
		}
	}
}

sleep(secs)
int secs;
{
	if (secs) {
		sendtimer(secs*1000000);
		waittimer();
	}
}

Delay_Firebolt()
{
	WaitTOF();
//	sendtimer(1);
//	waittimer();
}


UBYTE *
convert_menunum_to_str(int menunum, int itemnum) 
{
	static UBYTE buf[10];
	switch(menunum) {
		case 0: // project menu
			switch(itemnum) {
				case 0: // first menu item
					if (!rogue_like_commands)
						return "C";
					else 
						return "C";
				case 1:
					if (!rogue_like_commands)
						return "V";
					else 
						return "V";
				case 2:
					if (!rogue_like_commands)
						return "=";
					else 
						return "=";
				case 3:
					if (!rogue_like_commands)
						return "?";
					else 
						return "?";
				case 4:
					if (!rogue_like_commands) {
						buf[0] = CTRL('P');
						buf[1] = '\0';
						return buf;
					} else { 
						buf[0] = CTRL('P');
						buf[1] = '\0';
						return buf;
					}
				case 5:
					if (!rogue_like_commands)
						return "g";
					else 
						return "g";
				case 6:
					if (!rogue_like_commands)
						return "`";
					else 
						return "`";
				case 7:
					if (!rogue_like_commands)
						return "#";
					else 
						return "0";
				case 8:
					if (!rogue_like_commands)
						return "v";
					else 
						return "v";
				case 9:
					if (!rogue_like_commands) {
						buf[0] = CTRL('X');
						buf[1] = '\0';
						return buf;
					} else { 
						buf[0] = CTRL('X');
						buf[1] = '\0';
						return buf;
					}
				case 10:
					if (!rogue_like_commands) {
						buf[0] = CTRL('K');
						buf[1] = '\0';
						return buf;
					} else 
						return "Q";
			}
		case 1: // fight menu
			switch(itemnum) {
				case 0:
					if (!rogue_like_commands)
						return "f";
					else 
						return "t";
				case 1:
					if (!rogue_like_commands)
						return "a";
					else 
						return "z";
				case 2:
					if (!rogue_like_commands)
						return "u";
					else 
						return "Z";
				case 3:
					if (!rogue_like_commands)
						return "m";
					else 
						return "m";
				case 4:
					if (!rogue_like_commands)
						return "p";
					else 
						return "p";
				case 5:
					if (!rogue_like_commands)
						return "r";
					else 
						return "r";
				case 6:
					if (!rogue_like_commands)
						return "B";
					else 
						return "f";
				case 7:
					if (!rogue_like_commands)
						return "~";
					else 
						return "~";
			}
		case 2: // info menu
			switch(itemnum) {
				case 0:
					if (!rogue_like_commands)
						return "b";
					else 
						return "P";
				case 1:
					if (!rogue_like_commands)
						return "o";
					else 
						return "o";
				case 2:
					if (!rogue_like_commands)
						return "s";
					else 
						return "s";
				case 3:
					if (!rogue_like_commands)
						return "S";
					else 
						return "#";
				case 4:
					if (!rogue_like_commands)
						return "/";
					else 
						return "/";
				case 5:
					if (!rogue_like_commands)
						return "L";
					else 
						return "W";
				case 6:
					if (!rogue_like_commands)
						return "l";
					else 
						return "x";
				case 7:
					if (!rogue_like_commands)
						return "M";
					else 
						return "M";
				case 8:
					if (!rogue_like_commands)
						return ",";
					else 
						return ",";
			}
		case 3: // action menu
			switch(itemnum) {
				case 0:
					if (!rogue_like_commands)
						return "c";
					else 
						return "c";
				case 1:
					if (!rogue_like_commands)
						return "j";
					else 
						return "S";
				case 2:
					if (!rogue_like_commands)
						return "B";
					else 
						return "f";
				case 3:
					if (!rogue_like_commands)
						return "q";
					else 
						return "q";
				case 4:
					if (!rogue_like_commands)
						return "E";
					else 
						return "E";
				case 5:
					if (!rogue_like_commands)
						return "r";
					else 
						return "r";
				case 6:
					if (!rogue_like_commands)
						return "G";
					else 
						return "G";
				case 7:
					if (!rogue_like_commands)
						return "a";
					else 
						return "z";
				case 8:
					if (!rogue_like_commands)
						return "u";
					else 
						return "Z";
				case 9:
					if (!rogue_like_commands)
						return "D";
					else 
						return "D";
				case 10:
					if (!rogue_like_commands)
						return "F";
					else 
						return "F";
				case 11:
					if (!rogue_like_commands)
						return "T";
					else 
						return "~";
				case 12:
					if (!rogue_like_commands)
						return "{";
					else 
						return "{";
				case 13:
					if (!rogue_like_commands)
						return "R";
					else 
						return "R";
				case 14:
					if (!rogue_like_commands)
						return "R*\n";
					else 
						return "R*\n";
			}
		case 4: // inventory menu
			switch(itemnum) {
				case 0:
					if (!rogue_like_commands)
						return "i";
					else 
						return "i";
				case 1:
					if (!rogue_like_commands)
						return "e";
					else 
						return "e";
				case 2:
					if (!rogue_like_commands)
						return "w";
					else 
						return "w";
				case 3:
					if (!rogue_like_commands)
						return "d";
					else 
						return "d";
				case 4:
					if (!rogue_like_commands)
						return "t";
					else 
						return "T";
				case 5:
					if (!rogue_like_commands)
						return "x";
					else 
						return "X";
			}
		case 5: // move menu
			switch(itemnum) {
				case 0:
					if (!rogue_like_commands)
						return "<";
					else 
						return "<";
				case 1:
					if (!rogue_like_commands)
						return ">";
					else 
						return ">";
				case 2:
					if (!rogue_like_commands)
						return "-";
					else 
						return "-";
				case 3:
					if (!rogue_like_commands)
						return ".";
					else 
						return "~";
				case 4:
					if (!rogue_like_commands)
						return "(";
					else 
						return "(";
				case 5:
					if (!rogue_like_commands)
						return "1";
					else 
						return "b";
				case 6:
					if (!rogue_like_commands)
						return "2";
					else 
						return "j";
				case 7:
					if (!rogue_like_commands)
						return "3";
					else 
						return "n";
				case 8:
					if (!rogue_like_commands)
						return "4";
					else 
						return "h";
				case 9:
					if (!rogue_like_commands)
						return "5";
					else 
						return ".";
				case 10:
					if (!rogue_like_commands)
						return "6";
					else 
						return "l";
				case 11:
					if (!rogue_like_commands)
						return "7";
					else 
						return "y";
				case 12:
					if (!rogue_like_commands)
						return "8";
					else 
						return "k";
				case 13:
					if (!rogue_like_commands)
						return "9";
					else 
						return "u";
			}
	}
}

amiga_bell() {
//	DisplayBeep(AmigaScreen);
}
