/*    SCCS Id: @(#)winfuncs.c    3.1    2000/01/12 */
/* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993,1996. */
/* NetHack may be freely redistributed.  See license for details. */

#include "NH:sys/amiga/windefs.h"
#include "NH:sys/amiga/winext.h"
#include "NH:sys/amiga/winproto.h"
#include "patchlevel.h"

extern struct TagItem scrntags[];

static BitMapHeader amii_bmhd;
static void cursor_common(struct RastPort *, int, int);

#ifdef	CLIPPING
int CO, LI;

/* Changing clipping region, skip clear of screen in overview window. */
int reclip;

/* Must be set to at least two or you will get stuck! */
int xclipbord = 4, yclipbord = 2;
#endif

int mxsize, mysize;
struct Rectangle amii_oldover;
struct Rectangle amii_oldmsg;

int amii_msgAPen;
int amii_msgBPen;
int amii_statAPen;
int amii_statBPen;
int amii_menuAPen;
int amii_menuBPen;
int amii_textAPen;
int amii_textBPen;
int amii_otherAPen;
int amii_otherBPen;
long amii_libvers = LIBRARY_FONT_VERSION;

void
ami_wininit_data( void )
{
    extern unsigned short amii_init_map[ AMII_MAXCOLORS ];
    extern unsigned short amiv_init_map[ AMII_MAXCOLORS ];
    if( !WINVERS_AMIV )
    {
# ifdef	TEXTCOLOR
	amii_numcolors = 8;
# else
	amii_numcolors = 4;
# endif
	amii_defpens[ 0 ] = C_BLACK;	/* DETAILPEN        */
	amii_defpens[ 1 ] = C_BLUE; 	/* BLOCKPEN         */
	amii_defpens[ 2 ] = C_BROWN;	/* TEXTPEN          */
	amii_defpens[ 3 ] = C_WHITE;	/* SHINEPEN         */
	amii_defpens[ 4 ] = C_BLUE;	/* SHADOWPEN        */
	amii_defpens[ 5 ] = C_CYAN;	/* FILLPEN          */
	amii_defpens[ 6 ] = C_WHITE;	/* FILLTEXTPEN      */
	amii_defpens[ 7 ] = C_CYAN;	/* BACKGROUNDPEN    */
	amii_defpens[ 8 ] = C_RED;	/* HIGHLIGHTTEXTPEN */
	amii_defpens[ 9 ] = C_WHITE;	/* BARDETAILPEN     */
	amii_defpens[ 10 ] = C_CYAN;	/* BARBLOCKPEN      */
	amii_defpens[ 11 ] = C_BLUE;	/* BARTRIMPEN       */
	amii_defpens[ 12 ] = (unsigned short) ~0;

	amii_msgAPen = C_WHITE;
	amii_msgBPen = C_BLACK;
	amii_statAPen = C_WHITE;
	amii_statBPen = C_BLACK;
	amii_menuAPen = C_WHITE;
	amii_menuBPen = C_BLACK;
	amii_textAPen = C_WHITE;
	amii_textBPen = C_BLACK;
	amii_otherAPen = C_RED;
	amii_otherBPen = C_BLACK;

	mxsize = 8;
	mysize = 8;

	amii_libvers = LIBRARY_FONT_VERSION;
	memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) );
    }
    else
    {
	mxsize = 16;
	mysize = 16;

	amii_numcolors = 16;

	amii_defpens[ 0 ] = C_BLACK;	/* DETAILPEN        */
	amii_defpens[ 1 ] = C_WHITE;	/* BLOCKPEN         */
	amii_defpens[ 2 ] = C_BLACK;	/* TEXTPEN          */
	amii_defpens[ 3 ] = C_CYAN;	/* SHINEPEN         */
	amii_defpens[ 4 ] = C_BLUE;	/* SHADOWPEN        */
	amii_defpens[ 5 ] = C_GREYBLUE;	/* FILLPEN          */
	amii_defpens[ 6 ] = C_LTGREY;	/* FILLTEXTPEN      */
	amii_defpens[ 7 ] = C_GREYBLUE;	/* BACKGROUNDPEN    */
	amii_defpens[ 8 ] = C_RED;	/* HIGHLIGHTTEXTPEN */
	amii_defpens[ 9 ] = C_WHITE;	/* BARDETAILPEN     */
	amii_defpens[ 10] = C_GREYBLUE;	/* BARBLOCKPEN      */
	amii_defpens[ 11] = C_BLUE;	/* BARTRIMPEN       */
	amii_defpens[ 12] = (unsigned short) ~0;

	amii_msgAPen = C_WHITE;
	amii_msgBPen = C_GREYBLUE;
	amii_statAPen = C_WHITE;
	amii_statBPen = C_GREYBLUE;
	amii_menuAPen = C_BLACK;
	amii_menuBPen = C_LTGREY;
	amii_textAPen = C_BLACK;
	amii_textBPen = C_LTGREY;
	amii_otherAPen = C_RED;
	amii_otherBPen = C_BLACK;
	amii_libvers = LIBRARY_TILE_VERSION;

	memcpy( amii_initmap, amiv_init_map, sizeof( amii_initmap ) );
    }
#ifdef OPT_DISPMAP
    dispmap_sanity();
#endif
    memcpy(flags.amii_dripens,amii_defpens,sizeof(flags.amii_dripens));
}

# ifdef	INTUI_NEW_LOOK
struct Hook fillhook;
struct TagItem wintags[] =
{
	{ WA_BackFill, (ULONG)&fillhook },
	{ TAG_END, 0 },
};
# endif

void
amii_destroy_nhwindow(win)      /* just hide */
    register winid win;
{
    int i;
    int type;
    register struct amii_WinDesc *cw;

    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
    {
	panic(winpanicstr,win,"destroy_nhwindow");
    }

    if( WINVERS_AMIV )
    {
	if( cw->type == NHW_MAP )
	{
	    /* If inventory is up, close it now, it will be freed later */
	    if( alwaysinvent && WIN_INVEN != WIN_ERR &&
				amii_wins[ WIN_INVEN ] &&
				amii_wins[ WIN_INVEN ]->win )
	    {
		dismiss_nhwindow( WIN_INVEN );
	    }

	    /* Tear down overview window if it is up */
	    if( WIN_OVER != WIN_ERR )
	    {
		amii_destroy_nhwindow( WIN_OVER );
		WIN_OVER = WIN_ERR;
	    }
	}
	else if( cw->type == NHW_OVER )
	{
	    struct Window *w = amii_wins[ WIN_OVER ]->win;
	    amii_oldover.MinX = w->LeftEdge;
	    amii_oldover.MinY = w->TopEdge;
	    amii_oldover.MaxX = w->Width;
	    amii_oldover.MaxY = w->Height;

	    if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] )
	    {
		w = amii_wins[ WIN_MESSAGE ]->win;
		amii_oldmsg.MinX = w->LeftEdge;
		amii_oldmsg.MinY = w->TopEdge;
		amii_oldmsg.MaxX = w->Width;
		amii_oldmsg.MaxY = w->Height;
		SizeWindow( amii_wins[ WIN_MESSAGE ]->win,
			(amiIDisplay->xpix -
			amii_wins[ WIN_MESSAGE ]->win->LeftEdge) -
			amii_wins[ WIN_MESSAGE ]->win->Width,
			0 );
	    }
	}
    }

    /* Tear down the Intuition stuff */
    dismiss_nhwindow(win);
    type = cw->type;

    if( cw->resp )    free( cw->resp );
    if( cw->canresp ) free( cw->canresp );
    if( cw->morestr ) free( cw->morestr );
    if( cw->hook ) free( cw->hook );
    cw->hook = NULL;

    if( cw->data && ( cw->type == NHW_MESSAGE ||
			    cw->type == NHW_MENU || cw->type == NHW_TEXT ) )
    {
	for( i = 0; i < cw->maxrow; ++i )
	{
	    if( cw->data[ i ] )
		free( cw->data[ i ] );
	}
	free( cw->data );
    }

    free( cw );
    amii_wins[win] = NULL;

    /* Set globals to WIN_ERR for known one-of-a-kind windows. */
    if( win == WIN_MAP) WIN_MAP = WIN_ERR;
    else if( win == WIN_STATUS) WIN_STATUS = WIN_ERR;
    else if( win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR;
    else if( win == WIN_INVEN) WIN_INVEN = WIN_ERR;

}

#ifdef INTUI_NEW_LOOK
struct FillParams
{
	struct Layer *layer;
	struct Rectangle bounds;
	WORD offsetx;
	WORD offsety;
};

void
#ifndef _DCC
__interrupt
#endif
__saveds __asm
LayerFillHook(
    register __a0 struct Hook *hk,
    register __a2 struct RastPort *rp,
    register __a1 struct FillParams *fp )
{
    register long x, y, xmax, ymax;
    register int apen;
    struct RastPort rptmp;

    memcpy(&rptmp, rp, sizeof(struct RastPort));
    rptmp.Layer = NULL;

    switch( (int)hk->h_Data )
    {
    case NHW_STATUS:
	apen = amii_statBPen;
	break;
    case NHW_MESSAGE:
	apen = amii_msgBPen;
	break;
    case NHW_TEXT:
	apen = amii_textBPen;
	break;
    case NHW_MENU:
	apen = amii_menuBPen;
	break;
    case -2:
	apen = amii_otherBPen;
	break;
    case NHW_BASE:
    case NHW_MAP:
    case NHW_OVER:
    default:
	apen = C_BLACK;
	break;
    }

    x = fp->bounds.MinX;
    y = fp->bounds.MinY;
    xmax = fp->bounds.MaxX;
    ymax = fp->bounds.MaxY;

    SetAPen(&rptmp, apen);
    SetBPen(&rptmp, apen);
    SetDrMd(&rptmp, JAM2);
    RectFill(&rptmp, x, y, xmax, ymax);
}
#endif


