/*	SCCS Id: @(#)wingem1.c	3.4	1999/12/10	*/
/* Copyright (c) Christian Bressler 1999 	  */
/* NetHack may be freely redistributed.  See license for details. */

#define __TCC_COMPAT__

#include	<stdio.h>
#include	<stdlib.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>
#include <e_gem.h>
#include <string.h>

#include "gem_rsc.h"
#include "load_img.h"
#include "gr_rect.h"

#define genericptr_t void *
#include "wintype.h"
#undef genericptr_t

#define NDECL(f)	f(void)
#define FDECL(f,p)	f p
#define CHAR_P char
#define SCHAR_P schar
#define UCHAR_P uchar
#define XCHAR_P xchar
#define SHORT_P short
#define BOOLEAN_P boolean
#define ALIGNTYP_P aligntyp
typedef signed char	xchar;
#include "wingem.h"
#undef CHAR_P
#undef SCHAR_P
#undef UCHAR_P
#undef XCHAR_P
#undef SHORT_P
#undef BOOLEAN_P
#undef ALIGNTYP_P
#undef NDECL
#undef FDECL

static char nullstr[]="",  md[]="NetHack 3.4.0", strCancel[]="Cancel", strOk[]="Ok", strText[]="Text";

extern winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN;

#define MAXWIN 20
#define ROWNO 21
#define COLNO 80
#define MSGLEN 100

#define MAP_GADGETS NAME|MOVER|CLOSER|FULLER|LFARROW|RTARROW|UPARROW|DNARROW|VSLIDE|HSLIDE|SIZER|SMALLER
#define DIALOG_MODE AUTO_DIAL|MODAL|NO_ICONIFY

/*
 *  Keyboard translation tables.
 */
#define C(c)	(0x1f & (c))
#define M(c)	(0x80 | (c))

#define KEYPADLO	0x61
#define KEYPADHI	0x71

#define PADKEYS 	(KEYPADHI - KEYPADLO + 1)
#define iskeypad(x)	(KEYPADLO <= (x) && (x) <= KEYPADHI)

/*
 * Keypad keys are translated to the normal values below.
 * When iflags.BIOS is active, shifted keypad keys are translated to the
 *    shift values below.
 */
static const struct pad {
	char normal, shift, cntrl;
} keypad[PADKEYS] = {
			{C('['), 'Q', C('[')},		/* UNDO */
			{'?', '/', '?'},		/* HELP */
			{'(', 'a', '('},		/* ( */
			{')', 'w', ')'},		/* ) */
			{'/', '/', '/'},		/* / */
			{C('p'), '$', C('p')},		/* * */
			{'y', 'Y', C('y')},		/* 7 */
			{'k', 'K', C('k')},		/* 8 */
			{'u', 'U', C('u')},		/* 9 */
			{'h', 'H', C('h')},		/* 4 */
			{'.', '.', '.'},
			{'l', 'L', C('l')},		/* 6 */
			{'b', 'B', C('b')},		/* 1 */
			{'j', 'J', C('j')},		/* 2 */
			{'n', 'N', C('n')},		/* 3 */
			{'i', 'I', C('i')},		/* Ins */
			{'.', ':', ':'}			/* Del */
}, numpad[PADKEYS] = {
			{C('['), 'Q', C('[')}	,	/* UNDO */
			{'?', '/', '?'},		/* HELP */
			{'(', 'a', '('},		/* ( */
			{')', 'w', ')'},		/* ) */
			{'/', '/', '/'},		/* / */
			{C('p'), '$', C('p')},		/* * */
			{'7', M('7'), '7'},		/* 7 */
			{'8', M('8'), '8'},		/* 8 */
			{'9', M('9'), '9'},		/* 9 */
			{'4', M('4'), '4'},		/* 4 */
			{'.', '.', '.'},		/* 5 */
			{'6', M('6'), '6'},		/* 6 */
			{'1', M('1'), '1'},		/* 1 */
			{'2', M('2'), '2'},		/* 2 */
			{'3', M('3'), '3'},		/* 3 */
			{'i', 'I', C('i')},		/* Ins */
			{'.', ':', ':'}			/* Del */
};

#define TBUFSZ 300
#define BUFSZ 256
extern int yn_number;							/* from decl.c */
extern char toplines[TBUFSZ];					/* from decl.c */
extern char mapped_menu_cmds[];				/* from options.c */
extern int mar_iflags_numpad(void);			/* from wingem.c */
extern void Gem_raw_print(const char *);	/* from wingem.c */
extern int mar_hp_query(void);				/* from wingem.c */
extern int mar_get_msg_history(void);		/* from wingem.c */
extern int mar_get_msg_visible(void);		/* from wingem.c */
extern void mar_get_font(int,char **,int *);/* from wingem.c */
extern int vdi2dev4[];							/* from load_img.c */

void recalc_msg_win(GRECT*);
void recalc_status_win(GRECT*);
void calc_std_winplace(int, GRECT *);
int (*v_mtext)(int,int,int,char*);
static int no_glyph;	/* the int indicating there is no glyph */
IMG_header tile_image, titel_image, rip_image;
MFDB Tile_bilder, Map_bild, Titel_bild, Rip_bild, Black_bild, Pet_Mark, FontCol_Bild;
static int Tile_width=16, Tile_heigth=16, Tiles_per_line=20;
char *Tilefile=NULL;
/* pet_mark Design by Warwick Allison warwick@troll.no */
static int pet_mark_data[]={0x0000,0x3600,0x7F00,0x7F00,0x3E00,0x1C00,0x0800};
static short	*normal_palette=NULL;

static struct gw{
	WIN *gw_window;
	int gw_type, gw_dirty;
	GRECT gw_place;
} Gem_nhwindow[MAXWIN];

typedef struct {
	int id;
	int size;
	int cw, ch;
	int prop;
} NHGEM_FONT;

/*struct gemmapdata {*/
	GRECT dirty_map_area={COLNO-1,ROWNO,0,0};
	int map_cursx=0, map_cursy=0, curs_col=WHITE;
	int draw_cursor=TRUE, scroll_margin=-1;
	NHGEM_FONT map_font;
	SCROLL 	scroll_map;
	char **map_glyphs=NULL;
	dirty_rect *dr_map;
/*};*/

/*struct gemstatusdata{*/
	char **status_line;
	int Anz_status_lines, status_w, status_align=FALSE;
	NHGEM_FONT status_font;
	dirty_rect *dr_stat;
/*};*/

/*struct gemmessagedata{*/
	int mar_message_pause=TRUE;
	int mar_esc_pressed=FALSE;
	int messages_pro_zug=0;
	char **message_line;
	int *message_age;
	int msg_pos=0, msg_max=0, msg_anz=0, msg_width=0, msg_vis=3, msg_align=TRUE;
	NHGEM_FONT msg_font;
	dirty_rect *dr_msg;
/*};*/

/*struct geminvdata {*/
	SCROLL scroll_menu;
	Gem_menu_item *invent_list;
	int Anz_inv_lines=0, Inv_breite=16;
	NHGEM_FONT menu_font;
	int Inv_how;
/*};*/

/*struct gemtextdata{*/
	char **text_lines;
	int Anz_text_lines=0, text_width;
	NHGEM_FONT text_font;
	int use_rip=FALSE;
	extern char** rip_line;
/*};*/

static OBJECT *zz_oblist[NHICON+1];

MITEM scroll_keys[]={
/* menu, key, state, mode, msg */
	{FAIL,key(CTRLLEFT,0),K_CTRL,PAGE_LEFT,FAIL},
	{FAIL,key(CTRLRIGHT,0),K_CTRL,PAGE_RIGHT,FAIL},
	{FAIL,key(SCANUP,0),K_SHIFT,PAGE_UP,FAIL},
	{FAIL,key(SCANDOWN,0),K_SHIFT,PAGE_DOWN,FAIL},
	{FAIL,key(SCANLEFT,0),0,LINE_LEFT,FAIL},
	{FAIL,key(SCANRIGHT,0),0,LINE_RIGHT,FAIL},
	{FAIL,key(SCANUP,0),0,LINE_UP,FAIL},
	{FAIL,key(SCANDOWN,0),0,LINE_DOWN,FAIL},
	{FAIL,key(SCANLEFT,0),K_SHIFT,LINE_START,FAIL},
	{FAIL,key(SCANRIGHT,0),K_SHIFT,LINE_END,FAIL},
	{FAIL,key(SCANUP,0),K_CTRL,WIN_START,FAIL},
	{FAIL,key(SCANDOWN,0),K_CTRL,WIN_END,FAIL},
	{FAIL,key(SCANHOME,0),K_SHIFT,WIN_END,FAIL},
	{FAIL,key(SCANHOME,0),0,WIN_START,FAIL}
};
#define SCROLL_KEYS	14

static DIAINFO *Inv_dialog;

#define null_free(ptr)	free(ptr), (ptr)=NULL
#define test_free(ptr)	if(ptr) null_free(ptr)

static char *Menu_title=NULL;

void mar_display_nhwindow(winid);
void mar_check_hilight_status(void){}	/* to be filled :-) */
static char *mar_copy_of(const char *);

extern void panic(const char *, ...);
void *m_alloc(size_t amt){
	void *ptr;

	ptr=malloc(amt);
	if (!ptr) panic("Memory allocation failure; cannot get %lu bytes", amt);
	return(ptr);
}

void mar_clear_messagewin(void){
	int i, *ptr=message_age;

	if(WIN_MESSAGE==WIN_ERR) return;
	for(i=msg_anz;--i>=0;ptr++){
		if(*ptr)
			Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
		*ptr=FALSE;
	}
	mar_message_pause=FALSE;

	mar_display_nhwindow(WIN_MESSAGE);
}

void clipbrd_save(void *data,int cnt,boolean append,boolean is_inv){
	char path[MAX_PATH],*text,*crlf="\r\n";
	long handle;
	int i;

	if (data && cnt>0 && scrp_path(path,"scrap.txt") && (handle = append ? Fopen(path,1) : Fcreate(path,0))>0){
		if (append)
			Fseek(0L,(int) handle,SEEK_END);
		if(is_inv){
			Gem_menu_item *it=(Gem_menu_item *)data;

			for(;it;it=it->Gmi_next){
				text=it->Gmi_str;
				Fwrite((int) handle,strlen(text),text);
				Fwrite((int) handle,2L,crlf);
			}
		}else{
			for(i=0;i<cnt;i++){
				text=((char **)data)[i]+1;
				Fwrite((int) handle,strlen(text),text);
				Fwrite((int) handle,2L,crlf);
			}
		}
		Fclose((int) handle);

		scrp_changed(SCF_TEXT,0x2e545854l);	/* .TXT */
	}
}

void move_win(WIN *z_win){
	GRECT frame=desk;

	v_set_mode(MD_XOR);
	v_set_line(BLACK,1,1,0,0);
	frame.g_w<<=1, frame.g_h<<=1;
	if(graf_rt_dragbox(FALSE,&z_win->curr,&frame,&z_win->curr.g_x,&z_win->curr.g_y,NULL))
		window_size(z_win,&z_win->curr);
	else
		window_top(z_win);
}

void message_handler(int x, int y){
	switch(objc_find(zz_oblist[MSGWIN],ROOT,MAX_DEPTH,x,y)){
	case UPMSG:
		if(msg_pos>msg_vis-1){
			msg_pos--;
			Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
			mar_display_nhwindow(WIN_MESSAGE);
		}
		Event_Timer(50,0,TRUE);
		break;
	case DNMSG:
		if(msg_pos<msg_max){
			msg_pos++;
			Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
			mar_display_nhwindow(WIN_MESSAGE);
		}
		Event_Timer(50,0,TRUE);
		break;
	case GRABMSGWIN:
	default:
		move_win(Gem_nhwindow[WIN_MESSAGE].gw_window);
		break;
	case -1:
		break;
	}
}

int mar_ob_mapcenter(OBJECT *p_obj){
	WIN *p_w= WIN_MAP!=WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL;

	if(p_obj && p_w){
		p_obj->ob_x=p_w->work.g_x+p_w->work.g_w/2-p_obj->ob_width/2;
		p_obj->ob_y=p_w->work.g_y+p_w->work.g_h/2-p_obj->ob_height/2;
		return(DIA_LASTPOS);
	}
	return(DIA_CENTERED);
}

/****************************** set_no_glyph *************************************/

void
mar_set_no_glyph(ng)
int ng;
{
	no_glyph=ng;
}

void
mar_set_tilefile(name)
char* name;
{
	Tilefile=name;
}
void
mar_set_tilex(value)
int value;
{
	Min(&value,32);
	Max(&value,1);
	Tile_width=value;
}
void
mar_set_tiley(value)
int value;
{
	Min(&value,32);
	Max(&value,1);
	Tile_heigth=value;
}
/****************************** userdef_draw *************************************/