amii_create_nhwindow(type)
    register int type;
{
    register struct Window *w = NULL;
    register struct NewWindow *nw = NULL;
    register struct amii_WinDesc *wd = NULL;
    struct Window *mapwin = NULL, *stwin = NULL, *msgwin = NULL;
    register int newid;
    int maph, stath, scrfontysize;

    scrfontysize = HackScreen->Font->ta_YSize;

    /*
     * Initial mapwindow height, this might change later in tilemode
     * and low screen
     */
    maph = ( 21 * mxsize ) + 2 + (bigscreen ?
	HackScreen->WBorTop + HackScreen->WBorBottom + scrfontysize + 1 : 0);

    /* Status window height, avoids having to calculate many times */
    stath = txheight * 2 + 2 + (WINVERS_AMIV || bigscreen ?
	HackScreen->WBorTop + HackScreen->WBorBottom +
	( bigscreen ? scrfontysize + 1 : 0 ) : 0);

    if( WIN_STATUS != WIN_ERR && amii_wins[ WIN_STATUS ] )
	stwin = amii_wins[ WIN_STATUS ]->win;

    if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] )
	msgwin = amii_wins[ WIN_MESSAGE ]->win;

    if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
	mapwin = amii_wins[ WIN_MAP ]->win;

    /* Create Port anytime that we need it */

    if( HackPort == NULL )
    {
	HackPort = CreatePort( NULL, 0 );
	if( !HackPort )
	    panic( "no memory for msg port" );
    }

    nw = &new_wins[ type ].newwin;
    nw->Width = amiIDisplay->xpix;
    nw->Screen = HackScreen;

    if( WINVERS_AMIV )
    {
	nw->DetailPen = C_WHITE;
	nw->BlockPen = C_GREYBLUE;
    }
    else
    {
	nw->DetailPen = C_WHITE;
	nw->BlockPen = C_BLACK;
    }

    if ( type == NHW_BASE ) {
	nw->LeftEdge = 0;
	nw->TopEdge = HackScreen->BarHeight+1;
	nw->Width = HackScreen->Width;
	nw->Height = HackScreen->Height - nw->TopEdge;
    } else if( !WINVERS_AMIV && type == NHW_MAP ) {
	nw->LeftEdge = 0;
	nw->Height = maph;

	if( msgwin && stwin ) {
	    nw->TopEdge = stwin->TopEdge - maph;
	} else {
	    panic( "msgwin and stwin must open before map" );
	}
	if (nw->TopEdge < 0)
	    panic( "Too small screen to fit map" );
    }
    else if( type == NHW_MAP && WINVERS_AMIV )
    {
	struct Window *w;

	w = amii_wins[ WIN_MESSAGE ]->win;
	nw->LeftEdge = 0;
	nw->TopEdge = w->TopEdge + w->Height;
	nw->Width = amiIDisplay->xpix - nw->LeftEdge;

	w = amii_wins[ WIN_STATUS ]->win;
	nw->Height = w->TopEdge - nw->TopEdge;
	nw->MaxHeight = 0xffff;
	nw->MaxWidth = 0xffff;

	if( nw->TopEdge + nw->Height > amiIDisplay->ypix - 1 )
	    nw->Height = amiIDisplay->ypix - nw->TopEdge - 1;
    }
    else if( type == NHW_STATUS )
    {
	if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) )
	    w = amii_wins[ WIN_MAP ]->win;
	else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
	    w = amii_wins[ WIN_BASE ]->win;
	else
	    panic( "No window to base STATUS location from" );

	nw->Height = stath;
	nw->TopEdge = amiIDisplay->ypix - nw->Height;
	nw->LeftEdge = w->LeftEdge;

	if( nw->LeftEdge + nw->Width >= amiIDisplay->xpix )
	    nw->LeftEdge = 0;

	if( nw->Width >= amiIDisplay->xpix - nw->LeftEdge )
	    nw->Width = amiIDisplay->xpix - nw->LeftEdge;
    }
    else if( WINVERS_AMIV && type == NHW_OVER )
    {
	nw->Flags |= WINDOWSIZING|WINDOWDRAG|WINDOWCLOSE;
	nw->IDCMPFlags |= CLOSEWINDOW;
	/* Bring up window as half the width of the message window, and make
	 * the message window change to one half the width...
	 */
	if( amii_oldover.MaxX != 0 )
	{
	    nw->LeftEdge = amii_oldover.MinX;
	    nw->TopEdge = amii_oldover.MinY;
	    nw->Width = amii_oldover.MaxX;
	    nw->Height = amii_oldover.MaxY;
	    ChangeWindowBox( amii_wins[ WIN_MESSAGE ]->win,
			amii_oldmsg.MinX, amii_oldmsg.MinY,
			amii_oldmsg.MaxX, amii_oldmsg.MaxY );
	}
	else
	{
	    nw->LeftEdge = (amii_wins[ WIN_MESSAGE ]->win->Width*4)/9;
	    nw->TopEdge = amii_wins[ WIN_MESSAGE ]->win->TopEdge;
	    nw->Width = amiIDisplay->xpix - nw->LeftEdge;
	    nw->Height = amii_wins[ WIN_MESSAGE ]->win->Height;
	    SizeWindow( amii_wins[ WIN_MESSAGE ]->win,
		    nw->LeftEdge - amii_wins[ WIN_MESSAGE ]->win->Width, 0 );
	}
    }
    else if( type == NHW_MESSAGE )
    {
	if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) )
	    w = amii_wins[ WIN_MAP ]->win;
	else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
	    w = amii_wins[ WIN_BASE ]->win;
	else
	    panic( "No window to base STATUS location from" );

	nw->TopEdge = bigscreen ? HackScreen->BarHeight+1 : 0;

	/* Assume highest possible message window */
	nw->Height = HackScreen->Height - nw->TopEdge - maph - stath;

	/* In tilemode we can cope with this */
	if (WINVERS_AMIV && nw->Height < 0)
	    nw->Height = 0;

	/* If in fontmode messagewindow is too small, open it with 3 lines
	   and overlap it with map */
	if (nw->Height < txheight+2) {
	    nw->Height = txheight*4 + 3 + HackScreen->WBorTop + HackScreen->WBorBottom;
	}

	if ((nw->Height-2)/txheight < 3) {
	    scrollmsg = 0;
	    nw->Title = 0;
	} else {
	    nw->FirstGadget = &MsgScroll;
	    nw->Flags |= WINDOWSIZING|WINDOWDRAG;
	    nw->Flags &= ~BORDERLESS;

	    if( WINVERS_AMIV || nw->Height == 0) {
		if( WINVERS_AMIV ) {
		    nw->Height = TextsFont->tf_YSize + HackScreen->WBorTop + 3 +
				HackScreen->WBorBottom;
		    if( bigscreen )
			nw->Height += ( txheight * 6 );
		    else
			nw->Height += ( txheight * 3 );
		}
		else
		{
		    nw->Height = HackScreen->Height - nw->TopEdge - stath - maph;
		}
	    }
	}

	/* Do we have room for larger message window ?
	 * This is possible if we can show full height map in tile
	 * mode	with default scaling.
	 */
	if (nw->Height + stath + maph < HackScreen->Height - nw->TopEdge )
	    nw->Height = HackScreen->Height - nw->TopEdge - 1 - maph - stath;

#ifdef  INTUI_NEW_LOOK
	if( IntuitionBase->LibNode.lib_Version >= 37 )
	{
	    MsgPropScroll.Flags |= PROPNEWLOOK;
	}