void rearrange_windows(void);
void mar_set_status_align(int sa){
	if(status_align!=sa){
		status_align=sa;
		rearrange_windows();
	}
}
void mar_set_msg_align(int ma){
	if(msg_align!=ma){
		msg_align=ma;
		rearrange_windows();
	}
}
void mar_set_msg_visible(int mv){
	if(mv!=msg_vis){
		Max(&mv,1);
		Min(&mv,min(msg_anz,20));
		Min(&mv,desk.g_h/msg_font.ch/2);
		msg_vis=mv;
		rearrange_windows();
	}
}
/* size<0 cellheight; size>0 points */
void mar_set_fontbyid(int type, int id, int size){
	int chardim[4];
	if(id<=0)
		id=ibm_font_id;
	if((size>-3 && size<3) || size<-20 || size>20)
		size=-ibm_font;
	/* MAR -- 17.Mar 2002 For now allow FNT_PROP only with NHW_TEXT */
	if(type!=NHW_TEXT && (FontInfo(id)->type & (FNT_PROP|FNT_ASCII)))
		id=ibm_font_id;
	switch(type){
	case NHW_MESSAGE:
		if(msg_font.size==-size && msg_font.id==id)
			break;
		msg_font.size=-size;
		msg_font.id=id;
		msg_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
		v_set_text(msg_font.id,msg_font.size,BLACK,0,0,chardim);
		msg_font.ch=chardim[3] ? chardim[3] : 1;
		msg_font.cw=chardim[2] ? chardim[2] : 1;
		msg_width=min(max_w/msg_font.cw-3,MSGLEN);
		rearrange_windows();
		break;
	case NHW_MAP:
		if(map_font.size!=-size || map_font.id!=id){
			MFDB mtmp;
			map_font.size=-size;
			map_font.id=id;
			map_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
			v_set_text(map_font.id,map_font.size,BLACK,0,0,chardim);
			map_font.ch=chardim[3] ? chardim[3] : 1;
			map_font.cw=chardim[2] ? chardim[2] : 1;
			mfdb(&mtmp,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
			if(mfdb_size(&mtmp)>mfdb_size(&FontCol_Bild) && mfdb_size(&mtmp)>mfdb_size(&Map_bild)){
				FontCol_Bild.fd_addr=Map_bild.fd_addr=(int *)realloc(Map_bild.fd_addr,mfdb_size(&mtmp));
				if(!Map_bild.fd_addr)	/* FIXME -- Not really neccessary since the former space is still valid */
					panic("Not enough Space for the map.");
			}
			mfdb(&FontCol_Bild,FontCol_Bild.fd_addr,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
			rearrange_windows();
		}
		break;
	case NHW_STATUS:
		if(status_font.size==-size && status_font.id==id)
			break;
		status_font.size=-size;
		status_font.id=id;
		status_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
		v_set_text(status_font.id,status_font.size,BLACK,0,0,chardim);
		status_font.ch=chardim[3] ? chardim[3] : 1;
		status_font.cw=chardim[2] ? chardim[2] : 1;
		rearrange_windows();
		break;
	case NHW_MENU:
		if(menu_font.size==-size && menu_font.id==id)
			break;
		menu_font.size=-size;
		menu_font.id=id;
		menu_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
		v_set_text(menu_font.id,menu_font.size,BLACK,0,0,chardim);
		menu_font.ch=chardim[3] ? chardim[3] : 1;
		menu_font.cw=chardim[2] ? chardim[2] : 1;
		break;
	case NHW_TEXT:
		if(text_font.size==-size && text_font.id==id)
			break;
		text_font.size=-size;
		text_font.id=id;
		text_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII);
		v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim);
		text_font.ch=chardim[3] ? chardim[3] : 1;
		text_font.cw=chardim[2] ? chardim[2] : 1;
		break;
	default:
		break;
	}
}
void mar_set_font(int type, const char *font_name, int size){
	int id=0;
	/* MAR -- 17.Mar 2002 usual Gem behavior, use the Font-ID */
	if(font_name && *font_name){
		id=atoi(font_name);
		if(id<=0){
			int i, tid;
			char name[32];
			for(i=fonts_loaded;--i>=0;){
				tid=vqt_name(x_handle,i,name);
				if(!stricmp(name,font_name)){
					id=tid;
					break;
				}
			}
		}
	}
	mar_set_fontbyid(type,id,size);
}
void rearrange_windows(void){
	GRECT area;
	int todo=TRUE;
	if(WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window){
		scroll_map.px_hline=mar_set_tile_mode(FAIL)?Tile_width:map_font.cw;
		scroll_map.px_vline=mar_set_tile_mode(FAIL)?Tile_heigth:map_font.ch;
		if(todo){
			calc_std_winplace(FAIL,&area);
			todo=FALSE;
		}
		calc_std_winplace(NHW_MAP,&area);
		Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w;
		Gem_nhwindow[WIN_MAP].gw_window->max.g_h=area.g_h;
		Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w;
		window_reinit(Gem_nhwindow[WIN_MAP].gw_window,md,md,NULL,FALSE,FALSE);
		{
			int buf[8];
			buf[3]=K_CTRL;
			buf[4]=C('L');
			AvSendMsg(ap_id,AV_SENDKEY,buf);
		}
	}
	if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window){
		if(todo){
			calc_std_winplace(FAIL,&area);
			todo=FALSE;
		}
		calc_std_winplace(NHW_MESSAGE,&area);
		Gem_nhwindow[WIN_MESSAGE].gw_window->min_h=area.g_h;
		window_size(Gem_nhwindow[WIN_MESSAGE].gw_window,&area);
		redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window,NULL);
	}
	if(WIN_STATUS != WIN_ERR && Gem_nhwindow[WIN_STATUS].gw_window){
		if(todo){
			calc_std_winplace(FAIL,&area);
			todo=FALSE;
		}
		calc_std_winplace(NHW_STATUS,&area);
		Gem_nhwindow[WIN_STATUS].gw_window->min_h=area.g_h;
		window_size(Gem_nhwindow[WIN_STATUS].gw_window,&area);
		redraw_window(Gem_nhwindow[WIN_STATUS].gw_window,NULL);
	}
}
void my_color_area(GRECT *area, int col){
	int pxy[4];

	v_set_fill(col,1,IP_SOLID,0);
	rc_grect_to_array(area,pxy);
	v_bar(x_handle,pxy);
}

void my_clear_area(GRECT *area){
	my_color_area(area, WHITE);
}

int mar_set_tile_mode(int);

static void win_draw_map(int first, WIN *win, GRECT *area){
	int pla[8], w=area->g_w-1, h=area->g_h-1;
	int i, x, y;
	GRECT back=*area;

	first=first;

	if(!mar_set_tile_mode(FAIL)){
		int start=(area->g_x-win->work.g_x)/map_font.cw+scroll_map.hpos;
		int stop=(area->g_x+area->g_w+map_font.cw-1-win->work.g_x)/map_font.cw+scroll_map.hpos;
		int starty=(area->g_y-win->work.g_y)/map_font.ch+scroll_map.vpos;
		int stopy=min((area->g_y+area->g_h+map_font.ch-1-win->work.g_y)/map_font.ch+scroll_map.vpos,ROWNO);
		char tmp;
		v_set_text(map_font.id,map_font.size,WHITE,0,0,NULL);
		v_set_mode(MD_TRANS);

		x=win->work.g_x-scroll_map.px_hpos+start*map_font.cw;
		y=win->work.g_y-scroll_map.px_vpos+starty*map_font.ch;
		pla[2]=pla[0]=scroll_map.px_hpos+area->g_x-win->work.g_x;
		pla[3]=pla[1]=starty*map_font.ch;
		pla[2]+=w;
		pla[3]+=map_font.ch-1;
		pla[6]=pla[4]=area->g_x;	/* x_wert to */
		pla[7]=pla[5]=y;	/* y_wert to */
		pla[6]+=w;
		pla[7]+=map_font.ch-1;
		back.g_h=map_font.ch;
		for(i=starty;i<stopy;i++,y+=map_font.ch,pla[1]+=map_font.ch,pla[3]+=map_font.ch,pla[5]+=map_font.ch,pla[7]+=map_font.ch){
			back.g_y=y;
			my_color_area(&back,BLACK);
			tmp=map_glyphs[i][stop];
			map_glyphs[i][stop]=0;
			(*v_mtext)(x_handle,x,y,&map_glyphs[i][start]);
			map_glyphs[i][stop]=tmp;
			vro_cpyfm(x_handle, S_OR_D, pla, &FontCol_Bild, screen);
		}
	}else{
		v_set_mode(MD_REPLACE);
		pla[2]=pla[0]=scroll_map.px_hpos+area->g_x-win->work.g_x;
		pla[3]=pla[1]=scroll_map.px_vpos+area->g_y-win->work.g_y;
		pla[2]+=w;
		pla[3]+=h;
		pla[6]=pla[4]=area->g_x;	/* x_wert to */
		pla[7]=pla[5]=area->g_y;	/* y_wert to */
		pla[6]+=w;
		pla[7]+=h;
		vro_cpyfm(x_handle, S_ONLY, pla, &Map_bild, screen);
	}

	if(draw_cursor){
		v_set_line(curs_col,1,1,0,0);
		pla[0]=pla[2]=win->work.g_x+scroll_map.px_hline*(map_cursx-scroll_map.hpos);
		pla[1]=pla[3]=win->work.g_y+scroll_map.px_vline*(map_cursy-scroll_map.vpos);
		pla[2]+=scroll_map.px_hline-1;
		pla[3]+=scroll_map.px_vline-1;
		v_rect(pla[0],pla[1],pla[2],pla[3]);
	}
}

static int draw_titel(PARMBLK *pb){
	static int pla[8];
	GRECT work=*(GRECT *) &pb->pb_x;

	if(rc_intersect((GRECT *)&pb->pb_xc,&work)){
		pla[0]=pla[1]=0;
		pla[2]=pb->pb_w-1;
		pla[3]=pb->pb_h-1;
		pla[6]=pla[4]=pb->pb_x;	/* x_wert to */
		pla[7]=pla[5]=pb->pb_y;	/* y_wert to */
		pla[6]+=pb->pb_w-1;
		pla[7]+=pb->pb_h-1;

		vro_cpyfm(x_handle, S_ONLY, pla, &Titel_bild, screen);
	}

	return(0);
}

static int draw_lines(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;

	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		char **ptr;
		int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y);

		v_set_mode((text_font.cw&7)==0 && text_font.prop==0 ? MD_REPLACE : MD_TRANS);

/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])	*/
		v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL);
		start_line /= text_font.ch;
		y+=start_line*text_font.ch;
		x-=(int)scroll_menu.px_hpos;
		ptr=&text_lines[start_line+=scroll_menu.vpos];
		start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line);
		area.g_h=text_font.ch;
		Vsync();
/*		x=(x+7) & ~7;*/
		for(;--start_line>=0;y+=text_font.ch){
			area.g_y=y;
			my_clear_area(&area);
			if(**ptr-1){
				v_set_text(FAIL,0,BLUE,0x01,0,NULL);
				(*v_mtext)(x_handle,x,y,(*ptr++)+1);
				v_set_text(FAIL,0,BLACK,0x00,0,NULL);
			}else
				(*v_mtext)(x_handle,x,y,(*ptr++)+1);
		}
	}
	return(0);
}

static int draw_rip(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;
	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		char **ptr;
		int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y), chardim[4], pla[8],i;
		v_set_mode(MD_REPLACE);
/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])	*/
		v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim);
		start_line /= text_font.ch;
		y+=start_line*text_font.ch;
		x-=scroll_menu.px_hpos;
		ptr=&text_lines[start_line+=scroll_menu.vpos];
		start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line);
		area.g_h=text_font.ch;
		Vsync();
		x=(x+7) & ~7;
		for(;--start_line>=0;y+=text_font.ch){
			area.g_y=y;
			my_clear_area(&area);
			if(**ptr-1){
				v_set_text(FAIL,0,BLUE,0x01,0,NULL);
				(*v_mtext)(x_handle,x,y,(*ptr++)+1);
				v_set_text(FAIL,0,BLACK,0x00,0,NULL);
			}else
				(*v_mtext)(x_handle,x,y,(*ptr++)+1);
		}
		pla[0]=pla[1]=0;
		pla[2]=min(pb->pb_w-1,Rip_bild.fd_w-1);
		pla[3]=min(pb->pb_h-1,Rip_bild.fd_h-1);
		pla[6]=pla[4]=pb->pb_x+(pb->pb_w-Rip_bild.fd_w)/2;	/* x_wert to */
		pla[7]=pla[5]=pb->pb_y;	/* y_wert to */
		pla[6]+=pla[2];
		pla[7]+=pla[3];
		vro_cpyfm(x_handle, S_ONLY, pla, &Rip_bild, screen);
		v_set_mode(MD_TRANS);
		vst_alignment(x_handle,1,5,&i,&i);
		pla[5]+=64;
		for(i=0;i<7;i++,pla[5]+=chardim[3]){
			v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,WHITE,1,0,chardim);
			(*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]);
			v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,BLACK,0,0,chardim);
			(*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]);
		}
		vst_alignment(x_handle,0,5,&i,&i);
	}
	return(0);
}