#endif
    }

    nw->IDCMPFlags |= MENUPICK;

    /* Check if there is "Room" for all this stuff... */
    if( ( WINVERS_AMIV || bigscreen ) &&
	type != NHW_BASE )
    {
	nw->Flags &= ~( BORDERLESS | BACKDROP );

	if( WINVERS_AMIV )
	{
	    if( type == NHW_STATUS )
	    {
		nw->Flags &= ~( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING );
		nw->IDCMPFlags &= ~NEWSIZE;
	    }
	    else
	    {
		nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING );
		nw->IDCMPFlags |= NEWSIZE;
	    }
	}
	else
	{
	    if( HackScreen->Width < 657 )
	    {
		nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH );
	    }
	    else
	    {
		nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT );
	    }
	}
    }

    if ( WINVERS_AMII && type == NHW_MAP )
	nw->Flags &= ~WINDOWSIZING;

    if ( type == NHW_MESSAGE && scrollmsg ) {
	nw->Flags |= WINDOWDRAG|WINDOWDEPTH|SIZEBRIGHT|WINDOWSIZING;
	nw->Flags &= ~BORDERLESS;
    }

    /* No titles on a hires only screen except for messagewindow */
    if( !(WINVERS_AMIV && type == NHW_MAP) && !bigscreen && type != NHW_MESSAGE )
	nw->Title = 0;

    wd = (struct amii_WinDesc *)alloc(sizeof(struct amii_WinDesc));
    memset( wd, 0, sizeof( struct amii_WinDesc ) );

    /* Both, since user may have changed the pen settings so respect those */
    if( WINVERS_AMII || WINVERS_AMIV )
    {
	/* Special backfill for these types of layers */
	switch( type )
	{
	case NHW_MESSAGE:
	case NHW_STATUS:
	case NHW_TEXT:
	case NHW_MENU:
	case NHW_BASE:
	case NHW_OVER:
	case NHW_MAP:
	    if( wd )
	    {
		fillhook.h_Entry = (ULONG(*)())LayerFillHook;
		fillhook.h_Data = (void *)type;
		fillhook.h_SubEntry = 0;
		wd->hook = alloc( sizeof( fillhook ) );
		memcpy( wd->hook, &fillhook, sizeof( fillhook ) );
		memcpy( wd->wintags, wintags, sizeof( wd->wintags) );
		wd->wintags[0].ti_Data = (long)wd->hook;
		nw->Extension = (void *)wd->wintags;
	    }
	    break;
	}
    }

    /* Don't open MENU or TEXT windows yet */

    if( type == NHW_MENU || type == NHW_TEXT )
	w = NULL;
    else
	w=OpenShWindow( (void *)nw );

    if( w == NULL && type != NHW_MENU && type != NHW_TEXT )
    {
	char buf[ 100 ];

	sprintf( buf, "nw type (%d) dims l: %d, t: %d, w: %d, h: %d",
		type,
		nw->LeftEdge, nw->TopEdge,
		nw->Width, nw->Height );
	raw_print( buf );
	panic("bad openwin %d",type);
    }

    /* Check for an empty slot */

    for(newid = 0; newid<MAXWIN + 1; newid++)
    {
	if(amii_wins[newid] == 0)
	    break;
    }

    if(newid==MAXWIN+1)
	panic("time to write re-alloc code\n");

    /* Set wincnt accordingly */

    if( newid > wincnt )
	wincnt = newid;

    /* Do common initialization */

    amii_wins[newid] = wd;

    wd->newwin = NULL;
    wd->win = w;
    wd->type = type;
    wd->wflags = 0;
    wd->active = FALSE;
    wd->curx=wd->cury = 0;
    wd->resp = wd->canresp = wd->morestr = 0;   /* CHECK THESE */
    wd->maxrow = new_wins[type].maxrow;
    wd->maxcol = new_wins[type].maxcol;

    if( type != NHW_TEXT && type != NHW_MENU )
    {
	if( TextsFont && ( type == NHW_MESSAGE || type == NHW_STATUS ) )
	{
	    SetFont(w->RPort, TextsFont);
	    txheight = w->RPort->TxHeight;
	    txwidth = w->RPort->TxWidth;
	    txbaseline = w->RPort->TxBaseline;
	    if( type == NHW_MESSAGE )
	    {
		if (scrollmsg )
		{
		    if( WINVERS_AMIV )
		    {
			WindowLimits( w, 100, w->BorderTop +
				w->BorderBottom +
				((txheight+1)*2) + 1, 0, 0 );
		    }
		    else
		    {
			WindowLimits( w, w->Width, w->BorderTop +
				w->BorderBottom +
				((txheight+1)*2) + 1, 0, 0 );
		    }
		}
		else
		{
		    WindowLimits( w, w->Width, w->BorderTop +
				w->BorderBottom +
				txheight + 2, 0, 0 );
		}
	    }
	}
#ifdef HACKFONT
	else if( HackFont )
	    SetFont(w->RPort, HackFont);
#endif
    }

    /* Text and menu windows are not opened yet */
    if( w )
    {
	wd->rows = ( w->Height - w->BorderTop -
	    w->BorderBottom - 2 ) / w->RPort->TxHeight;
	wd->cols = ( w->Width - w->BorderLeft -
	    w->BorderRight - 2 ) / w->RPort->TxWidth;
    }

    /* Okay, now do the individual type initialization */

    switch(type)
    {
	/* History lines for MESSAGE windows are stored in cw->data[?].
	 * maxcol and maxrow are used as cursors.  maxrow is the count
	 * of the number of history lines stored.  maxcol is the cursor
	 * to the last line that was displayed by ^P.
	 */
	case NHW_MESSAGE:
	    SetMenuStrip(w, MenuStrip);
	    iflags.msg_history = wd->rows*10;
	    if (iflags.msg_history < 40)
		iflags.msg_history = 40;
	    if (iflags.msg_history > 400)
		iflags.msg_history = 400;
	    iflags.window_inited=TRUE;
	    wd->data = (char **)alloc( iflags.msg_history*sizeof( char * ) );
	    memset( wd->data, 0, iflags.msg_history * sizeof( char * ) );
	    wd->maxrow = wd->maxcol = 0;
	    /* Indicate that we have not positioned the cursor yet */
	    wd->curx = -1;
	    break;

	    /* A MENU contains a list of lines in wd->data[?].  These
	     * lines are created in amii_putstr() by reallocating the size
	     * of wd->data to hold enough (char *)'s.  wd->rows is the
	     * number of (char *)'s allocated.  wd->maxrow is the number
	     * used.  wd->maxcol is used to track how wide the menu needs
	     * to be.  wd->resp[x] contains the characters that correspond
	     * to selecting wd->data[x].  wd->resp[x] corresponds to
	     * wd->data[x] for any x. Elements of wd->data[?] that are not
	     * valid selections have the corresponding element of
	     * wd->resp[] set to a value of '\01';  i.e. a ^A which is
	     * not currently a valid keystroke for responding to any
	     * MENU or TEXT window.
	     */
	case NHW_MENU:
	    wd->resp=(char*)alloc(256);
	    wd->resp[0]=0;
	    wd->rows = wd->maxrow = 0;
	    wd->cols = wd->maxcol = 0;
	    wd->data = NULL;
	    break;

	    /* See the explanation of MENU above.  Except, wd->resp[] is not
	     * used for TEXT windows since there is no selection of a
	     * a line performed/allowed.  The window is always full
	     * screen width.
	     */
	case NHW_TEXT:
	    wd->rows = wd->maxrow = 0;
	    wd->cols = wd->maxcol = amiIDisplay->cols;
	    wd->data = NULL;
	    wd->morestr = NULL;
	    break;

	    /* The status window has only two lines.  These are stored in
	     * wd->data[], and here we allocate the space for them.
	     */
	case NHW_STATUS:
	    SetMenuStrip(w, MenuStrip);
	    /* wd->cols is the number of characters which fit across the
	     * screen.
	     */
	    wd->data=(char **)alloc(3*sizeof(char *));
	    wd->data[0] = (char *)alloc(wd->cols + 10);
	    wd->data[1] = (char *)alloc(wd->cols + 10);
	    wd->data[2] = NULL;
	    break;

	    /* NHW_OVER does not use wd->data[] or the other text
	     * manipulating members of the amii_WinDesc structure.
	     */
	case NHW_OVER:
	    SetMenuStrip(w, MenuStrip);
	    break;

	    /* NHW_MAP does not use wd->data[] or the other text
	     * manipulating members of the amii_WinDesc structure.
	     */
	case NHW_MAP:
	    SetMenuStrip(w, MenuStrip);
	    if( WINVERS_AMIV )
	    {
		extern struct TextFont *RogueFont;
		CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
		LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
		amii_setclipped();
		SetFont( w->RPort, RogueFont);
		SetAPen( w->RPort, C_WHITE);	/* XXX not sufficient */
		SetBPen( w->RPort, C_BLACK);
		SetDrMd( w->RPort, JAM2);
	    }
	    else
	    {
		if( HackFont )
		    SetFont( w->RPort, HackFont );
	    }
	    break;

	    /* The base window must exist until CleanUp() deletes it. */
	case NHW_BASE:
	    SetMenuStrip(w, MenuStrip);
	    /* Make our requesters come to our screen */
	    {
		register struct Process *myProcess =
					(struct Process *) FindTask(NULL);
		pr_WindowPtr = (struct Window *)(myProcess->pr_WindowPtr);
		myProcess->pr_WindowPtr = (APTR) w;
	    }

	    /* Need this for RawKeyConvert() */

	    ConsoleIO.io_Data = (APTR) w;
	    ConsoleIO.io_Length = sizeof( struct Window );
	    ConsoleIO.io_Message.mn_ReplyPort = CreatePort(NULL, 0L);
	    if( OpenDevice("console.device", -1L,
				(struct IORequest *) &ConsoleIO, 0L) != 0)
	    {
		Abort(AG_OpenDev | AO_ConsoleDev);
	    }

	    ConsoleDevice = (struct Library *) ConsoleIO.io_Device;

	    KbdBuffered = 0;

#ifdef HACKFONT
	    if( TextsFont )
		SetFont( w->RPort, TextsFont );
	    else if( HackFont )
		SetFont( w->RPort, HackFont );
#endif
	    txwidth = w->RPort->TxWidth;
	    txheight = w->RPort->TxHeight;
	    txbaseline = w->RPort->TxBaseline;
	    break;

	default:
	    panic("bad create_nhwindow( %d )\n",type);
	    return WIN_ERR;
    }

    return( newid );
}

/* Initialize the windowing environment */

void
amii_init_nhwindows(argcp,argv)
    int *argcp;
    char **argv;
{
    int i;
    struct Screen *wbscr;
    int forcenobig = 0;

    if( HackScreen )
	panic( "init_nhwindows() called twice", 0 );

	/* run args & set bigscreen from -L(1)/-l(-1) */
    {
	int lclargc = *argcp;
	int t;
	char **argv_in = argv;
	char **argv_out = argv;

	for(t=1;t<=lclargc;t++){
	    if(!strcmp("-L",*argv_in) || !strcmp("-l",*argv_in)){
		bigscreen = (*argv_in[1]=='l') ? -1 : 1;
		/* and eat the flag */
		(*argcp)--;
	    } else {
		*argv_out = *argv_in;	/* keep the flag */
		argv_out++;
	    }
	    argv_in++;
	}
	*argv_out = 0;
    }

    WIN_MESSAGE = WIN_ERR;
    WIN_MAP = WIN_ERR;
    WIN_STATUS = WIN_ERR;
    WIN_INVEN = WIN_ERR;
    WIN_BASE = WIN_ERR;
    WIN_OVER = WIN_ERR;

    if ( (IntuitionBase = (struct IntuitionBase *)
	  OpenLibrary("intuition.library", amii_libvers )) == NULL)
    {
	Abort(AG_OpenLib | AO_Intuition);
    }

    if ( (GfxBase = (struct GfxBase *)
	      OpenLibrary("graphics.library", amii_libvers )) == NULL)
    {
	Abort(AG_OpenLib | AO_GraphicsLib);
    }

    if( WINVERS_AMIV && (LayersBase = (struct Library *)
		OpenLibrary("layers.library", amii_libvers )) == NULL)
    {
	Abort(AG_OpenLib | AO_LayersLib);
    }

    amiIDisplay=(struct amii_DisplayDesc *)alloc(sizeof(struct amii_DisplayDesc));
    memset( amiIDisplay, 0, sizeof( struct amii_DisplayDesc ) );

    /* Use Intuition sizes for overscan screens... */

    amiIDisplay->xpix = 0;
#ifdef	INTUI_NEW_LOOK
    if( IntuitionBase->LibNode.lib_Version >= 37 )
    {
	if( wbscr = LockPubScreen( "Workbench" ) )
	{
	    amiIDisplay->xpix = wbscr->Width;
	    amiIDisplay->ypix = wbscr->Height;
	    UnlockPubScreen( NULL, wbscr );
	}
    }
#endif
    if( amiIDisplay->xpix == 0 )
    {
	amiIDisplay->ypix = GfxBase->NormalDisplayRows;
	amiIDisplay->xpix = GfxBase->NormalDisplayColumns;
    }

    amiIDisplay->cols = amiIDisplay->xpix / FONTWIDTH;

    amiIDisplay->toplin=0;
    amiIDisplay->rawprint=0;
    amiIDisplay->lastwin=0;

    if( bigscreen == 0 )
    {
	if( ( GfxBase->ActiView->ViewPort->Modes & LACE ) == LACE )
	{
	    amiIDisplay->ypix *= 2;
	    NewHackScreen.ViewModes |= LACE;
	    bigscreen = 1;
	}
	else if( GfxBase->NormalDisplayRows >= 300 )
	{
	    bigscreen = 1;
	}
    }
    else if( bigscreen == -1 )
    {
	bigscreen = 0;
	forcenobig = 1;
    }
    else if( bigscreen )
    {
	/* If bigscreen requested and we don't have enough rows in
	 * noninterlaced mode, switch to interlaced...
	 */
	if( GfxBase->NormalDisplayRows < 300 )
	{
	    amiIDisplay->ypix *= 2;
	    NewHackScreen.ViewModes |= LACE;
	}
    }

    if( !bigscreen )
    {
    	alwaysinvent = 0;
    }
    amiIDisplay->rows = amiIDisplay->ypix / FONTHEIGHT;

#ifdef HACKFONT
    /*
     *  Load the fonts that we need.
     */

    if( DiskfontBase =
		OpenLibrary( "diskfont.library", amii_libvers  ) )
    {
	Hack80.ta_Name -= SIZEOF_DISKNAME;
	HackFont = OpenDiskFont( &Hack80 );
	Hack80.ta_Name += SIZEOF_DISKNAME;

	/* Textsfont13 is filled in with "FONT=" settings. The default is
	 * courier/13.
	 */
	TextsFont = NULL;
	if( bigscreen )
	    TextsFont = OpenDiskFont( &TextsFont13 );

	/* Try hack/8 for texts if no user specified font */
	if( TextsFont == NULL )
	{
	    Hack80.ta_Name -= SIZEOF_DISKNAME;
	    TextsFont = OpenDiskFont( &Hack80 );
	    Hack80.ta_Name += SIZEOF_DISKNAME;
	}

	/* If no fonts, make everything topaz 8 for non-view windows.
	 */
	Hack80.ta_Name = "topaz.font";
	RogueFont = OpenFont( &Hack80 );
	if(!RogueFont) panic("Can't get topaz:8");
	if( !HackFont || !TextsFont )
	{
	    if( !HackFont )
	    {
		HackFont = OpenFont( &Hack80 );
		if( !HackFont )
		    panic( "Can't get a map font, topaz:8" );
	    }

	    if( !TextsFont )
	    {
		TextsFont = OpenFont( &Hack80 );
		if( !TextsFont )
		    panic( "Can't open text font" );
	    }
	}
	CloseLibrary(DiskfontBase);
	DiskfontBase = NULL;
    }
#endif

    /* This is the size screen we want to open, within reason... */

    NewHackScreen.Width = max( WIDTH, amiIDisplay->xpix );
    NewHackScreen.Height = max( SCREENHEIGHT, amiIDisplay->ypix );
    {
	static char fname[18];
	sprintf(fname,"NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
	NewHackScreen.DefaultTitle=fname;
    }
#if 0
    NewHackScreen.BlockPen = C_BLACK;
    NewHackScreen.DetailPen = C_WHITE;
#endif
#ifdef	INTUI_NEW_LOOK
    if( IntuitionBase->LibNode.lib_Version >= 37 )
    {
    	int i;
	struct DimensionInfo dims;
	DisplayInfoHandle handle;
	struct DisplayInfo disp;
	ULONG modeid = DEFAULT_MONITOR_ID|HIRES_KEY;

	NewHackScreen.Width = STDSCREENWIDTH;
	NewHackScreen.Height = STDSCREENHEIGHT;

	if( forcenobig == 0 )
	{
	    if( ( wbscr = LockPubScreen( "Workbench" ) ) != NULL ||
		( wbscr = LockPubScreen( NULL ) ) != NULL )
	    {
		/* Get the default pub screen's size */
		modeid = GetVPModeID( &wbscr->ViewPort );
		if( modeid == INVALID_ID ||
		    ModeNotAvailable( modeid ) ||
		    ( handle = FindDisplayInfo( modeid ) ) == NULL ||
		    GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ),
			DTAG_DIMS, modeid ) <= 0 ||
		    GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ),
			DTAG_DISP, modeid ) <= 0 )
		{
		    modeid = DEFAULT_MONITOR_ID|HIRES_KEY;
		    /* If the display database seems to not work, use the screen
		     * dimensions
		     */
		    NewHackScreen.Height = wbscr->Height;
		    NewHackScreen.Width = wbscr->Width;
		
		    /*
		     * Request LACE if it looks laced.  For 2.1/3.0, we will get
		     * promoted to the users choice of modes (if promotion is allowed)
		     * If the user is using a dragable screen, things will get hosed
		     * but that is life...
		     */
		    if( wbscr->ViewPort.Modes & LACE )
			NewHackScreen.ViewModes |= LACE;
		    modeid = -1;
		}
		else
		{
		    /* Use the display database to get the correct information */
		    if( disp.PropertyFlags & DIPF_IS_LACE )
			NewHackScreen.ViewModes |= LACE;
		    NewHackScreen.Height = dims.StdOScan.MaxY;
		    NewHackScreen.Width = dims.StdOScan.MaxX;
		}
		NewHackScreen.TopEdge = 0;
		NewHackScreen.LeftEdge = 0;

		UnlockPubScreen( NULL, wbscr );
	    }
	}

	for( i = 0; scrntags[i].ti_Tag != TAG_DONE; ++i )
	{
	    switch( scrntags[i].ti_Tag )
	    {
		case SA_DisplayID:
		    if( !amii_scrnmode || ModeNotAvailable( amii_scrnmode ) )
		    {
			if( ModeNotAvailable( modeid ) )
			{
			    scrntags[i].ti_Tag = TAG_IGNORE;
			    break;
			}
			else
			    scrntags[i].ti_Data = (long)modeid;
		    }
		    else
			modeid = scrntags[i].ti_Data = (long)amii_scrnmode;
		    if( ( handle = FindDisplayInfo( modeid ) ) != NULL &&
			GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ),
			    DTAG_DIMS, modeid ) > 0 &&
			GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ),
			    DTAG_DISP, modeid ) > 0 )
		    {
			if( disp.PropertyFlags & DIPF_IS_LACE )
			    NewHackScreen.ViewModes |= LACE;
			NewHackScreen.Height = dims.StdOScan.MaxY;
			NewHackScreen.Width = dims.StdOScan.MaxX;
		    }
		    break;

		case SA_Pens:
		    scrntags[i].ti_Data = (long)flags.amii_dripens;
		    break;
	    }
	}
    }