static int draw_msgline(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;

	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		int x=pb->pb_x, y=pb->pb_y+(msg_vis-1)*msg_font.ch, foo, i;
		char **ptr=&message_line[msg_pos], tmp;
		int startx, stopx, starty, stopy;

		x=(x+7) & ~7;	/* Byte alignment speeds output up */

		v_set_mode(MD_REPLACE);

/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])	*/
		v_set_text(msg_font.id,msg_font.size,FAIL, FAIL,0,NULL);
		vst_alignment(x_handle,0,5,&foo,&foo);
		stopy=min(msg_pos,msg_vis);
/*		Vsync();*/
		startx=(area.g_x-x)/msg_font.cw-1;	/* MAR 06.02.2001 -- because italic covers the next char */
		Max(&startx,0);
		stopx=(area.g_x+area.g_w+msg_font.cw-x-1)/msg_font.cw;
		x+=startx*msg_font.cw;
		for(i=0;i<stopy;i++,y-=msg_font.ch,ptr--){
			if(message_age[msg_pos-i])
				v_set_text(FAIL,0,BLACK,0,0,NULL);
			else
				v_set_text(FAIL,0,LBLACK,4,0,NULL);
			tmp=(*ptr)[stopx];
			(*ptr)[stopx]=0;
			(*v_mtext)(x_handle,x,y,&(*ptr)[startx]);
			(*ptr)[stopx]=tmp;
		}
	}
	return(0);
}

static int draw_status(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;

	area.g_x+=2*status_font.cw-2;
	area.g_w-=2*status_font.cw-2;
	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		int x=pb->pb_x, y=pb->pb_y, startx, stopx, starty, stopy, i;
		char tmp;

/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])	*/
		v_set_mode(MD_REPLACE);
		v_set_text(status_font.id,status_font.size,BLACK,0,0,NULL);
		x = (x+2*status_font.cw+6) & ~7;

		startx=(area.g_x-x)/status_font.cw;
		starty=(area.g_y-y)/status_font.ch;
		stopx=(area.g_x+area.g_w+status_font.ch-1-x)/status_font.cw;
		stopy=(area.g_y+area.g_h+status_font.ch-1-y)/status_font.ch;
		Max(&startx,0);	/* MAR -- Hmm, area.g_x could end up 1 below x */
		Max(&stopx,0);
		x+=startx*status_font.cw;
		y+=starty*status_font.ch;
/*		Vsync();*/
		area.g_h=status_font.ch;
		for(i=starty;i<min(2,stopy);i++,area.g_y+=status_font.ch,y+=status_font.ch){
		my_clear_area(&area);
			tmp=status_line[i][stopx];
			status_line[i][stopx]=0;
			(*v_mtext)(x_handle,x,y,&status_line[i][startx]);
			status_line[i][stopx]=tmp;
		}
	}
	return(0);
}

static int draw_inventory(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;

	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		int gl, i, x=pb->pb_x, y=pb->pb_y,start_line=area.g_y-y;
		Gem_menu_item *it;

		v_set_mode(MD_REPLACE);
		v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL);

		start_line /= menu_font.ch;
		y+=start_line*menu_font.ch;
		x-=scroll_menu.px_hpos;
		start_line+=scroll_menu.vpos;

		for(it=invent_list,i=start_line; --i>=0 && it; it=it->Gmi_next);

		i = min((area.g_y-y+area.g_h+menu_font.ch-1)/menu_font.ch,Anz_inv_lines-start_line);

		Vsync();
		area.g_h=menu_font.ch;

		for(;(--i>=0) && it;it=it->Gmi_next,y+=menu_font.ch){
			if(it->Gmi_attr)
				v_set_text(FAIL,FALSE,BLUE,1,FAIL,NULL);	/* Bold */
			else
				v_set_text(FAIL,FALSE,BLACK,0,FAIL,NULL);

			area.g_y=y;
			my_clear_area(&area);
			if((gl=it->Gmi_glyph) != no_glyph){
				int pla[8], h=min(menu_font.ch,Tile_heigth)-1;

				pla[0]=pla[2]=(gl%Tiles_per_line)*Tile_width;	/* x_wert from */
				pla[1]=pla[3]=(gl/Tiles_per_line)*Tile_heigth;	/* y_wert from */
				pla[4]=pla[6]=x;				/* x_wert to */
				pla[5]=pla[7]=y;				/* y_wert to */
				pla[2]+=Tile_width-1;
				pla[3]+=h;
				pla[6]+=Tile_heigth-1;
				pla[7]+=h;

				vro_cpyfm(x_handle,S_ONLY,pla,&Tile_bilder,screen);
			}
			if(it->Gmi_identifier)
				it->Gmi_str[2]=it->Gmi_selected ? (it->Gmi_count == -1L ? '+' : '#') : '-';
			(*v_mtext)(x_handle,(x+23) & ~7,y,it->Gmi_str);
		}
	}
	return(0);
}

static int draw_prompt(PARMBLK *pb){
	GRECT area=*(GRECT *) &pb->pb_x;

	if(rc_intersect((GRECT *)&pb->pb_xc,&area)){
		char **ptr=(char **)pb->pb_parm;
		int x=pb->pb_x, y=pb->pb_y, chardim[4];

/* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4])	*/
		v_set_mode(MD_TRANS);
		v_set_text(ibm_font_id,ibm_font,WHITE,0,0,chardim);
		Vsync();
		if(planes<4){
			int pxy[4];
			v_set_fill(BLACK,2,4,0);
			rc_grect_to_array(&area,pxy);
			v_bar(x_handle,pxy);
		}else
			my_color_area(&area,LWHITE);
		(*v_mtext)(x_handle,x,y,*(ptr++));
		if(*ptr)
			(*v_mtext)(x_handle,x,y+chardim[3],*ptr);
	}
	return(0);
}

static USERBLK ub_lines={draw_lines, 0L}, ub_msg={draw_msgline, 0L},
					ub_inventory={draw_inventory, 0L}, ub_titel={draw_titel, 0L},
					ub_status={draw_status, 0L}, ub_prompt={draw_prompt, 0L};

/**************************** rsc_funktionen *****************************/

void my_close_dialog(DIAINFO *dialog,boolean shrink_box){
	close_dialog(dialog,shrink_box);
	Event_Timer(0,0,TRUE);
}

void
mar_get_rsc_tree(obj_number, z_ob_obj)
int obj_number;
OBJECT **z_ob_obj;
{
   rsrc_gaddr( R_TREE, obj_number, z_ob_obj );
	fix_objects(*z_ob_obj,SCALING,0,0);
}

void mar_clear_map(void);

void
img_error(errnumber)
int errnumber;
{
	char buf[BUFSZ];

	switch(errnumber){
	case ERR_HEADER :
		sprintf(buf,"%s","[1][ Image Header | corrupt. ][ Oops ]");
		break;
	case ERR_ALLOC :
		sprintf(buf,"%s","[1][ Not enough | memory for | an image. ][ Oops ]");
		break;
	case ERR_FILE :
		sprintf(buf,"%s","[1][ The Image-file | is not available ][ Oops ]");
		break;
	case ERR_DEPACK :
		sprintf(buf,"%s","[1][ The Image-file | is corrupt ][ Oops ]");
		break;
	case ERR_COLOR :
		sprintf(buf,"%s","[1][ Number of colors | not supported ][ Oops ]");
		break;
	default:
		sprintf(buf,"[1][ img_error | strange error | number: %i ][ Hmm ]",errnumber);
		break;
	}
	form_alert(1,buf);
}

void mar_change_button_char(OBJECT *z_ob, int nr, char ch){
	*ob_get_text(z_ob,nr,0)=ch;
	ob_set_hotkey(z_ob,nr,ch);
}

void
mar_set_dir_keys()
{
	static int mi_numpad=FAIL;
	char mcmd[]="bjnh.lyku", npcmd[]="123456789", *p_cmd;

	if(mi_numpad!=mar_iflags_numpad()){
		OBJECT *z_ob=zz_oblist[DIRECTION];
		int i;
		mi_numpad=mar_iflags_numpad();
		ob_set_hotkey(z_ob,DIRDOWN,'>');
		ob_set_hotkey(z_ob,DIRUP,'<');
		p_cmd= mi_numpad ? npcmd : mcmd;
		for(i=0;i<9;i++)
			mar_change_button_char(z_ob,DIR1+2*i,p_cmd[i]);
	}
}

int
mar_gem_init()
{
	int i, bild_fehler=FALSE, fsize;
	char *fname;
	static MITEM wish_workaround= {FAIL,key(0,'J'),K_CTRL,W_CYCLE,FAIL};
	OBJECT *z_ob;

	if((i=open_rsc("gem_rsc.rsc",NULL,md,md,md,0,0,0))<=0){
		graf_mouse(M_OFF,NULL);
		if(i<0)
			form_alert(1,"[3][| Fatal Error | File: GEM_RSC.RSC | not found. ][ grumble ]");
		else
			form_alert(1,"[3][| Fatal Error | GEM initialisation | failed. ][ a pity ]");
		return(0);
	}
	if(planes<1 || planes>8){
		form_alert(1,"[3][ Color-depth | not supported, | try 2-256 colors. ][ Ok ]");
		return(0);
	}
	MouseBee();

	/* MAR -- 17.Mar 2002 NVDI 3.0 or better uses v_ftext */
	v_mtext= speedo==3 ? &v_ftext : &v_gtext;
	for(i=0;i<NHICON;i++)
		mar_get_rsc_tree(i, &zz_oblist[i]);

	z_ob=zz_oblist[ABOUT];
	ob_hide(z_ob,OKABOUT,TRUE);
	ob_draw_dialog(z_ob,0,0,0,0);

	mar_get_font(NHW_MESSAGE,&fname,&fsize);
	mar_set_font(NHW_MESSAGE,fname,fsize);
	mar_get_font(NHW_MAP,&fname,&fsize);
	mar_set_font(NHW_MAP,fname,fsize);
	mar_get_font(NHW_STATUS,&fname,&fsize);
	mar_set_font(NHW_STATUS,fname,fsize);
	mar_get_font(NHW_MENU,&fname,&fsize);
	mar_set_font(NHW_MENU,fname,fsize);
	mar_get_font(NHW_TEXT,&fname,&fsize);
	mar_set_font(NHW_TEXT,fname,fsize);
	msg_anz=mar_get_msg_history();
	mar_set_msg_visible(mar_get_msg_visible());
	msg_width=min(max_w/msg_font.cw-3,MSGLEN);

	if(max_w/status_font.cw<COLNO-1)
		mar_set_fontbyid(NHW_STATUS,small_font_id,-small_font);
	status_w=min(max_w/status_font.cw-3,MSGLEN);
	if(planes>0 && planes<9)
		normal_palette=(short *)m_alloc(3*colors*sizeof(short));
		get_colors(x_handle,normal_palette, colors);
	if(planes<4){
		bild_fehler=depack_img(Tilefile?Tilefile:"NH2.IMG",&tile_image);
	}else{
		bild_fehler=depack_img(Tilefile?Tilefile:"NH16.IMG",&tile_image);
		if(!bild_fehler)
			if(tile_image.planes>1)
				img_set_colors(x_handle, tile_image.palette, tile_image.planes);
#if 0
			else{
				int mypalette[]={};
				img_set_colors(x_handle, mypalette, 4);
			}
#endif
	}

	if(bild_fehler ){
		z_ob=zz_oblist[ABOUT];
		ob_undraw_dialog(z_ob,0,0,0,0);
		ob_hide(z_ob,OKABOUT,FALSE);
		img_error(bild_fehler);
		return(0);
	}

	mfdb(&Tile_bilder, (int *)tile_image.addr, tile_image.img_w, tile_image.img_h, 1, tile_image.planes);
	transform_img(&Tile_bilder);

	mfdb(&Map_bild,NULL,(COLNO-1)*Tile_width, ROWNO*Tile_heigth, 0, planes);
	mfdb(&FontCol_Bild,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes);
	Map_bild.fd_addr=(int *)m_alloc(mfdb_size(&Map_bild)>mfdb_size(&FontCol_Bild)?mfdb_size(&Map_bild):mfdb_size(&FontCol_Bild));
	FontCol_Bild.fd_addr=Map_bild.fd_addr;

	mfdb(&Pet_Mark,pet_mark_data,8, 7, 1, 1);
	vr_trnfm(x_handle,&Pet_Mark,&Pet_Mark);

	mfdb(&Black_bild,NULL,16, 32, 1, 1);	/* MAR -- 17.Mar 2002 that should cover the biggest map-font */
	Black_bild.fd_addr=(int *)m_alloc(mfdb_size(&Black_bild));
	memset(Black_bild.fd_addr,255,mfdb_size(&Black_bild));
	vr_trnfm(x_handle,&Black_bild,&Black_bild);

	for(i=0;i<MAXWIN;i++){
		Gem_nhwindow[i].gw_window=NULL;
		Gem_nhwindow[i].gw_type=0;
		Gem_nhwindow[i].gw_dirty=TRUE;
	}

	memset(&scroll_menu,0,sizeof(scroll_menu));
	scroll_menu.scroll=AUTO_SCROLL;
	scroll_menu.obj=LINESLIST;
	scroll_menu.px_hline=menu_font.cw;
	scroll_menu.px_vline=menu_font.ch;
	scroll_menu.hscroll=
	scroll_menu.vscroll=1;
	scroll_menu.tbar_d=2*gr_ch-2;

	mar_set_dir_keys();

	memset(&scroll_map,0,sizeof(scroll_map));
	scroll_map.scroll=AUTO_SCROLL;
	scroll_map.obj=ROOT;
	scroll_map.px_hline=mar_set_tile_mode(FAIL)?Tile_width:map_font.cw;
	scroll_map.px_vline=mar_set_tile_mode(FAIL)?Tile_heigth:map_font.ch;
	scroll_map.hsize=COLNO-1;
	scroll_map.vsize=ROWNO;
	scroll_map.hpage=8;
	scroll_map.vpage=8;
	scroll_map.hscroll=1;
	scroll_map.vscroll=1;

	/* dial_options( round, niceline, standard, return_default, background, nonselectable,
		always_keys, toMouse, clipboard, hz);	*/
	dial_options(TRUE,TRUE,FALSE,RETURN_DEFAULT,AES_BACK,TRUE,KEY_ALWAYS,FALSE,TRUE,3);
	/*	dial_colors( dial_pattern, dial_color, dial_frame, hotkey, alert, cycle_button,
		check_box, radio_button, arrow, cycle_backgrnd, check_backgrnd, radio_backgrnd,
		arrow_backgrnd, edit_3d, draw_3d)	*/
	if(planes<4)
		dial_colors(4,BLACK,WHITE,RED,RED,WHITE,BLACK,BLACK,BLACK,FAIL,FAIL,FAIL,FAIL,TRUE,TRUE);
	else
		dial_colors(7,LWHITE,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);

	/* void MenuItems(MITEM *close,MITEM *closeall,MITEM *cycle,MITEM *invcycle,
		MITEM *globcycle,MITEM *full,MITEM *bottom,MITEM *iconify,MITEM *iconify_all,
		MITEM *menu,int menu_cnt) */
	/* Ctrl-W ist normaly bound to cycle */
	MenuItems(NULL,NULL,&wish_workaround,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);

	menu_install(zz_oblist[MENU],TRUE);

	z_ob=zz_oblist[ABOUT];
	ob_undraw_dialog(z_ob,0,0,0,0);
	ob_hide(z_ob,OKABOUT,FALSE);

	return(1);
}