#endif

    if( WINVERS_AMIV )
	amii_bmhd = ReadTileImageFiles( );
    else
	memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) );
    memcpy(flags.amii_curmap,amii_initmap,sizeof(flags.amii_curmap));

    /* Find out how deep the screen needs to be, 32 planes is enough! */
    for( i = 0; i < 32; ++i )
    {
	if( ( 1L << i ) >= amii_numcolors )
	    break;
    }

    NewHackScreen.Depth = i;

    /* If for some reason Height/Width became smaller than the required,
	have the required one */
    if (NewHackScreen.Height < SCREENHEIGHT)
	NewHackScreen.Height = SCREENHEIGHT;
    if (NewHackScreen.Width < WIDTH)
	NewHackScreen.Width = WIDTH;
#ifdef HACKFONT
    i = max(TextsFont->tf_XSize, HackFont->tf_XSize);
    if (NewHackScreen.Width < 80*i+4)
	NewHackScreen.Width = 80*i+4;
#endif

    /* While openscreen fails try fewer colors to see if that is the problem. */
    while( ( HackScreen = OpenScreen( (void *)&NewHackScreen ) ) == NULL )
    {
#ifdef	TEXTCOLOR
	if( --NewHackScreen.Depth < 3 )
#else
	if( --NewHackScreen.Depth < 2 )
#endif
	    Abort( AN_OpenScreen & ~AT_DeadEnd );
    }
    amii_numcolors = 1L << NewHackScreen.Depth;
    if( HackScreen->Height > 300 && forcenobig == 0 )
	bigscreen = 1;
    else
	bigscreen = 0;

#ifdef  INTUI_NEW_LOOK
    if( IntuitionBase->LibNode.lib_Version >= 37 )
	PubScreenStatus( HackScreen, 0 );
#endif

    amiIDisplay->ypix = HackScreen->Height;
    amiIDisplay->xpix = HackScreen->Width;

    LoadRGB4(&HackScreen->ViewPort, flags.amii_curmap, amii_numcolors );

    VisualInfo = GetVisualInfo(HackScreen, TAG_END);
    MenuStrip = CreateMenus(GTHackMenu, TAG_END);
    LayoutMenus(MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END);

    /* Display the copyright etc... */

    if( WIN_BASE == WIN_ERR )
	WIN_BASE = amii_create_nhwindow( NHW_BASE );
    amii_clear_nhwindow( WIN_BASE );
    amii_putstr( WIN_BASE, 0, "" );
    amii_putstr( WIN_BASE, 0, "" );
    amii_putstr( WIN_BASE, 0, "" );
    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_A);
    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_B);
    amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_C);
    amii_putstr( WIN_BASE, 0, "");

    Initialized = 1;
}

void
amii_sethipens( struct Window *w, int type, int attr )
{
    switch( type )
    {
	default:
	    SetAPen( w->RPort, attr ? C_RED : amii_otherAPen );
	    SetBPen( w->RPort, C_BLACK );
	    break;
	case NHW_STATUS:
	    SetAPen( w->RPort, attr ? C_WHITE : amii_statAPen );
	    SetBPen( w->RPort, amii_statBPen );
	    break;
	case NHW_MESSAGE:
	    SetAPen( w->RPort, attr ? C_WHITE : amii_msgAPen );
	    SetBPen( w->RPort, amii_msgBPen );
	    break;
	case NHW_MENU:
	    SetAPen( w->RPort, attr ? C_BLACK : amii_menuAPen );
	    SetBPen( w->RPort, amii_menuBPen );
	    break;
	case NHW_TEXT:
	    SetAPen( w->RPort, attr ? C_BLACK : amii_textAPen );
	    SetBPen( w->RPort, amii_textBPen );
	case -2:
	    SetBPen( w->RPort, amii_otherBPen );
	    SetAPen( w->RPort, attr ? C_RED : amii_otherAPen );
	    break;
    }
}

void
amii_setfillpens( struct Window *w, int type )
{
    switch( type )
    {
    case NHW_MESSAGE:
	SetAPen( w->RPort, amii_msgBPen );
	SetBPen( w->RPort, amii_msgBPen );
	break;
    case NHW_STATUS:
	SetAPen( w->RPort, amii_statBPen );
	SetBPen( w->RPort, amii_statBPen );
	break;
    case NHW_MENU:
	SetAPen( w->RPort, amii_menuBPen );
	SetBPen( w->RPort, amii_menuBPen );
	break;
    case NHW_TEXT:
	SetAPen( w->RPort, amii_textBPen );
	SetBPen( w->RPort, amii_textBPen );
	break;
    case NHW_MAP:
    case NHW_BASE:
    case NHW_OVER:
    default:
	SetAPen( w->RPort, C_BLACK );
	SetBPen( w->RPort, C_BLACK );
	break;
    case -2:
	SetAPen( w->RPort, amii_otherBPen );
	SetBPen( w->RPort, amii_otherBPen );
	break;
    }
}

void
amii_setdrawpens( struct Window *w, int type )
{
    switch( type )
    {
    case NHW_MESSAGE:
	SetAPen( w->RPort, amii_msgAPen );
	SetBPen( w->RPort, amii_msgBPen );
	break;
    case NHW_STATUS:
	SetAPen( w->RPort, amii_statAPen );
	SetBPen( w->RPort, amii_statBPen );
	break;
    case NHW_MENU:
	SetAPen( w->RPort, amii_menuAPen );
	SetBPen( w->RPort, amii_menuBPen );
	break;
    case NHW_TEXT:
	SetAPen( w->RPort, amii_textAPen );
	SetBPen( w->RPort, amii_textBPen );
	break;
    case NHW_MAP:
    case NHW_BASE:
    case NHW_OVER:
	SetAPen( w->RPort, C_WHITE );
	SetBPen( w->RPort, C_BLACK );
	break;
    default:
	SetAPen( w->RPort, amii_otherAPen );
	SetBPen( w->RPort, amii_otherBPen );
	break;
    }
}

/* Clear the indicated window */

void
amii_clear_nhwindow(win)
    register winid win;
{
    register struct amii_WinDesc *cw;
    register struct Window *w;

    if( reclip == 2 ) return;

    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
	panic( winpanicstr, win, "clear_nhwindow" );

    /* Clear the overview window too if it is displayed */
    if( WINVERS_AMIV && ( cw->type == WIN_MAP && WIN_OVER != WIN_ERR && reclip == 0 ) )
    {
	amii_clear_nhwindow( WIN_OVER );
    }

    if( w = cw->win )
	SetDrMd( w->RPort, JAM2);
    else
        return;

    if( (cw->wflags & FLMAP_CURSUP ) )
    {
	if( cw->type != NHW_MAP )
	    cursor_off( win );
	else
	    cw->wflags &= ~FLMAP_CURSUP;
    }

    amii_setfillpens( w, cw->type );
    SetDrMd( w->RPort, JAM2 );

    if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
    {
	RectFill( w->RPort, w->BorderLeft, w->BorderTop,
	  w->Width - w->BorderRight-1,
	  w->Height - w->BorderBottom-1 );
    }
    else
    {
	if( cw->type == NHW_MESSAGE )
	{
	    amii_curs( win, 1, 0 );
	    if( !scrollmsg )
		TextSpaces( w->RPort, cw->cols );
	}
	else
	{
	    RectFill( w->RPort, w->BorderLeft, w->BorderTop,
	      w->Width - w->BorderRight-1,
	      w->Height - w->BorderBottom-1 );
	}
    }

    cw->cury = 0;
    cw->curx = 0;
    amii_curs( win, 1, 0 );
}

/* Dismiss the window from the screen */

void
dismiss_nhwindow(win)
    register winid win;
{
    register struct Window *w;
    register struct amii_WinDesc *cw;

    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
    {
	panic(winpanicstr,win, "dismiss_nhwindow");
    }

    w = cw->win;

    if( w )
    {
	/* All windows have this stuff attached to them. */
	if(	cw->type == NHW_MAP ||
		cw->type == NHW_OVER ||
		cw->type == NHW_BASE ||
		cw->type == NHW_MESSAGE ||
		cw->type == NHW_STATUS )
	{
	    ClearMenuStrip( w );
	}

	/* Save where user like inventory to appear */
	if( win == WIN_INVEN )
	{
	    lastinvent.MinX = w->LeftEdge;
	    lastinvent.MinY = w->TopEdge;
	    lastinvent.MaxX = w->Width;
	    lastinvent.MaxY = w->Height;
	}

	/* Close the window */
	CloseShWindow( w );
	cw->win = NULL;

	/* Free copy of NewWindow structure for TEXT/MENU windows. */
	if( cw->newwin )
	    FreeNewWindow( (void *)cw->newwin );
	cw->newwin = NULL;
    }
}

void
amii_exit_nhwindows(str)
    const char *str;
{
    /* Seems strange to have to do this... but we need the BASE window
     * left behind...
     */
    kill_nhwindows( 0 );
    if( WINVERS_AMIV )
	FreeTileImageFiles( );

    if( str )
    {
	raw_print( "" );	/* be sure we're not under the top margin */
	raw_print( str );
    }
}

void
amii_display_nhwindow(win,blocking)
    winid win;
    boolean blocking;
{
    menu_item *mip;
    int cnt;
    static int lastwin = -1;
    struct amii_WinDesc *cw;

    if( !Initialized )
	return;
    lastwin = win;

    if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL )
	panic(winpanicstr,win,"display_nhwindow");

    if( cw->type == NHW_MESSAGE )
	cw->wflags &= ~FLMAP_SKIP;

    if( cw->type == NHW_MESSAGE || cw->type == NHW_STATUS )
	return;

    if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
    {
	flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
    }

    if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
    {
	cnt = DoMenuScroll( win, blocking, PICK_ONE, &mip );
    }
    else if( cw->type==NHW_MAP )
    {
	amii_end_glyphout( win );
	/* Do more if it is time... */
	if( blocking == TRUE && amii_wins[ WIN_MESSAGE ]->curx )
	{
	    outmore( amii_wins[ WIN_MESSAGE ] );
	}
    }
}

void
amii_curs(window, x, y)
winid window;
register int x, y;  /* not xchar: perhaps xchar is unsigned and
	       curx-x would be unsigned as well */
{
    register struct amii_WinDesc *cw;
    register struct Window *w;
    register struct RastPort *rp;

    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
	panic(winpanicstr,  window, "curs");
    if( (w = cw->win) == NULL )
    {
	if( cw->type == NHW_MENU || cw->type == NHW_TEXT )
	    return;
	else
	    panic( "No window open yet in curs() for winid %d\n", window );
    }
    amiIDisplay->lastwin = window;

    /* Make sure x is within bounds */
    if( x > 0 )
	--x;    /* column 0 is never used */
    else
	x = 0;

    cw->curx = x;
    cw->cury = y;

#ifdef DEBUG
    if( x<0 || y<0 || y >= cw->rows || x >= cw->cols )
    {
	char *s = "[unknown type]";
	switch(cw->type)
	{
	    case NHW_MESSAGE: s = "[topl window]"; break;
	    case NHW_STATUS: s = "[status window]"; break;
	    case NHW_MAP: s = "[map window]"; break;
	    case NHW_MENU: s = "[menu window]"; break;
	    case NHW_TEXT: s = "[text window]"; break;
	    case NHW_BASE: s = "[base window]"; break;
	    case NHW_OVER: s = "[overview window]"; break;
	}
	impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
	return;
    }
#endif

#ifdef CLIPPING
    if(clipping && cw->type == NHW_MAP)
    {
	x -= clipx;
	y -= clipy;
    }
#endif

    /* Output all saved output before doing cursor movements for MAP */

    if( cw->type == NHW_MAP )
    {
	flush_glyph_buffer( w );
    }

    /* Actually do it */

    rp = w->RPort;
    if( cw->type == NHW_MENU )
    {
	if( WINVERS_AMIV )
	{
	    if( window == WIN_INVEN )
	    {
		Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1 + pictdata.xsize + 4,
		    (y * max(rp->TxHeight,pictdata.ysize + 3) ) +
		     rp->TxBaseline + pictdata.ysize - rp->TxHeight + w->BorderTop + 4 );
	    }
	    else
	    {
		Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
		    (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1 );
	    }
	}
	else
	{
	    Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
		(y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 );
	}
    }
    else if( cw->type == NHW_TEXT )
    {
	Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1,
	    (y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 );
    }
    else if( cw->type == NHW_MAP || cw->type == NHW_BASE )
    {
	/* These coordinate calculations must be synced with those
	 * in flush_glyph_buffer() in winchar.c.  curs_on_u() will
	 * use this code, all other drawing occurs through the glyph
	 * code.  In order for the cursor to appear on top of the hero,
	 * the code must compute X,Y in the same manner relative to
	 * the RastPort coordinates.
	 *
	 * y = w->BorderTop + (g_nodes[i].y-2) * rp->TxHeight +
	 *   rp->TxBaseline + 1;
	 * x = g_nodes[i].x * rp->TxWidth + w->BorderLeft;
	 */

	if( WINVERS_AMIV )
	{
	    if( cw->type == NHW_MAP )
	    {
	      if(Is_rogue_level(&u.uz)){
#if 0
int qqx= (x * w->RPort->TxWidth) + w->BorderLeft;
int qqy= w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1;
printf("pos: (%d,%d)->(%d,%d)\n",x,y,qqx,qqy);
#endif
		SetAPen(w->RPort,C_WHITE); /* XXX should be elsewhere (was 4)*/
		Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
			w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1 );
	      } else {
		Move( rp, (x * mxsize) + w->BorderLeft,
				w->BorderTop + ( (y+1) * mysize ) + 1 );
	      }
	    }
	    else
	    {
		Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
			    w->BorderTop + ( (y + 1) * w->RPort->TxHeight ) +
			    w->RPort->TxBaseline + 1 );
	    }
	}
	else
	{
	    Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft,
			w->BorderTop + ( y * w->RPort->TxHeight ) +
			w->RPort->TxBaseline + 1 );
	}
    }
    else if( WINVERS_AMIV && cw->type == NHW_OVER )
    {
	Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
			w->BorderTop + w->RPort->TxBaseline + 3 );
    }
    else if( cw->type == NHW_MESSAGE && !scrollmsg )
    {
	Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
			w->BorderTop + w->RPort->TxBaseline + 3 );
    }
    else if( cw->type == NHW_STATUS )
    {
	Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
			(y*(w->RPort->TxHeight+1)) + w->BorderTop +
			w->RPort->TxBaseline + 1 );
    }
    else
    {
	Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2,
			(y*w->RPort->TxHeight) + w->BorderTop +
			w->RPort->TxBaseline + 1 );
    }
}

void
amii_set_text_font( name, size )
    char *name;
    int size;
{
    register int i;
    register struct amii_WinDesc *cw;
    int osize = TextsFont13.ta_YSize;
    static char nname[ 100 ];

    strncpy( nname, name, sizeof( nname ) - 1 );
    nname[ sizeof( nname ) - 1 ] = 0;

    TextsFont13.ta_Name = nname;
    TextsFont13.ta_YSize = size;

    /* No alternate text font allowed for 640x269 or smaller */
    if( !HackScreen || !bigscreen )
	return;

    /* Look for windows to set, and change them */

    if( DiskfontBase =
		OpenLibrary( "diskfont.library", amii_libvers  ) )
    {
	TextsFont = OpenDiskFont( &TextsFont13 );
	for( i = 0; TextsFont && i < MAXWIN; ++i )
	{
	    if( (cw = amii_wins[ i ]) && cw->win != NULL )
	    {
	    	switch( cw->type )
	    	{
	    	case NHW_STATUS:
		    MoveWindow( cw->win, 0, -( size - osize ) * 2 );
		    SizeWindow( cw->win, 0, ( size - osize ) * 2 );
		    SetFont( cw->win->RPort, TextsFont );
		    break;
	    	case NHW_MESSAGE:
	    	case NHW_MAP:
	    	case NHW_BASE:
	    	case NHW_OVER:
		    SetFont( cw->win->RPort, TextsFont );
		    break;
	    	}
	    }
	}
    }
    CloseLibrary(DiskfontBase);
    DiskfontBase = NULL;
}

void
kill_nhwindows( all )
    register int all;
{
    register int i;
    register struct amii_WinDesc *cw;

    /* Foreach open window in all of amii_wins[], CloseShWindow, free memory */

    for( i = 0; i < MAXWIN; ++i )
    {
	if( (cw = amii_wins[ i ]) && (cw->type != NHW_BASE || all) )
	{
	    amii_destroy_nhwindow( i );
	}
    }
}

void
amii_cl_end( cw, curs_pos )
    register struct amii_WinDesc *cw;
    register int curs_pos;
{
    register struct Window *w = cw->win;
    register int oy, ox;

    if( !w )
	panic("NULL window pointer in amii_cl_end()");

    oy = w->RPort->cp_y;
    ox = w->RPort->cp_x;

    TextSpaces( w->RPort, cw->cols - curs_pos );

    Move( w->RPort, ox, oy );
}

void
cursor_off( window )
    winid window;
{
    register struct amii_WinDesc *cw;
    register struct Window *w;
    register struct RastPort *rp;
    int curx, cury;
    int x, y;
    long dmode;
    short apen, bpen;
    unsigned char ch;

    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
    {
	iflags.window_inited=0;
	panic(winpanicstr,window, "cursor_off");
    }

    if( !(cw->wflags & FLMAP_CURSUP ) )
	return;

    w = cw->win;

    if( !w )
	return;

    cw->wflags &= ~FLMAP_CURSUP;
    rp = w->RPort;

    /* Save the current information */
    curx = rp->cp_x;
    cury = rp->cp_y;
    x = cw->cursx;
    y = cw->cursy;
    dmode = rp->DrawMode;
    apen = rp->FgPen;
    bpen = rp->BgPen;
    SetAPen( rp, cw->curs_apen );
    SetBPen( rp, cw->curs_bpen );
    SetDrMd( rp, COMPLEMENT );
/*printf("CURSOR OFF: %d %d\n",x,y);*/

    if( WINVERS_AMIV && cw->type == NHW_MAP)
    {
	cursor_common(rp, x, y);
	if(Is_rogue_level(&u.uz))
	    Move(rp,curx,cury);
    }
    else
    {
	ch = CURSOR_CHAR;
	Move( rp, x, y );
	Text( rp, &ch, 1 );

	/* Put back the other stuff */

	Move( rp, curx, cury );
    }
    SetDrMd( rp, dmode );
    SetAPen( rp, apen );
    SetBPen( rp, bpen );
}