/************************* mar_exit_nhwindows *******************************/

void
mar_exit_nhwindows()
{
	int i;

	for(i=MAXWIN;--i>=0;)
		if(Gem_nhwindow[i].gw_type)
			mar_destroy_nhwindow(i);

	if(normal_palette){
		img_set_colors(x_handle,normal_palette,tile_image.planes);
		null_free(normal_palette);
	}
	test_free(tile_image.palette);
	test_free(tile_image.addr);
	test_free(titel_image.palette);
	test_free(titel_image.addr);
}

/************************* mar_curs *******************************/

void
mar_curs(x,y)
int x, y;
{
	Min(&dirty_map_area.g_x,x);
	Min(&dirty_map_area.g_y,y);
	Max(&dirty_map_area.g_w,x);
	Max(&dirty_map_area.g_h,y);
	Min(&dirty_map_area.g_x,map_cursx);
	Min(&dirty_map_area.g_y,map_cursy);
	Max(&dirty_map_area.g_w,map_cursx);
	Max(&dirty_map_area.g_h,map_cursy);

	map_cursx=x;
	map_cursy=y;

	if(WIN_MAP!=WIN_ERR)
		Gem_nhwindow[WIN_MAP].gw_dirty=TRUE;
}

void mar_cliparound(void);
void mar_map_curs_weiter(void)
{
	mar_curs(map_cursx+1,map_cursy);
	mar_cliparound();
}

/************************* about *******************************/

void
mar_about()
{
	xdialog(zz_oblist[ABOUT], md, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE);
	Event_Timer(0,0,TRUE);
}

/************************* ask_name *******************************/

char *
mar_ask_name()
{
	OBJECT *z_ob=zz_oblist[NAMEGET];
	int bild_fehler;
	char who_are_you[] = "Who are you? ";

	bild_fehler=depack_img(planes<4 ? "TITLE2.IMG" : "TITLE.IMG", &titel_image);
	if(bild_fehler ){	/* MAR -- this isn't lethal */
		ob_set_text(z_ob,NETHACKPICTURE,"missing title.img.");
	}else{
		mfdb(&Titel_bild, (int *)titel_image.addr, titel_image.img_w, titel_image.img_h, 1, titel_image.planes);
		transform_img(&Titel_bild);
		z_ob[NETHACKPICTURE].ob_type=G_USERDEF;
		z_ob[NETHACKPICTURE].ob_spec.userblk=&ub_titel;
	}

	ob_clear_edit(z_ob);
	xdialog(z_ob,who_are_you, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE);
	Event_Timer(0,0,TRUE);

	test_free(titel_image.palette);
	test_free(titel_image.addr);
	test_free(Titel_bild.fd_addr);
	return(ob_get_text(z_ob,PLNAME,0));
}

/************************* more *******************************/

void
send_key(int key)
{
	int buf[8];

	buf[3]=0;	/* No Shift/Ctrl/Alt */
	buf[4]=key;
	AvSendMsg(ap_id,AV_SENDKEY,buf);
}

void
send_return()
{
	send_key(key(SCANRET,0));
}

int
K_Init(xev,availiable)
XEVENT *xev;
int availiable;
{
	xev=xev;
	return(MU_KEYBD&availiable);
}

int
KM_Init(xev,availiable)
XEVENT *xev;
int availiable;
{
	xev=xev;
	return((MU_KEYBD|MU_MESAG)&availiable);
}

int
M_Init(xev,availiable)
XEVENT *xev;
int availiable;
{
	xev=xev;
	return(MU_MESAG&availiable);
}

#define More_Init K_Init

int
More_Handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;

	if(ev&MU_KEYBD){
		char ch=(char)(xev->ev_mkreturn&0x00FF);
		DIAINFO *dinf;
		WIN *w;

		switch(ch){
		case '\033':	/* no more more more */
		case ' ':
			if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[PAGER]){
				if(ch=='\033')
					mar_esc_pressed=TRUE;
				send_return();
			break;
			}
			/* Fall thru */
		default:
			ev &= ~MU_KEYBD;	/* unknown key */
			break;
		}
	}
	return(ev);
}

void
mar_more()
{
	if(!mar_esc_pressed){
		OBJECT *z_ob=zz_oblist[PAGER];
		WIN *p_w;

		Event_Handler(More_Init,More_Handler);
		dial_colors(7,RED,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);
		if(WIN_MESSAGE!=WIN_ERR && (p_w=Gem_nhwindow[WIN_MESSAGE].gw_window)){
			z_ob->ob_x=p_w->work.g_x;
			z_ob->ob_y=p_w->curr.g_y+p_w->curr.g_h+gr_ch;
		}
		xdialog(z_ob,NULL, NULL, NULL, DIA_LASTPOS, FALSE, DIALOG_MODE);
		Event_Timer(0,0,TRUE);
		Event_Handler(NULL,NULL);

		if(planes<4)
			dial_colors(4,BLACK,WHITE,RED,RED,WHITE,BLACK,BLACK,BLACK,FAIL,FAIL,FAIL,FAIL,TRUE,TRUE);
		else
			dial_colors(7,LWHITE,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE);
	}
}

/************************* Gem_start_menu *******************************/
void
Gem_start_menu(win)
winid win;
{
	win=win;
	if(invent_list){
		Gem_menu_item *curr, *next;

		for(curr=invent_list;curr;curr=next){
			next=curr->Gmi_next;
			free(curr->Gmi_str);
			free(curr);
		}
	}
	invent_list=NULL;
	Anz_inv_lines=0;
	Inv_breite=16;
}

/************************* mar_add_menu *******************************/

void
mar_add_menu(win, item)
winid win;
Gem_menu_item *item;
{
	win=win;
	item->Gmi_next = invent_list;
	invent_list = item;
	Anz_inv_lines++;
}

void
mar_reverse_menu()
{
	Gem_menu_item *next, *head = 0, *curr=invent_list;

	while (curr) {
		next = curr->Gmi_next;
		curr->Gmi_next = head;
		head = curr;
		curr = next;
	}
	invent_list=head;
}

void
mar_set_accelerators()
{
	char ch='a';
	Gem_menu_item *curr;

	for(curr=invent_list;curr;curr=curr->Gmi_next){
		int extent[8];
		v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL);
		vqt_extent(x_handle,curr->Gmi_str,extent);
		Max(&Inv_breite,extent[4]+Tile_width+menu_font.cw);
		if(ch && curr->Gmi_accelerator==0 && curr->Gmi_identifier){
			curr->Gmi_accelerator=ch;
			curr->Gmi_str[0]=ch;
			if(ch=='z') ch='A';
			else if(ch=='Z') ch=0;
			else ch++;
		}
	}
}

Gem_menu_item *
mar_hol_inv()
{
	return(invent_list);
}

/************************* mar_putstr_text *********************/

void mar_raw_print(const char *);

void mar_set_text_to_rip(winid w){
	use_rip=TRUE;
}
void
mar_putstr_text(winid window, int attr, const char *str)
{
	static int zeilen_frei=0;
	int breite;
	char *ptr;

	window=window;
	if(!text_lines){
		text_lines=(char **)m_alloc(12*sizeof(char *));
		zeilen_frei=12;
	}
	if(!zeilen_frei){
		text_lines=(char **)realloc(text_lines,(Anz_text_lines+12)*sizeof(char *));
		zeilen_frei=12;
	}
	if(!text_lines){
		mar_raw_print("No room for Text");
		return;
	}

	if(str)
		breite=strlen(str);
	Min(&breite,80);
	ptr=text_lines[Anz_text_lines]=(char *)m_alloc(breite*sizeof(char)+2);
	*ptr=(char)(attr+1);	/* avoid 0 */
	strncpy(ptr+1,str,breite);
	ptr[breite+1]=0;
	Anz_text_lines++;
	zeilen_frei--;
}

int
mar_set_inv_win(Anzahl, Breite)
int Anzahl, Breite;
{
	OBJECT *z_ob=zz_oblist[LINES];
	int retval=WIN_DIAL|MODAL|NO_ICONIFY;

	scroll_menu.hsize=0;
	scroll_menu.vpage= (desk.g_h-3*gr_ch)/scroll_menu.px_vline;
	if(Anzahl>scroll_menu.vpage){
		retval |= WD_VSLIDER;
		if(Breite>max_w-3*scroll_menu.px_hline){
			retval|=WD_HSLIDER;
			scroll_menu.hpage=(max_w-3*scroll_menu.px_hline)/scroll_menu.px_hline;
			scroll_menu.hpos=0;
			scroll_menu.hsize=Breite/scroll_menu.px_hline;
			scroll_menu.vpage=(desk.g_h-4*gr_ch-1)/scroll_menu.px_vline;
		}
		Anzahl=scroll_menu.vpage;
	}else{
		if(Breite>max_w-scroll_menu.px_hline){
			retval|=WD_HSLIDER;
			scroll_menu.hpage=(max_w-scroll_menu.px_hline)/scroll_menu.px_hline;
			scroll_menu.hpos=0;
			scroll_menu.hsize=Breite/scroll_menu.px_hline;
			scroll_menu.vpage= (desk.g_h-4*gr_ch-1)/scroll_menu.px_vline;
			if(Anzahl>scroll_menu.vpage){
				retval |= WD_VSLIDER;
				Anzahl=scroll_menu.vpage;
			}
		}
		scroll_menu.vpage=Anzahl;
	}
	if((scroll_menu.hmax=scroll_menu.hsize-scroll_menu.hpage)<0)
		scroll_menu.hmax=0;
	if((scroll_menu.vmax=scroll_menu.vsize-scroll_menu.vpage)<0)
		scroll_menu.vmax=0;

	/* left/right/up 2 pixel border down 2gr_ch toolbar */
	z_ob[ROOT].ob_width=z_ob[LINESLIST].ob_width=Breite;
	z_ob[ROOT].ob_height=
	z_ob[QLINE].ob_y=
	z_ob[LINESLIST].ob_height=scroll_menu.px_vline*Anzahl;
	z_ob[QLINE].ob_y+=gr_ch/2;
	z_ob[ROOT].ob_width+=4;
	z_ob[ROOT].ob_height+=2*gr_ch+2;

	return(retval);
}

/************************* mar_status_dirty *******************************/

void
mar_status_dirty()
{
	int ccol;

	ccol=mar_hp_query();

	if(ccol<2)	curs_col=WHITE;		/* 50-100% : 0 */
	else if(ccol<3)	curs_col=YELLOW;		/* 33-50% : 6 */
	else if(ccol<5)	curs_col=LYELLOW;		/* 20-33% : 14*/
	else if(ccol<10)	curs_col=RED;		/* 10-20% : 2 */
	else	curs_col=MAGENTA;		/* <10% : 7*/
}

/************************* mar_add_message *******************************/

void
mar_add_message(str)
const char *str;
{
	int i, mesg_hist=mar_get_msg_history();
	char *tmp, *rest, buf[TBUFSZ];

	if(WIN_MESSAGE == WIN_ERR)
		return;

	if(!mar_message_pause){
		mar_message_pause=TRUE;
		messages_pro_zug=0;
		msg_pos=msg_max;
	}

	if(msg_max>mesg_hist-2){
		msg_max=mesg_hist-2;
		msg_pos--;
		if(msg_pos<0) msg_pos=0;
		tmp=message_line[0];
		for(i=0;i<mesg_hist-1;i++){
			message_line[i]=message_line[i+1];
			message_age[i]=message_age[i+1];
		}
		message_line[mesg_hist-1]=tmp;
	}
	strcpy(toplines,str);
	messages_pro_zug++;
	msg_max++;

	if((int)strlen(toplines)>=msg_width){
		int pos=msg_width;
		tmp=toplines+msg_width;
		while(*tmp!=' ' && pos>=0){
			tmp--;
			pos--;
		}
		if(pos<=0) pos=msg_width;	/* Mar -- Oops, what a word :-) */
		message_age[msg_max]=TRUE;
		strncpy(message_line[msg_max],toplines,pos);
		message_line[msg_max][pos]=0;
		rest=strcpy(buf,toplines+pos);
	}else{
		message_age[msg_max]=TRUE;
		strncpy(message_line[msg_max],toplines,msg_width);
		rest=0;
	}

	Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
	if(messages_pro_zug>=mesg_hist){ /* MAR -- Greater then should never happen */
		messages_pro_zug=mesg_hist;
		mar_display_nhwindow(WIN_MESSAGE);
	}

	if(rest)
		mar_add_message(rest);
}

/************************* mar_add_status_str *******************************/

void
mar_add_status_str(str,line)
const char *str;
int line;
{
	int i,last_diff=-1;
	GRECT area={0,line*status_font.ch,status_font.cw,status_font.ch};
	for(i=0;(i<status_w-2) && str[i];i++)
		if(str[i]!=status_line[line][i]){
			if(last_diff==-1) area.g_x=i*status_font.cw;
			else area.g_w+=status_font.cw;
			last_diff=i;
			status_line[line][i]=str[i];
		}else if(last_diff>=0){
			add_dirty_rect(dr_stat,&area);
			last_diff=-1;
			area.g_w=status_font.cw;
		}
		for(;i<status_w-1;i++){
			if(status_line[line][i]){
				if(last_diff==-1) area.g_x=i*status_font.cw;
				else area.g_w+=status_font.cw;
				last_diff=i;
			}
			status_line[line][i]=0;
		}
	if(last_diff>=0)
		add_dirty_rect(dr_stat,&area);
}

/************************* mar_set_menu_title *******************************/

void
mar_set_menu_title(str)
const char *str;
{
	test_free(Menu_title);	/* just in case */
	Menu_title=mar_copy_of(str ? str : nullstr);
}

/************************* mar_set_menu_type *******************************/

void
mar_set_menu_type(how)
int how;
{
	Inv_how=how;
}

/************************* Inventory Utils *******************************/

void
set_all_on_page(start, page)
int start, page;
{
	Gem_menu_item *curr;

	if(start<0 || page<0)
		return;

	for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
	for(; page--&&curr; curr=curr->Gmi_next)
		if (curr->Gmi_identifier && !curr->Gmi_selected)
			curr->Gmi_selected = TRUE;
}

void
unset_all_on_page(start, page)
int start, page;
{
	Gem_menu_item *curr;

	if(start<0 || page<0)
		return;

	for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
	for(; page--&&curr; curr=curr->Gmi_next)
		if (curr->Gmi_identifier && curr->Gmi_selected) {
			curr->Gmi_selected = FALSE;
			curr->Gmi_count = -1L;
		}
}

void
invert_all_on_page(start, page, acc)
int start, page;
char acc;
{
	Gem_menu_item *curr;

	if(start<0 || page<0)
		return;

	for(curr=invent_list; start--&&curr; curr=curr->Gmi_next);
	for(; page--&&curr; curr=curr->Gmi_next)
		if (curr->Gmi_identifier && (acc == 0 || curr->Gmi_groupacc == acc)) {
			if (curr->Gmi_selected) {
				curr->Gmi_selected = FALSE;
				curr->Gmi_count = -1L;
			} else
				curr->Gmi_selected = TRUE;
		}
}

/************************* Inv_Handler and Inv_Init *******************************/

int scroll_top_dialog(char ch){
	WIN *w;
	DIAINFO *dinf;

	if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[LINES]){
		switch(ch){
		case ' ':
			if(scroll_menu.vpos==scroll_menu.vmax){
				send_return();
				break;
			}
			/* Fall thru */
		case MENU_NEXT_PAGE:
			scroll_window(w,PAGE_DOWN,NULL);
			break;
		case MENU_PREVIOUS_PAGE:
			scroll_window(w,PAGE_UP,NULL);
			break;
		case MENU_FIRST_PAGE:
			scroll_window(w,WIN_START,NULL);
			break;
		case MENU_LAST_PAGE:
			scroll_window(w,WIN_END,NULL);
			break;
		default:
			return(FALSE);
		}
		return(TRUE);
	}
	return(FALSE);
}

#define Text_Init KM_Init

int
Text_Handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;

	if(ev&MU_MESAG){
		int *buf=xev->ev_mmgpbuf, y_wo, i;
		if(*buf==FONT_CHANGED){
			if(buf[3]>=0){
				mar_set_fontbyid(NHW_TEXT,buf[4],buf[5]);
				FontAck(buf[1],1);
			}
		}
	}
	if(ev&MU_KEYBD){
		char ch=(char)(xev->ev_mkreturn&0x00FF);

		if(!scroll_top_dialog(ch))
			switch(ch){
			case '\033':
				send_return();	/* just closes the textwin */
				break;
			case C('c'):
				clipbrd_save(text_lines,Anz_text_lines,xev->ev_mmokstate&K_SHIFT,FALSE);
				break;
			default:
				ev &= ~MU_KEYBD;	/* unknown key */
				break;
			}
	}
	return(ev);
}

#define Inv_Init KM_Init

static long count=0;
int
Inv_Handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;
	Gem_menu_item *it;
	GRECT area;
	OBJECT *z_ob=zz_oblist[LINES];

	ob_pos(z_ob,LINESLIST,&area);
	if(ev&MU_MESAG){
		int *buf=xev->ev_mmgpbuf, y_wo, i;

		if(*buf==FONT_CHANGED){
			if(buf[3]>=0){
				mar_set_fontbyid(NHW_MENU,buf[4],buf[5]);
				FontAck(buf[1],1);
			}
		}else
		if(*buf==OBJC_CHANGED && buf[3]==LINESLIST){
			ob_undostate(z_ob,LINESLIST,SELECTED);
			mouse(NULL,&y_wo);
			y_wo=(y_wo-area.g_y)/menu_font.ch+scroll_menu.vpos;
			for(it=invent_list,i=0;i<y_wo && it;it=it->Gmi_next,i++);
			if(it->Gmi_identifier){
				it->Gmi_selected=!it->Gmi_selected;
				it->Gmi_count= count==0L ? -1L : count;
				count = 0L;
				if(Inv_how!=PICK_ANY){
					/*my_close_dialog(Inv_dialog,TRUE);*/
					send_return();
				}else{
					area.g_x=(area.g_x+23+2*menu_font.cw) & ~7;
					area.g_w=menu_font.cw;
					area.g_h=menu_font.ch;
					area.g_y+=(y_wo-scroll_menu.vpos)*menu_font.ch;
					ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL);
				}	/* how != PICK_ANY */
			}	/* identifier */
		}else	/* LINESLIST changed */
			ev &= ~MU_MESAG;	/* unknown message not used */
	}	/* MU_MESAG */

	if(ev&MU_KEYBD){
		char ch=(char)(xev->ev_mkreturn&0x00FF);

		if(!scroll_top_dialog(ch)){
			switch(ch){
			case '0':	/* special 0 is also groupaccelerator for balls */
				if(count<=0)
					goto find_acc;
			case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				if(Inv_how==PICK_NONE)
					goto find_acc;
				count = (count * 10L) + (long) (ch - '0');
				break;
			case '\033':	/* cancel - from counting or loop */
				if(count>0L)
				count=0L;
				else{
					unset_all_on_page(0, (int)scroll_menu.vsize);
					my_close_dialog(Inv_dialog,TRUE);
					return(ev);
				}
				break;
			case '\0':		/* finished (commit) */
			case '\n':
			case '\r':
				break;
			case MENU_SELECT_PAGE:
				if(Inv_how==PICK_NONE)
					goto find_acc;
				if (Inv_how == PICK_ANY)
					set_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage);
				break;
			case MENU_SELECT_ALL:
				if(Inv_how==PICK_NONE)
					goto find_acc;
				if (Inv_how == PICK_ANY)
					set_all_on_page(0, (int)scroll_menu.vsize);
				break;
			case MENU_UNSELECT_PAGE:
				unset_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage);
				break;
			case MENU_UNSELECT_ALL:
				unset_all_on_page(0, (int)scroll_menu.vsize);
				break;
			case MENU_INVERT_PAGE:
				if(Inv_how==PICK_NONE)
					goto find_acc;
				if (Inv_how == PICK_ANY)
					invert_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage, 0);
				break;
			case MENU_INVERT_ALL:
				if(Inv_how==PICK_NONE)
					goto find_acc;
				if (Inv_how == PICK_ANY)
					invert_all_on_page(0, (int)scroll_menu.vsize, 0);
				break;
			case MENU_SEARCH:
				if(Inv_how!=PICK_NONE){
					char buf[BUFSZ];
					Gem_getlin("Search for:",buf);
					if(!*buf || buf[0]=='\033')
						break;
					for(it=invent_list;it;it=it->Gmi_next){
						if(it->Gmi_identifier && strstr(it->Gmi_str,buf)){
							it->Gmi_selected=TRUE;
							if(Inv_how!=PICK_ANY){
								my_close_dialog(Inv_dialog,FALSE);
								break;
							}
						}
					}
				}
				break;
			case C('c'):
				clipbrd_save(invent_list,Anz_inv_lines,xev->ev_mmokstate&K_SHIFT,TRUE);
				break;
			default:
			find_acc:
				if(Inv_how==PICK_NONE)
					my_close_dialog(Inv_dialog,TRUE);
				else
					for(it=invent_list;it;it=it->Gmi_next){
						if(it->Gmi_identifier && (it->Gmi_accelerator==ch || it->Gmi_groupacc==ch)){
							it->Gmi_selected=!it->Gmi_selected;
							it->Gmi_count= count==0L ? -1L : count;
							count = 0L;
							if(Inv_how!=PICK_ANY)
								my_close_dialog(Inv_dialog,TRUE);
						}
					}
				break;
			}	/* end switch(ch) */
			if(Inv_how==PICK_ANY){
				area.g_x=(area.g_x+23+2*menu_font.cw) & ~7;
				area.g_w=menu_font.cw;
				ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL);
			}
		}	/* !scroll_Inv_dialog */
	}	/* MU_KEYBD */

	if(Inv_how==PICK_ANY){
		ob_set_text(Inv_dialog->di_tree,QLINE,strCancel);
		for(it=invent_list;it;it=it->Gmi_next)
			if(it->Gmi_identifier && it->Gmi_selected){
				ob_set_text(Inv_dialog->di_tree,QLINE,strOk);
				break;
			}
		ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL);
	}
	return(ev);
}

/************************* draw_window *******************************/

static void
mar_draw_window( first, win, area)
int first;
WIN *win;
GRECT *area;
{
	OBJECT *obj=(OBJECT *)win->para;

	if(obj){
		if(first){
		obj->ob_x=win->work.g_x;
		obj->ob_y=win->work.g_y;
		}
		if(area==NULL)
			area=&(win->work);
		objc_draw(obj, ROOT, MAX_DEPTH, area->g_x, area->g_y, area->g_w, area->g_h);
	}
}

/************************* mar_display_nhwindow *******************************/

void redraw_winwork(WIN *w,GRECT *area){
	area->g_x+=w->work.g_x;
	area->g_y+=w->work.g_y;
	redraw_window(w,area);
}
void mar_menu_set_slider(WIN *p_win){
	if(p_win){
		SCROLL *sc=p_win->scroll;

		if(!sc)
			return;

		if(p_win->gadgets&HSLIDE){
			long hsize=1000l;

			if(sc->hsize>0 && sc->hpage>0){
				hsize *= sc->hpage;
				hsize /= sc->hsize;
			}
			window_slider(p_win,HOR_SLIDER,0,(int)hsize);
		}
		if(p_win->gadgets&VSLIDE){
			long vsize=1000l;

			if(sc->vsize>0 && sc->vpage>0){
				vsize *= sc->vpage;
				vsize /= sc->vsize;
			}
			window_slider(p_win,VERT_SLIDER,0,(int)vsize);
		}
	}
}