void
cursor_on( window )
    winid window;
{
    int x, y;
    register struct amii_WinDesc *cw;
    register struct Window *w;
    register struct RastPort *rp;
    unsigned char ch;
    long dmode;
    short apen, bpen;

    if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
    {
	/* tty does this differently - is this OK? */
	iflags.window_inited=0;
	panic(winpanicstr,window, "cursor_on");
    }

/*printf("CURSOR ON: %d %d\n",cw->win->RPort->cp_x, cw->win->RPort->cp_y);*/
    if( (cw->wflags & FLMAP_CURSUP ) )
	cursor_off( window );

    w = cw->win;

    if( !w )
	return;

    cw->wflags |= FLMAP_CURSUP;
    rp = w->RPort;

    /* Save the current information */

#ifdef	DISPMAP
    if( WINVERS_AMIV && cw->type == NHW_MAP && !Is_rogue_level(&u.uz))
	x = cw->cursx = (rp->cp_x & -8) + 8;
    else
#endif
	x = cw->cursx = rp->cp_x;
    y = cw->cursy = rp->cp_y;
    apen = rp->FgPen;
    bpen = rp->BgPen;
    dmode = rp->DrawMode;

    /* Draw in complement mode. The cursor body will be C_WHITE */

    cw->curs_apen = C_RED;
    cw->curs_bpen = C_RED;
    SetAPen( rp, cw->curs_apen );
    SetBPen( rp, cw->curs_bpen );
    SetDrMd( rp, COMPLEMENT );
    if( WINVERS_AMIV && cw->type == NHW_MAP)
    {
	cursor_common(rp, x, y);
    }
    else
    {
	Move( rp, x, y );
	ch = CURSOR_CHAR;
	Text( rp, &ch, 1 );
	Move( rp, x, y );
    }

    SetDrMd( rp, dmode );
    SetAPen( rp, apen );
    SetBPen( rp, bpen );
}

static void
cursor_common(rp, x, y)
	struct RastPort *rp;
	int x,y;
{
    int x1,x2,y1,y2;

    if(Is_rogue_level(&u.uz)){
	x1 = x-2;		y1 = y-rp->TxHeight;
	x2 = x+rp->TxWidth+1;	y2 = y+3;
/*printf("COMM: (%d %d) (%d %d)  (%d %d) (%d %d)\n",x1,y1,x2,y2,x1+2,y1+2,x2-2,y2-2);*/
    } else {
	x1 = x;			y1 = y-mysize-1;
	x2 = x+mxsize-1;	y2 = y-2;
	RectFill(rp, x1, y1, x2, y2);
    }

    RectFill(rp, x1+2, y1+2, x2-2, y2-2);
}

void amii_suspend_nhwindows( str )
    const char *str;
{
    if( HackScreen )
	ScreenToBack( HackScreen );
}

void amii_resume_nhwindows()
{
    if( HackScreen )
	ScreenToFront( HackScreen );
}

void amii_bell()
{
    DisplayBeep( NULL );
}

void
removetopl(cnt)
	int cnt;
{
    struct amii_WinDesc *cw=amii_wins[WIN_MESSAGE];
					/* NB - this is sufficient for
					 * yn_function, but that's it
					 */
    if(cw->curx < cnt)cw->curx=0;
    else cw->curx -= cnt;

    amii_curs(WIN_MESSAGE, cw->curx+1, cw->cury);
    amii_cl_end(cw, cw->curx);
}
/*#endif /* AMIGA_INTUITION */

#ifdef  PORT_HELP
void
port_help()
{
    display_file( PORT_HELP, 1 );
}
#endif

/*
 *  print_glyph
 *
 *  Print the glyph to the output device.  Don't flush the output device.
 *
 *  Since this is only called from show_glyph(), it is assumed that the
 *  position and glyph are always correct (checked there)!
 */

void
amii_print_glyph(win,x,y,glyph)
    winid win;
    xchar x,y;
    int glyph;
{
    struct amii_WinDesc *cw;
    uchar   ch;
    register int offset;
#ifdef TEXTCOLOR
    int     color;
#endif
    extern int zapcolors[];

    /* In order for the overview window to work, we can not clip here */
    if( !WINVERS_AMIV )
    {
#ifdef	CLIPPING
	/* If point not in visible part of window just skip it */
	if( clipping )
	{
	    if( x <= clipx || y < clipy || x >= clipxmax || y >= clipymax )
		return;
	}
#endif
    }

    if( win == WIN_ERR || (cw=amii_wins[win]) == NULL || cw->type != NHW_MAP)
    {
	panic(winpanicstr,win,"amii_print_glyph");
    }

#if 0
{
static int x=-1;
if(u.uz.dlevel != x){
 fprintf(stderr,"lvlchg: %d (%d)\n",u.uz.dlevel,Is_rogue_level(&u.uz));
 x = u.uz.dlevel;
}
}
#endif
    if(
	WINVERS_AMIV
#ifdef REINCARNATION
	&& !Is_rogue_level(&u.uz)
#endif
    )
    {
	amii_curs(win,x,y);
	amiga_print_glyph(win,0,glyph);
    }
    else		/* AMII, or Rogue level in either version */
    {
#ifdef TEXTCOLOR
#define zap_color(n)  color = iflags.use_color ? zapcolors[n] : NO_COLOR
#define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR
#define obj_color(n)  color = iflags.use_color ? objects[n].oc_color : NO_COLOR
#define mon_color(n)  color = iflags.use_color ? mons[n].mcolor : NO_COLOR
#define invis_color(n) color = NO_COLOR
#define pet_color(n)  color = iflags.use_color ? mons[n].mcolor :          \
		/* If no color, try to hilite pets; black  */ \
		/* should be HI                */ \
		    ((iflags.hilite_pet) ? CLR_BLACK : NO_COLOR)
# define warn_color(n) color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR
# else /* no text color */

#define zap_color(n)
#define cmap_color(n)
#define obj_color(n)
#define mon_color(n)
#define invis_color(n)
#define pet_color(n)
#define warn_color(n)
#endif

	/*
	 *  Map the glyph back to a character.
	 *
	 *  Warning:  For speed, this makes an assumption on the order of
	 *        offsets.  The order is set in display.h.
	 */
	if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) {	/* a warning flash */
	    ch = warnsyms[offset];
	    warn_color(offset);
	} else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {  /* swallow */
	    /* see swallow_to_glyph()in display.c */
	    ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
	    mon_color(offset >> 3);
	} else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {       /* zap beam */
	    ch = showsyms[S_vbeam + (offset & 0x3)];
	    zap_color((offset >> 2));
	} else if( ( offset = (glyph - GLYPH_CMAP_OFF) ) >= 0 ) {   /* cmap */
	    ch = showsyms[offset];
	    cmap_color(offset);
	} else if( ( offset = (glyph - GLYPH_OBJ_OFF) ) >= 0 ) {    /* object */
	    ch = oc_syms[objects[offset].oc_class];
	    obj_color(offset);
	} else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* a ridden monster */
	    ch = (uchar) monsyms[mons[offset].mlet];
	    mon_color(offset);
	} else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {  /* a corpse */
	    ch = oc_syms[objects[CORPSE].oc_class];
	    mon_color(offset);
	} else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* a detected monster */
	    ch = (uchar) monsyms[mons[offset].mlet];
	    mon_color(offset);
	} else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) {	/* invisible */
	    ch = DEF_INVISIBLE;
	    invis_color(offset);
	} else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {   /* a pet */
	    ch = (uchar) monsyms[mons[offset].mlet];
	    pet_color(offset);
	} else /*if( glyph_is_monster(glyph) )*/ {      /* a monster */
	    ch = (uchar) monsyms[mons[glyph].mlet];
	    mon_color(glyph);
	}
				/* XXX next if should be ifdef REINCARNATION */
	if( WINVERS_AMIV ){			/* implies Rogue level here */
	    amii_curs(win,x,y);
	    amiga_print_glyph(win,NO_COLOR,ch + 10000);
	} else {
		/* Move the cursor. */
	    amii_curs(win,x,y+2);

#ifdef TEXTCOLOR
		/* Turn off color if rogue level. */
# ifdef REINCARNATION
	    if (Is_rogue_level(&u.uz))
		color = NO_COLOR;
#  endif

	    amiga_print_glyph(win,color,ch);
#else
	    g_putch(ch);    /* print the character */
#endif
	    cw->curx++;     /* one character over */
	}
    }
}

/* Make sure the user sees a text string when no windowing is available */