void recalc_msg_win(GRECT *area){
	OBJECT *z_ob;
	z_ob=zz_oblist[MSGWIN];
	z_ob[MSGLINES].ob_spec.userblk=&ub_msg;
	z_ob[MSGLINES].ob_width=
	z_ob[ROOT].ob_width=		(msg_width+3)*msg_font.cw;
	z_ob[MSGLINES].ob_width-=z_ob[UPMSG].ob_width;
	z_ob[ROOT].ob_height=
	z_ob[GRABMSGWIN].ob_height=
	z_ob[MSGLINES].ob_height=msg_vis*msg_font.ch;
	z_ob[DNMSG].ob_y=z_ob[GRABMSGWIN].ob_height-z_ob[DNMSG].ob_height;
	window_border(0,0,0,z_ob->ob_width,z_ob->ob_height, area);
}
void recalc_status_win(GRECT *area){
	OBJECT *z_ob;
	z_ob=zz_oblist[STATUSLINE];
	z_ob[ROOT].ob_type=G_USERDEF;
	z_ob[ROOT].ob_spec.userblk=&ub_status;
	z_ob[ROOT].ob_width=(status_w+2)*status_font.cw;
	z_ob[ROOT].ob_height=
	z_ob[GRABSTATUS].ob_height=2*status_font.ch;
	z_ob[GRABSTATUS].ob_width=2*status_font.cw-2;
	window_border(0,0,0,z_ob->ob_width,z_ob->ob_height,area);
}
void calc_std_winplace(int which, GRECT *place){
	static int todo=TRUE;
	static GRECT me, ma, st;

	if(todo || which<0){
		OBJECT *z_ob;
		int map_h_off, foo;

		/* First the messagewin */
		recalc_msg_win(&me);

		/* Now the map */
		wind_calc(WC_BORDER,MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO,&foo,&foo,&foo,&map_h_off);
		map_h_off-=scroll_map.px_vline*ROWNO;
		window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &ma);

		/* Next the statuswin */
		recalc_status_win(&st);

		/* And last but not least a final test */
		ma.g_h=map_h_off+scroll_map.px_vline*ROWNO;
		while(me.g_h+ma.g_h+st.g_h>=desk.g_h)
			ma.g_h-=scroll_map.px_vline;
		/* stack the windows */
		ma.g_y=me.g_y=st.g_y=desk.g_y;
		if(status_align){
			ma.g_y+=st.g_h;
			if(msg_align){
				st.g_y+=me.g_h;
				ma.g_y+=me.g_h;
			}else{
				me.g_y+=st.g_h+ma.g_h;
			}
		}else{
			if(msg_align){
				ma.g_y+=me.g_h;
			}else{
				me.g_y+=ma.g_h;
			}
			st.g_y+=me.g_h+ma.g_h;
		}

		if(which) todo=FALSE;
	}
	switch(which){
	case NHW_MESSAGE:
		*place=me;
		break;
	case NHW_MAP:
		*place=ma;
		break;
	case NHW_STATUS:
		*place=st;
		break;
	default:
		break;
	}
}

void
mar_display_nhwindow(wind)
winid wind;
{
	DIAINFO *dlg_info;
	OBJECT *z_ob;
	int d_exit=W_ABANDON, i, breite, mar_di_mode, tmp_magx=magx;
	GRECT g_mapmax, area;
	char *tmp_button;
	struct gw *p_Gw;

	if(wind == WIN_ERR)	return;

	p_Gw=&Gem_nhwindow[wind];
	switch(p_Gw->gw_type){
	case NHW_TEXT:
		if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
			mar_display_nhwindow(WIN_MESSAGE);
		z_ob=zz_oblist[LINES];
		scroll_menu.vsize=Anz_text_lines;
		scroll_menu.vpos=0;
		if(use_rip){
			if(!depack_img(planes<4 ? "RIP2.IMG" : "RIP.IMG", &rip_image)){
				mfdb(&Rip_bild, (int *)rip_image.addr, rip_image.img_w, rip_image.img_h, 1, rip_image.planes);
				transform_img(&Rip_bild);
			}
			ub_lines.ub_code=draw_rip;
		}else
			ub_lines.ub_code=draw_lines;
		z_ob[LINESLIST].ob_spec.userblk=&ub_lines;
		breite=16;
		v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL);
		for(i=0;i<Anz_text_lines;i++){
			int eout[8];
			vqt_extent(x_handle,text_lines[i],eout);
			Max(&breite,eout[4]);
		}
		scroll_menu.px_vline=text_font.ch;
		scroll_menu.px_hline=text_font.cw;
		mar_di_mode=mar_set_inv_win(Anz_text_lines, breite);
		tmp_button=ob_get_text(z_ob,QLINE,0);
		ob_set_text(z_ob,QLINE,strOk);
		ob_undoflag(z_ob,LINESLIST,TOUCHEXIT);
		Event_Handler(Text_Init,Text_Handler);
		if((dlg_info=open_dialog(z_ob,strText, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL))!=NULL){
			WIN *ptr_win=dlg_info->di_win;

			ptr_win->scroll=&scroll_menu;
			mar_menu_set_slider(ptr_win);
			WindowItems(ptr_win,SCROLL_KEYS,scroll_keys);
			if((d_exit=X_Form_Do(NULL))!=W_ABANDON){
				my_close_dialog(dlg_info,FALSE);
				if(d_exit!=W_CLOSED)
					ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED);
			}
		}
		Event_Handler(NULL,NULL);
		ob_set_text(z_ob,QLINE,tmp_button);
		break;
	case NHW_MENU:
		if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
			mar_display_nhwindow(WIN_MESSAGE);
		z_ob=zz_oblist[LINES];
		scroll_menu.vsize=Anz_inv_lines;
		scroll_menu.vpos=0;
		z_ob[LINESLIST].ob_spec.userblk=&ub_inventory;
		if((Menu_title)&&(wind!=WIN_INVEN))	/* because I sets no Menu_title */
			Max(&Inv_breite,gr_cw*strlen(Menu_title)+16);
		scroll_menu.px_vline=menu_font.ch;
		scroll_menu.px_hline=menu_font.cw;
		mar_di_mode=mar_set_inv_win(Anz_inv_lines, Inv_breite, NHW_MENU);
		tmp_button=ob_get_text(z_ob,QLINE,0);
		ob_set_text(z_ob,QLINE,Inv_how!=PICK_NONE ? strCancel : strOk );
		ob_doflag(z_ob,LINESLIST,TOUCHEXIT);
		Event_Handler(Inv_Init, Inv_Handler);
		if((Inv_dialog=open_dialog(z_ob,(wind==WIN_INVEN) ? "Inventory" : (Menu_title ? Menu_title : "Staun"), NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL))!=NULL){
			WIN *ptr_win=Inv_dialog->di_win;

			ptr_win->scroll=&scroll_menu;
			mar_menu_set_slider(ptr_win);
			WindowItems(ptr_win,SCROLL_KEYS,scroll_keys);
			do{
				int y_wo,x_wo,ru_w=1,ru_h=1;
				GRECT oarea;
				Gem_menu_item *it;
				d_exit=X_Form_Do(NULL);
				if((d_exit&NO_CLICK)==LINESLIST){
					ob_pos(z_ob,LINESLIST,&oarea);
					if(mouse(&x_wo,&y_wo) && Inv_how==PICK_ANY){
						graf_rt_rubberbox(FALSE,x_wo,y_wo,FAIL,FAIL,&oarea,&ru_w,&ru_h,NULL);
						invert_all_on_page((int)((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos),(ru_h+menu_font.ch-1)/menu_font.ch,0);
					}else{
						for(it=invent_list,i=0;i<((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos) && it;it=it->Gmi_next,i++);
						if(it && it->Gmi_identifier){
							it->Gmi_selected=!it->Gmi_selected;
							it->Gmi_count= count==0L ? -1L : count;
							count = 0L;
							if(Inv_how!=PICK_ANY)
								break;
						}	/* identifier */
					}
					oarea.g_x=(oarea.g_x+23+2*menu_font.cw) & ~7;
					oarea.g_y=y_wo-(y_wo-oarea.g_y)%menu_font.ch;
					oarea.g_w=menu_font.cw;
					oarea.g_h=((ru_h+menu_font.ch-1)/menu_font.ch)*menu_font.ch;
					ob_draw_chg(Inv_dialog,LINESLIST,&oarea,FAIL);
				}
				if(Inv_how==PICK_ANY){
					ob_set_text(Inv_dialog->di_tree,QLINE,strCancel);
					for(it=invent_list;it;it=it->Gmi_next)
						if(it->Gmi_identifier && it->Gmi_selected){
							ob_set_text(Inv_dialog->di_tree,QLINE,strOk);
							break;
						}
					ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL);
				}
			}while((d_exit&NO_CLICK)==LINESLIST);
			if(d_exit!=W_ABANDON){
				my_close_dialog(Inv_dialog,FALSE);
				if(d_exit!=W_CLOSED)
					ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED);
			}
		}
		Event_Handler(NULL,NULL);
		ob_set_text(z_ob,QLINE,tmp_button);
		break;
	case NHW_MAP:
		if(p_Gw->gw_window==NULL){
			calc_std_winplace(NHW_MAP,&p_Gw->gw_place);
			window_border(MAP_GADGETS,0,0,Tile_width*(COLNO-1),Tile_heigth*ROWNO, &g_mapmax);
			p_Gw->gw_window=open_window(md, md, NULL, zz_oblist[NHICON], MAP_GADGETS, TRUE, 128, 128, &g_mapmax, &p_Gw->gw_place, &scroll_map, win_draw_map, NULL, XM_TOP|XM_BOTTOM|XM_SIZE);
			WindowItems(p_Gw->gw_window,SCROLL_KEYS-1,scroll_keys);	/* ClrHome centers on u */
			mar_clear_map();
		}
		if(p_Gw->gw_dirty){
			area.g_x=p_Gw->gw_window->work.g_x+scroll_map.px_hline*(dirty_map_area.g_x-scroll_map.hpos);
			area.g_y=p_Gw->gw_window->work.g_y+scroll_map.px_vline*(dirty_map_area.g_y-scroll_map.vpos);
			area.g_w=(dirty_map_area.g_w-dirty_map_area.g_x+1)*scroll_map.px_hline;
			area.g_h=(dirty_map_area.g_h-dirty_map_area.g_y+1)*scroll_map.px_vline;

			redraw_window(p_Gw->gw_window,&area);

			dirty_map_area.g_x=COLNO-1;
			dirty_map_area.g_y=ROWNO;
			dirty_map_area.g_w=
			dirty_map_area.g_h=0;
		}
		break;
	case NHW_MESSAGE:
		if(p_Gw->gw_window==NULL){
			calc_std_winplace(NHW_MESSAGE,&p_Gw->gw_place);
			z_ob=zz_oblist[MSGWIN];
			magx=0;	/* MAR -- Fake E_GEM to remove Backdropper */
			p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE);
			magx=tmp_magx;
			window_size(p_Gw->gw_window,&p_Gw->gw_window->curr);
			p_Gw->gw_dirty=TRUE;
		}

		if(p_Gw->gw_dirty){
			ob_pos(zz_oblist[MSGWIN],MSGLINES,&area);
			while(messages_pro_zug>3){
				messages_pro_zug-=3;
				msg_pos+=3;
				redraw_window(p_Gw->gw_window,&area);
				mar_more();
			}
			msg_pos+=messages_pro_zug;
			messages_pro_zug=0;
			if(msg_pos>msg_max) msg_pos=msg_max;
			redraw_window(p_Gw->gw_window,&area);
			mar_message_pause=FALSE;
		}
		break;
	case NHW_STATUS:
		if(p_Gw->gw_window==NULL){
			z_ob=zz_oblist[STATUSLINE];
			calc_std_winplace(NHW_STATUS,&p_Gw->gw_place);
			magx=0;	/* MAR -- Fake E_GEM to remove Backdropper */
			p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, FALSE, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE);
			magx=tmp_magx;
			/* Because 2*status_font.ch is smaller then e_gem expects the minimum win_height */
			p_Gw->gw_window->min_h=z_ob[ROOT].ob_height;
			window_size(p_Gw->gw_window,&p_Gw->gw_place);
			p_Gw->gw_dirty=TRUE;
		}
		while(get_dirty_rect(dr_stat,&area)){
			area.g_x=(area.g_x+p_Gw->gw_window->work.g_x+2*status_font.cw+6)&~7;
			area.g_y+=p_Gw->gw_window->work.g_y;
			redraw_window(p_Gw->gw_window,&area);
		}
		break;
	default:
		if(p_Gw->gw_dirty)
			redraw_window(p_Gw->gw_window,NULL);
	}
	p_Gw->gw_dirty=FALSE;
}

/************************* create_window *******************************/

int mar_hol_win_type(window)
winid	window;
{
	return(Gem_nhwindow[window].gw_type);
}

winid
mar_create_window(type)
int type;
{
	winid newid;
	static char name[]="Gem";
	int i;
	struct gw *p_Gw=&Gem_nhwindow[0];

	for(newid = 0; p_Gw->gw_type && newid < MAXWIN; newid++, p_Gw++);

	switch(type){
	case NHW_MESSAGE:
		message_line=(char **)m_alloc(msg_anz*sizeof(char *));
		message_age=(int *)m_alloc(msg_anz*sizeof(int));
		for(i=0;i<msg_anz;i++){
			message_age[i]=FALSE;
			message_line[i]=(char *)m_alloc((MSGLEN+1)*sizeof(char));
			*message_line[i]=0;
		}
		dr_msg=new_dirty_rect(10);
		if (!dr_msg) panic("Memory allocation failure (dr_msg)");
		break;
	case NHW_STATUS:
		status_line=(char **)m_alloc(2*sizeof(char *));
		for(i=0;i<2;i++){
			status_line[i]=(char *)m_alloc(status_w*sizeof(char));
			memset(status_line[i],0,status_w);
		}
		dr_stat=new_dirty_rect(10);
		if (!dr_stat) panic("Memory allocation failure (dr_stat)");
		break;
	case NHW_MAP:
		map_glyphs=(char **)m_alloc((long)ROWNO*sizeof(char *));
		for(i=0;i<ROWNO;i++){
			map_glyphs[i]=(char *)m_alloc((long)COLNO*sizeof(char));
			*map_glyphs[i]=map_glyphs[i][COLNO-1]=0;
		}
		dr_map=new_dirty_rect(10);
		if (!dr_map) panic("Memory allocation failure (dr_map)");

		mar_clear_map();
		break;
	case NHW_MENU:
	case NHW_TEXT:	/* They are no more treated as dialog */
		break;
	default:
		p_Gw->gw_window=open_window("Sonst", name, NULL, NULL, NAME|MOVER|CLOSER, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, NULL, NULL, XM_TOP|XM_BOTTOM|XM_SIZE);
		break;
	}

	p_Gw->gw_type=type;

	return(newid);
}

void
mar_change_menu_2_text(win)
winid win;
{
	Gem_nhwindow[win].gw_type=NHW_TEXT;
}

/************************* mar_clear_map *******************************/

void
mar_clear_map()
{
	int pla[8];
	int x,y;

	pla[0]=pla[1]=pla[4]=pla[5]=0;
	pla[2]=pla[6]=scroll_map.px_hline*(COLNO-1)-1;
	pla[3]=pla[7]=scroll_map.px_vline*ROWNO-1;
	for(y=0;y<ROWNO;y++) for(x=0;x<COLNO-1;x++)
		map_glyphs[y][x]=' ';
	vro_cpyfm(x_handle, ALL_BLACK,pla,&Tile_bilder,&Map_bild);	/* MAR -- 17.Mar 2002 Hmm, what if FontCol_Bild is bigger? */
	if(WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window)
		redraw_window(Gem_nhwindow[WIN_MAP].gw_window,NULL);
}

/************************* destroy_window *******************************/

void
mar_destroy_nhwindow(window)
winid window;
{
	int i;

	switch(Gem_nhwindow[window].gw_type){
	case NHW_TEXT:
		for(i=0;i<Anz_text_lines;i++)
			free(text_lines[i]);
		null_free(text_lines);
		Anz_text_lines=0;
		use_rip=FALSE;
		break;
	case NHW_MENU:
		Gem_start_menu(window);	/* delete invent_list */
		test_free(Menu_title);
		break;
	case 0:	/* No window available, probably an error message? */
		break;
	default:
		close_window( Gem_nhwindow[window].gw_window, 0 );
		break;
	}
	Gem_nhwindow[window].gw_window=NULL;
	Gem_nhwindow[window].gw_type=0;
	Gem_nhwindow[window].gw_dirty=FALSE;

	if(window==WIN_MAP){
		for(i=0;i<ROWNO;i++){
			free(map_glyphs[i]);
		}
		null_free(map_glyphs);
		WIN_MAP=WIN_ERR;
	}
	if(window==WIN_STATUS){
		for(i=0;i<2;i++)
			free(status_line[i]);
		null_free(status_line);
		WIN_STATUS=WIN_ERR;
	}
	if(window==WIN_MESSAGE){
		for(i=0;i<msg_anz;i++)
			free(message_line[i]);
		null_free(message_line);
		null_free(message_age);
		WIN_MESSAGE=WIN_ERR;
	}
	if(window==WIN_INVEN)
		WIN_INVEN=WIN_ERR;
}

/************************* nh_poskey *******************************/

void mar_set_margin(int m){
	Max(&m,0);
	Min(&m,min(ROWNO,COLNO));	/* MAR 16.Mar 2002 -- the larger the less sense */
	scroll_margin=m;
}
void
mar_cliparound()
{
	if(WIN_MAP!=WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window){
		int	breite=scroll_margin>0 ? scroll_margin : max(scroll_map.hpage/4,1),
				hoehe=scroll_margin>0 ? scroll_margin : max(scroll_map.vpage/4,1),
				adjust_needed;
		adjust_needed=FALSE;
		if ((map_cursx < scroll_map.hpos + breite) || (map_cursx >= scroll_map.hpos + scroll_map.hpage - breite)){
			scroll_map.hpos=map_cursx - scroll_map.hpage/2;
			adjust_needed=TRUE;
		}
		if ((map_cursy < scroll_map.vpos + hoehe) || (map_cursy >= scroll_map.vpos + scroll_map.vpage - hoehe)){
			scroll_map.vpos=map_cursy - scroll_map.vpage/2;
			adjust_needed=TRUE;
		}
		if(adjust_needed)
			scroll_window(Gem_nhwindow[WIN_MAP].gw_window,WIN_SCROLL,NULL);
	}
}

void
mar_update_value()
{
	if(WIN_MESSAGE!=WIN_ERR){
		mar_message_pause=FALSE;
		mar_esc_pressed=FALSE;
		mar_display_nhwindow(WIN_MESSAGE);
	}

	if(WIN_MAP!=WIN_ERR)
		mar_cliparound();

	if(WIN_STATUS!=WIN_ERR){
		mar_check_hilight_status();
		mar_display_nhwindow(WIN_STATUS);
	}
}

int
Main_Init(xev,availiable)
XEVENT *xev;
int availiable;
{
	xev->ev_mb1mask=
	xev->ev_mb1state=1;
	xev->ev_mb1clicks=
	xev->ev_mb2clicks=
	xev->ev_mb2mask=
	xev->ev_mb2state=2;
	return((MU_KEYBD|MU_BUTTON1|MU_BUTTON2|MU_MESAG)&availiable);
}

/*
 * return a key, or 0, in which case a mouse button was pressed
 * mouse events should be returned as character postitions in the map window.
 */
/*ARGSUSED*/
int
mar_nh_poskey(x, y, mod)
    int *x, *y, *mod;
{
	static XEVENT xev;
	int retval, ev;

	xev.ev_mflags=Main_Init(&xev,0xFFFF);
	ev=Event_Multi(&xev);

	retval=FAIL;

	if(ev&MU_KEYBD){
		char ch = xev.ev_mkreturn&0x00FF;
		char scan = (xev.ev_mkreturn & 0xff00) >> 8;
		int shift = xev.ev_mmokstate;
		const struct pad *kpad;

		/* Translate keypad keys */
		if (iskeypad(scan)) {
			kpad = mar_iflags_numpad()==1 ? numpad : keypad;
			if (shift & K_SHIFT)
				ch = kpad[scan - KEYPADLO].shift;
			else if (shift & K_CTRL){
				if(scan>=0x67 && scan<=0x6f && scan!=0x6b){
					send_key(kpad[scan - KEYPADLO].normal);
					ch = 'g';
				}else{
				ch = kpad[scan - KEYPADLO].cntrl;
				}
			}else
				ch = kpad[scan - KEYPADLO].normal;
		}
		if(scan==SCANHOME)
			mar_cliparound();
		else if(scan == SCANF1)
			retval='h';
		else if(scan == SCANF2){
			mar_set_tile_mode(!mar_set_tile_mode(FAIL));
			retval=C('l');	/* trigger full-redraw */
		}else if(scan == SCANF3){
			draw_cursor=!draw_cursor;
			mar_curs(map_cursx,map_cursy);
			mar_display_nhwindow(WIN_MAP);
		}else if(scan == SCANF4){	/* Font-Selector */
			if(!CallFontSelector(0,FAIL,FAIL,FAIL,FAIL)){
				xalert(1,1,X_ICN_ALERT,NULL,SYS_MODAL,BUTTONS_RIGHT,TRUE,"Hello","Fontselector not available!",NULL);
			}
		}else if(!ch && shift&K_CTRL && scan==-57){
			/* MAR -- nothing ignore Ctrl-Alt-Clr/Home == MagiC's restore screen */
		}else{
			if(!ch)
				ch=(char)M(tolower(scan_2_ascii(xev.ev_mkreturn,shift)));
			if(((int)ch)==-128)
				ch='\033';
			retval=ch;
		}
	}

	if(ev&MU_BUTTON1 || ev&MU_BUTTON2){
		int ex=xev.ev_mmox, ey=xev.ev_mmoy;
		WIN *akt_win=window_find(ex,ey);

		if(WIN_MAP != WIN_ERR && akt_win==Gem_nhwindow[WIN_MAP].gw_window){
			*x=max(min((ex-akt_win->work.g_x)/scroll_map.px_hline+scroll_map.hpos,COLNO-1),0)+1;
			*y=max(min((ey-akt_win->work.g_y)/scroll_map.px_vline+scroll_map.vpos,ROWNO),0);
			*mod=xev.ev_mmobutton;
			retval=0;
		}else if(WIN_STATUS != WIN_ERR && akt_win==Gem_nhwindow[WIN_STATUS].gw_window){
			move_win(akt_win);
		}else if(WIN_MESSAGE != WIN_ERR && akt_win==Gem_nhwindow[WIN_MESSAGE].gw_window){
			message_handler(ex,ey);
		}
	}

	if(ev&MU_MESAG){
		int *buf=xev.ev_mmgpbuf;
		char *str;
		OBJECT *z_ob=zz_oblist[MENU];

	   switch(*buf) {
		case MN_SELECTED :
			menu_tnormal(z_ob,buf[3],TRUE);	/* unselect menu header */
			str=ob_get_text(z_ob,buf[4],0);
			str+=strlen(str)-2;
			switch(*str){
			case ' ':	/* just that command */
				retval=str[1];
				break;
			case '\005':	/* Alt command */
			case '\007':
				retval=M(str[1]);
				break;
			case '^':	/* Ctrl command */
				retval=C(str[1]);
				break;
			case 'f':	/* Func Key */
				switch(str[1]){
				case '1':
					retval='h';
					break;
				case '2':
					mar_set_tile_mode(!mar_set_tile_mode(FAIL));
					retval=C('l');	/* trigger full-redraw */
					break;
				case '3':
					draw_cursor=!draw_cursor;
					mar_curs(map_cursx,map_cursy);
					mar_display_nhwindow(WIN_MAP);
					break;
				default:
				}
				break;
			default:
				mar_about();
				break;
			}
			break;	/* MN_SELECTED */
		case WM_CLOSED:
			WindowHandler(W_ICONIFYALL,NULL,NULL);
			break;
		case AP_TERM:
			retval='S';
			break;
		case FONT_CHANGED:
			if(buf[3]>=0){
				if(buf[3]==Gem_nhwindow[WIN_MESSAGE].gw_window->handle){
					mar_set_fontbyid(NHW_MESSAGE,buf[4],buf[5]);
					mar_display_nhwindow(WIN_MESSAGE);
				}else if(buf[3]==Gem_nhwindow[WIN_MAP].gw_window->handle){
					mar_set_fontbyid(NHW_MAP,buf[4],buf[5]);
					mar_display_nhwindow(WIN_MAP);
				}else if(buf[3]==Gem_nhwindow[WIN_STATUS].gw_window->handle){
					mar_set_fontbyid(NHW_STATUS,buf[4],buf[5]);
					mar_display_nhwindow(WIN_STATUS);
				}
				FontAck(buf[1],1);
			}
			break;
		default:
			break;
		}
	}	/* MU_MESAG */

	if(retval==FAIL)
		retval=mar_nh_poskey(x,y,mod);

	return(retval);
}

int
Gem_nh_poskey(x, y, mod)
    int *x, *y, *mod;
{
	mar_update_value();
	return(mar_nh_poskey(x, y, mod));
}

void
Gem_delay_output()
{
	Event_Timer(50,0,FALSE);	/* wait 50ms */
}

int
Gem_doprev_message()
{
	if(msg_pos>2){
		msg_pos--;
	if(WIN_MESSAGE != WIN_ERR)
		Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE;
	mar_display_nhwindow(WIN_MESSAGE);
	}
	return(0);
}