void
amii_raw_print(s)
    register const char *s;
{
    int argc = 0;

    if( !s )
	return;
    if(amiIDisplay)
	amiIDisplay->rawprint++;

    if (!Initialized) { /* Not yet screen open ... */
        puts(s);
        fflush(stdout);
        return;
    }

    if( Initialized == 0 && WIN_BASE == WIN_ERR )
	    init_nhwindows(&argc, (char **)0);

    if( amii_rawprwin != WIN_ERR )
	amii_putstr( amii_rawprwin, 0, s );
    else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
	amii_putstr( WIN_MAP, 0, s );
    else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
	amii_putstr( WIN_BASE, 0, s );
    else
    {
	puts( s);
	fflush(stdout);
    }
}

/* Make sure the user sees a bold text string when no windowing
 * is available
 */

void
amii_raw_print_bold(s)
    register const char *s;
{
    int argc = 0;

    if( !s )
	return;

    if(amiIDisplay)
	amiIDisplay->rawprint++;

    if (!Initialized) { /* Not yet screen open ... */
        puts(s);
        fflush(stdout);
        return;
    }

    if( Initialized == 0 && WIN_BASE == WIN_ERR )
	    init_nhwindows(&argc, (char **)0);

    if( amii_rawprwin != WIN_ERR )
	amii_putstr( amii_rawprwin, 1, s );
    else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] )
	amii_putstr( WIN_MAP, 1, s );
    else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] )
	amii_putstr( WIN_BASE, 1, s );
    else
    {
	printf("\33[1m%s\33[0m\n",s);
	fflush(stdout);
    }
}

/* Rebuild/update the inventory if the window is up.
 */
void
amii_update_inventory()
{
    register struct amii_WinDesc *cw;

    if( WIN_INVEN != WIN_ERR && ( cw = amii_wins[ WIN_INVEN ] ) &&
				cw->type == NHW_MENU && cw->win )
    {
	display_inventory( NULL, FALSE );
    }
}

/* Humm, doesn't really do anything useful */

void
amii_mark_synch()
{
    if(!amiIDisplay)
	fflush(stderr);
/* anything else?  do we need this much? */
}

/* Wait for everything to sync.  Nothing is asynchronous, so we just
 * ask for a key to be pressed.
 */
void
amii_wait_synch()
{
    if(!amiIDisplay || amiIDisplay->rawprint)
    {
	if(amiIDisplay) amiIDisplay->rawprint=0;
    }
    else
    {
	if( WIN_MAP != WIN_ERR )
	{
	    display_nhwindow(WIN_MAP,TRUE);
	    flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
	}
    }
}

void
amii_setclipped()
{
#ifdef	CLIPPING
    clipping = TRUE;
    clipx=clipy=0;
    clipxmax=CO;
    clipymax=LI;
/* some of this is now redundant with top of amii_cliparound XXX */
#endif
}

/* XXX still to do: suppress scrolling if we violate the boundary but the
 * edge of the map is already displayed
 */
void
amii_cliparound(x,y)
    register int x,y;
{
    extern boolean restoring;
#ifdef	CLIPPING
    int oldx = clipx, oldy = clipy;
    int oldxmax = clipxmax, oldymax = clipymax;
    int COx, LIx;
#define	SCROLLCNT	1	/* Get there in 3 moves... */
    int scrollcnt = SCROLLCNT;	/* ...or 1 if we changed level */
    if (!clipping)		/* And 1 in anycase, cleaner, simpler, quicker */
	return;

    if(Is_rogue_level(&u.uz)){
	struct Window *w = amii_wins[WIN_MAP]->win;
	struct RastPort *rp = w->RPort;

	COx = (w->Width-w->BorderLeft-w->BorderRight)/rp->TxWidth;
	LIx = (w->Height-w->BorderTop-w->BorderBottom)/rp->TxHeight;
    }else{
	COx = CO;
	LIx = LI;
    }
		/*
		 * On a level change, move the clipping region so that for a
		 * reasonablely large window extra motion is avoided; for
		 * the rogue level hopefully this means no motion at all.
		 */
    {
	static d_level saved_level = {127,127};		/* XXX */

	if(!on_level(&u.uz, &saved_level)){
	    scrollcnt = 1;	/* jump with blanking */
	    clipx=clipy=0;
	    clipxmax = COx; clipymax = LIx;
	    saved_level = u.uz;		/* save as new current level */
	}
    }

    if (x <= clipx + xclipbord ) {
	clipx = max(0, x - (clipxmax - clipx)/2 );
	clipxmax = clipx + COx;
    }
    else if (x > clipxmax - xclipbord ) {
	clipxmax = min(COLNO, x + (clipxmax - clipx)/2 );
	clipx = clipxmax - COx;
    }

    if (y <= clipy + yclipbord ) {
	clipy = max(0, y - (clipymax - clipy) / 2);
	clipymax = clipy + LIx;
    }
    else if (y > clipymax - yclipbord ) {
	clipymax = min(ROWNO, y + (clipymax - clipy) / 2);
	clipy = clipymax - LIx;
    }

    reclip = 1;
    if (clipx != oldx || clipy != oldy || clipxmax != oldxmax || clipymax != oldymax )
    {
#ifndef NOSCROLLRASTER
    	struct Window *w = amii_wins[ WIN_MAP ]->win;
    	struct RastPort *rp = w->RPort;
    	int xdelta, ydelta, xmod, ymod, i;
    	int incx, incy, mincx, mincy;
    	int savex, savey, savexmax, saveymax;
	int scrx, scry;

	if(Is_rogue_level(&u.uz)){
	    scrx = rp->TxWidth;
	    scry = rp->TxHeight;
	} else {
	    scrx = mxsize;
	    scry = mysize;
	}

	/* Ask that the glyph routines not draw the overview window */
	reclip = 2;
	cursor_off( WIN_MAP );

	/* Compute how far we are moving in terms of tiles */
	mincx = clipx - oldx ;
	mincy = clipy - oldy ;

	/* How many tiles to get there in SCROLLCNT moves */
	incx = ( clipx - oldx )/scrollcnt;
	incy = ( clipy - oldy )/scrollcnt;

	/* If less than SCROLLCNT tiles, then move by 1 tile if moving at all */
	if( incx == 0 ) incx = (mincx != 0);
	if( incy == 0 ) incy = (mincy != 0);

	/* Get count of pixels to move each iteration and final pixel count */
    	xdelta = ((clipx-oldx )*scrx) / scrollcnt;
    	xmod = ((clipx-oldx )*scrx) % scrollcnt;
    	ydelta = ((clipy-oldy )*scry) / scrollcnt;
    	ymod = ((clipy-oldy )*scry) % scrollcnt;

	/* Preserve the final move location */
    	savex = clipx;
     	savey = clipy;
	saveymax = clipymax;
	savexmax = clipxmax;

	/*
	 * Set clipping rectangle to be just the region that will be exposed so
	 * that drawing will be faster
	 */
#if 0	/* Doesn't seem to work quite the way it should */
	/* In some cases hero is 'centered' offscreen */
	if( xdelta < 0 )
	{
	    clipx = oldx;
	    clipxmax = clipx + incx;
	}
	else if( xdelta > 0 )
	{
	    clipxmax = oldxmax;
	    clipx = clipxmax - incx;
	}
	else
	{
	    clipx = oldx;
	    clipxmax = oldxmax;
	}

	if( ydelta < 0 )
	{
	    clipy = oldy;
	    clipymax = clipy + incy;
	}
	else if( ydelta > 0 )
	{
	    clipymax = oldymax;
	    clipy = clipymax - incy;
	}
	else
	{
	    clipy = oldy;
	    clipymax = oldymax;
	}
#endif
	/* Now, in scrollcnt moves, move the picture toward the final view */
    	for( i = 0; i < scrollcnt; ++i )
    	{
#ifdef	DISPMAP
	    if( i == scrollcnt - 1 && (xmod != 0 || ymod != 0) &&
			(xdelta != 0 || ydelta != 0) )
	    {
		incx += (clipx - oldx)%scrollcnt;
		incy += (clipy - oldy)%scrollcnt;
		xdelta += xmod;
		ydelta += ymod;
	    }
#endif
	    /* Scroll the raster if we are scrolling */
	    if( xdelta != 0 || ydelta != 0 )
	    {
		ScrollRaster( rp, xdelta, ydelta,
			    w->BorderLeft, w->BorderTop,
			    w->Width - w->BorderRight - 1,
			    w->Height - w->BorderBottom - 1 );

		if( mincx == 0 ) incx = 0;
		else mincx -= incx;

		clipx += incx;
		clipxmax += incx;

		if( mincy == 0 ) incy = 0;
		else mincy -= incy;

		clipy += incy;
		clipymax += incy;

		/* Draw the exposed portion */
		if (on_level(&u.uz0, &u.uz) && !restoring)
		    (void) doredraw();
		flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
	    }
    	}

    	clipx = savex;
     	clipy = savey;
	clipymax = saveymax;
	clipxmax = savexmax;
#endif
	if (on_level(&u.uz0, &u.uz) && !restoring && moves > 1)
	    (void) doredraw();
	flush_glyph_buffer( amii_wins[ WIN_MAP ]->win );
    }
    reclip = 0;
#endif
}

void
flushIDCMP( port )
	struct MsgPort *port;
{
	struct Message *msg;
	while( msg = GetMsg( port ) )
		ReplyMsg( msg );
}