/************************* print_glyph *******************************/

int mar_set_rogue(int);

int
mar_set_tile_mode(tiles)
int tiles;
{
	static int tile_mode=TRUE;
	static GRECT prev;
	WIN *z_w=WIN_MAP!=WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL;

	if(tiles<0)
		return(tile_mode);
	else if(!z_w)
		tile_mode=tiles;
	else if(tile_mode==tiles || (mar_set_rogue(FAIL) && tiles))
			return(FAIL);
	else{
		GRECT tmp;

		tile_mode=tiles;
		scroll_map.px_hline= tiles ? Tile_width : map_font.cw;
		scroll_map.px_vline= tiles ? Tile_heigth : map_font.ch;
		window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &tmp);
		z_w->max.g_w=tmp.g_w;
		z_w->max.g_h=tmp.g_h;
		if(tiles)
			z_w->curr=prev;
		else
			prev=z_w->curr;

		window_reinit(z_w,md,md,NULL,FALSE,FALSE);
	}
	return(FAIL);
}

int
mar_set_rogue(what)
int what;
{
	static int rogue=FALSE, prev_mode=TRUE;

	if(what<0) return(rogue);
	if(what!=rogue){
		rogue=what;
		if(rogue){
			prev_mode=mar_set_tile_mode(FAIL);
			mar_set_tile_mode(FALSE);
		}else
			mar_set_tile_mode(prev_mode);
	}
	return(FAIL);
}

void
mar_add_pet_sign(window,x,y)
winid window;
int x, y;
{
	if(window != WIN_ERR && window==WIN_MAP){
		static int pla[8]={0,0,7,7,0,0,0,0}, colindex[2]={RED,WHITE};

		pla[4]=pla[6]=scroll_map.px_hline*x;
		pla[5]=pla[7]=scroll_map.px_vline*y;
		pla[6]+=7;
		pla[7]+=6;
		vrt_cpyfm(x_handle,MD_TRANS,pla,&Pet_Mark,&Map_bild,colindex);
	}
}

void
mar_print_glyph(window, x, y, gl)
winid window;
int x, y, gl;
{
	if(window != WIN_ERR && window==WIN_MAP){
	static int pla[8];

			pla[2]=pla[0]=(gl%Tiles_per_line)*Tile_width;
			pla[3]=pla[1]=(gl/Tiles_per_line)*Tile_heigth;
			pla[2]+=Tile_width-1;
			pla[3]+=Tile_heigth-1;
			pla[6]=pla[4]=Tile_width*x;	/* x_wert to */
			pla[7]=pla[5]=Tile_heigth*y;	/* y_wert to */
			pla[6]+=Tile_width-1;
			pla[7]+=Tile_heigth-1;

			vro_cpyfm(x_handle, gl!=-1 ? S_ONLY : ALL_BLACK, pla, &Tile_bilder, &Map_bild);
		}
	}

void
mar_print_char(window, x, y, ch, col)
winid window;
int x, y;
char ch;
int col;
{
	if(window != WIN_ERR && window==WIN_MAP){
		static int gem_color[16]={ 9, 2,11,10, 4, 7, 8, 15,0,14, 3, 6, 5, 13,15, 0};
		int pla[8], colindex[2];

		map_glyphs[y][x]=ch;

		pla[0]=
		pla[1]=0;
		pla[2]=map_font.cw-1;
		pla[3]=map_font.ch-1;
		pla[6]=pla[4]=map_font.cw*x;
		pla[7]=pla[5]=map_font.ch*y;
		pla[6]+=map_font.cw-1;
		pla[7]+=map_font.ch-1;
		colindex[0]=gem_color[col];
		colindex[1]=WHITE;
		vrt_cpyfm(x_handle,MD_REPLACE,pla,&Black_bild,&FontCol_Bild,colindex);
	}
}

/************************* getlin *******************************/

void
Gem_getlin(ques, input)
const char *ques;
char *input;
{
	OBJECT *z_ob=zz_oblist[LINEGET];
	int d_exit, length;
	char *pr[2], *tmp;

	if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
		mar_display_nhwindow(WIN_MESSAGE);

	z_ob[LGPROMPT].ob_type=G_USERDEF;
	z_ob[LGPROMPT].ob_spec.userblk=&ub_prompt;
	z_ob[LGPROMPT].ob_height=2*gr_ch;

	length=z_ob[LGPROMPT].ob_width/gr_cw;
	if(strlen(ques)>length){
		tmp=ques+length;
		while(*tmp!=' ' && tmp>=ques){
			tmp--;
		}
		if(tmp<=ques) tmp=ques+length;	/* Mar -- Oops, what a word :-) */
		pr[0]=ques;
		*tmp=0;
		pr[1]=++tmp;
	}else{
		pr[0]=ques;
		pr[1]=NULL;
	}
	ub_prompt.ub_parm=(long)pr;

	ob_clear_edit(z_ob);
	d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
	Event_Timer(0,0,TRUE);

	if(d_exit==W_CLOSED || d_exit==W_ABANDON || (d_exit&NO_CLICK)==QLG){
		*input='\033';
		input[1]=0;
	}else
		strncpy(input,ob_get_text(z_ob,LGREPLY, 0),length);
}

/************************* ask_direction *******************************/

#define Dia_Init K_Init

int
Dia_Handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;
	char ch=(char)(xev->ev_mkreturn&0x00FF);

	if(ev&MU_KEYBD){
		WIN *w;
		DIAINFO *dinf;

		switch(ch){
		case 's':
			send_key((int)(mar_iflags_numpad() ? '5' : '.'));
			break;
		case '.':
			send_key('5');	/* MAR -- '.' is a button if numpad isn't set */
			break;
		case '\033':	/*ESC*/
			if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[DIRECTION]){
				my_close_dialog(dinf,FALSE);
				break;
			}
			/* Fall thru */
		default:
			ev &= ~MU_KEYBD;	/* let the dialog handle it */
			break;
		}
	}
	return(ev);
}

int
mar_ask_direction()
{
	int d_exit;
	OBJECT *z_ob=zz_oblist[DIRECTION];

	Event_Handler(Dia_Init,Dia_Handler);
	mar_set_dir_keys();
	d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
	Event_Timer(0,0,TRUE);
	Event_Handler(NULL,NULL);

	if(d_exit==W_CLOSED || d_exit==W_ABANDON)
		return('\033');
	if((d_exit&NO_CLICK)==DIRDOWN)
		return('>');
	if((d_exit&NO_CLICK)==DIRUP)
		return('<');
	if((d_exit&NO_CLICK)==(DIR1+8))	/* 5 or . */
		return('.');
	return(*ob_get_text(z_ob,d_exit&NO_CLICK,0));
}

/************************* yn_function *******************************/


#define any_init M_Init

static int
any_handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;

	if(ev&MU_MESAG){
		int *buf=xev->ev_mmgpbuf;

		if(*buf==OBJC_EDITED)
			my_close_dialog(*(DIAINFO **)&buf[4], FALSE);
		else
			ev &= ~MU_MESAG;
	}
	return(ev);
}

int
send_yn_esc(char ch)
{
	static char esc_char=0;

	if(ch<0){
		if(esc_char){
			send_key((int)esc_char);
			return(TRUE);
		}
		return(FALSE);
	}else
		esc_char=ch;
	return(TRUE);
}

#define single_init K_Init

static int
single_handler(xev)
XEVENT *xev;
{
	int ev=xev->ev_mwich;

	if(ev&MU_KEYBD){
		char ch=(char)xev->ev_mkreturn&0x00FF;
		WIN *w;
		DIAINFO *dinf;

		switch(ch){
		case ' ':
			send_return();
			break;
		case '\033':
			if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[YNCHOICE]){
				if(!send_yn_esc(FAIL))
					my_close_dialog(dinf,FALSE);
				break;
			}
			/* Fall thru */
		default:
			ev &= ~MU_MESAG;
		}
	}
	return(ev);
}

char
Gem_yn_function(query,resp, def)
const char *query,*resp;
char def;
{
	OBJECT *z_ob=zz_oblist[YNCHOICE];
	int d_exit, i, len;
	long anzahl;
	char *tmp;
	const char *ptr;

	if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window)
		mar_display_nhwindow(WIN_MESSAGE);

	/* if query for direction the special dialog */
	if(strstr(query,"irect"))
		return(mar_ask_direction());

	len=min(strlen(query),(max_w-8*gr_cw)/gr_cw);
	z_ob[ROOT].ob_width=(len+8)*gr_cw;
	z_ob[YNPROMPT].ob_width=gr_cw*len+8;
	tmp=ob_get_text(z_ob,YNPROMPT,0);
	ob_set_text(z_ob,YNPROMPT,mar_copy_of(query));

	if(resp){	/* single inputs */
		ob_hide(z_ob,SOMECHARS,FALSE);
		ob_hide(z_ob,ANYCHAR,TRUE);

		if(strchr(resp,'q')) send_yn_esc('q');
		else if(strchr(resp,'n')) send_yn_esc('n');
		else send_yn_esc(def);	/* strictly def should be returned, but in trad. I it's 0 */

		if(strchr(resp,'#')){	/* count possible */
			ob_hide(z_ob,YNOK,FALSE);
			ob_hide(z_ob,COUNT,FALSE);
		}else{	/* no count */
			ob_hide(z_ob,YNOK,TRUE);
			ob_hide(z_ob,COUNT,TRUE);
		}

		if((anzahl=(long)strchr(resp,'\033'))){
			anzahl-=(long)resp;
		}else{
			anzahl=strlen(resp);
		}
		for(i=0,ptr=resp;i<2*anzahl;i+=2,ptr++){
			ob_hide(z_ob,YN1+i,FALSE);
			mar_change_button_char(z_ob,YN1+i,*ptr);
			ob_undoflag(z_ob,YN1+i,DEFAULT);
			if(*ptr==def)
				ob_doflag(z_ob,YN1+i,DEFAULT);
		}

		z_ob[SOMECHARS].ob_width=z_ob[YN1+i].ob_x+8;
		z_ob[SOMECHARS].ob_height=z_ob[YN1+i].ob_y+gr_ch+gr_ch/2;
		Max((int *)&z_ob[ROOT].ob_width,z_ob[SOMECHARS].ob_width+4*gr_cw);
		z_ob[ROOT].ob_height=z_ob[SOMECHARS].ob_height+4*gr_ch;
		if(strchr(resp,'#'))
			z_ob[ROOT].ob_height=z_ob[YNOK].ob_y+2*gr_ch;

		for(i+=YN1;i<(YNN+1);i+=2){
			ob_hide(z_ob,i,TRUE);
		}
		Event_Handler(single_init,single_handler);
	}else{	/* any input */
		ob_hide(z_ob,SOMECHARS,TRUE);
		ob_hide(z_ob,ANYCHAR,FALSE);
		ob_hide(z_ob,YNOK,TRUE);
		ob_hide(z_ob,COUNT,TRUE);
		z_ob[ANYCHAR].ob_height=2*gr_ch;
		z_ob[CHOSENCH].ob_y=
		z_ob[CHOSENCH+1].ob_y=gr_ch/2;
		z_ob[ROOT].ob_width=max(z_ob[YNPROMPT].ob_width+z_ob[YNPROMPT].ob_x,z_ob[ANYCHAR].ob_width+z_ob[ANYCHAR].ob_x)+2*gr_cw;
		z_ob[ROOT].ob_height=z_ob[ANYCHAR].ob_height+z_ob[ANYCHAR].ob_y+gr_ch/2;
		*ob_get_text(z_ob,CHOSENCH,0)='?';
		Event_Handler(any_init,any_handler);
	}

	d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE);
	Event_Timer(0,0,TRUE);
	Event_Handler(NULL,NULL);
	/* display of count is missing (through the core too) */

	free(ob_get_text(z_ob,YNPROMPT,0));
	ob_set_text(z_ob,YNPROMPT,tmp);

	if(resp && (d_exit==W_CLOSED || d_exit==W_ABANDON))
		return('\033');
	if((d_exit&NO_CLICK)==YNOK){
		yn_number=atol(ob_get_text(z_ob,COUNT,0));
		return('#');
	}
	if(!resp)
		return(*ob_get_text(z_ob,CHOSENCH,0));
	return(*ob_get_text(z_ob,d_exit&NO_CLICK,0));
}

/*
 * Allocate a copy of the given string.  If null, return a string of
 * zero length.
 *
 * This is an exact duplicate of copy_of() in X11/winmenu.c.
 */
static char *
mar_copy_of(s)
    const char *s;
{
    if (!s) s = nullstr;
    return strcpy((char *) m_alloc((unsigned) (strlen(s) + 1)), s);
}

const char *strRP="raw_print", *strRPB="raw_print_bold";

void
mar_raw_print(str)
const char *str;
{
		xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRP,str,NULL);
}

void
mar_raw_print_bold(str)
const char *str;
{
	char buf[BUFSZ];

	sprintf(buf,"!%s",str);
	xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRPB,buf,NULL);
}

/*wingem1.c*/
