1 /*	SCCS Id: @(#)winami.c	3.2	2000/01/12	*/
2 /* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993,1996. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "NH:sys/amiga/windefs.h"
6 #include "NH:sys/amiga/winext.h"
7 #include "NH:sys/amiga/winproto.h"
8 #include "dlb.h"
9 
10 #ifdef AMIGA_INTUITION
11 
12 static int FDECL( put_ext_cmd, ( char *, int, struct amii_WinDesc *, int ) );
13 
14 struct amii_DisplayDesc *amiIDisplay;	/* the Amiga Intuition descriptor */
15 struct Rectangle lastinvent, lastmsg;
16 int clipping = 0;
17 int clipx=0;
18 int clipy=0;
19 int clipxmax=0;
20 int clipymax=0;
21 int scrollmsg = 1;
22 int alwaysinvent = 0;
23 int amii_numcolors;
24 long amii_scrnmode;
25 
26 /* Interface definition, for use by windows.c and winprocs.h to provide
27  * the intuition interface for the amiga...
28  */
29 struct window_procs amii_procs =
30 {
31     "amii",
32     amii_init_nhwindows,
33     amii_player_selection,
34     amii_askname,
35     amii_get_nh_event,
36     amii_exit_nhwindows,
37     amii_suspend_nhwindows,
38     amii_resume_nhwindows,
39     amii_create_nhwindow,
40     amii_clear_nhwindow,
41     amii_display_nhwindow,
42     amii_destroy_nhwindow,
43     amii_curs,
44     amii_putstr,
45     amii_display_file,
46     amii_start_menu,
47     amii_add_menu,
48     amii_end_menu,
49     amii_select_menu,
50     genl_message_menu,
51     amii_update_inventory,
52     amii_mark_synch,
53     amii_wait_synch,
54 #ifdef CLIPPING
55     amii_cliparound,
56 #endif
57 #ifdef POSITIONBAR
58     donull,
59 #endif
60     amii_print_glyph,
61     amii_raw_print,
62     amii_raw_print_bold,
63     amii_nhgetch,
64     amii_nh_poskey,
65     amii_bell,
66     amii_doprev_message,
67     amii_yn_function,
68     amii_getlin,
69     amii_get_ext_cmd,
70     amii_number_pad,
71     amii_delay_output,
72 #ifdef CHANGE_COLOR	/* only a Mac option currently */
73     amii_change_color,
74     amii_get_color_string,
75 #endif
76     /* other defs that really should go away (they're tty specific) */
77     amii_delay_output,
78     amii_delay_output,
79     amii_outrip
80 };
81 
82 /* The view window layout uses the same function names so we can use
83  * a shared library to allow the executable to be smaller.
84  */
85 struct window_procs amiv_procs =
86 {
87     "amitile",
88     amii_init_nhwindows,
89     amii_player_selection,
90     amii_askname,
91     amii_get_nh_event,
92     amii_exit_nhwindows,
93     amii_suspend_nhwindows,
94     amii_resume_nhwindows,
95     amii_create_nhwindow,
96     amii_clear_nhwindow,
97     amii_display_nhwindow,
98     amii_destroy_nhwindow,
99     amii_curs,
100     amii_putstr,
101     amii_display_file,
102     amii_start_menu,
103     amii_add_menu,
104     amii_end_menu,
105     amii_select_menu,
106     genl_message_menu,
107     amii_update_inventory,
108     amii_mark_synch,
109     amii_wait_synch,
110 #ifdef CLIPPING
111     amii_cliparound,
112 #endif
113 #ifdef POSITIONBAR
114     donull,
115 #endif
116     amii_print_glyph,
117     amii_raw_print,
118     amii_raw_print_bold,
119     amii_nhgetch,
120     amii_nh_poskey,
121     amii_bell,
122     amii_doprev_message,
123     amii_yn_function,
124     amii_getlin,
125     amii_get_ext_cmd,
126     amii_number_pad,
127     amii_delay_output,
128 #ifdef CHANGE_COLOR	/* only a Mac option currently */
129     amii_change_color,
130     amii_get_color_string,
131 #endif
132     /* other defs that really should go away (they're tty specific) */
133     amii_delay_output,
134     amii_delay_output,
135     amii_outrip
136 };
137 
138 unsigned short amii_initmap[ AMII_MAXCOLORS ];
139 /* Default pens used unless use overides in nethack.cnf. */
140 unsigned short amii_init_map[ AMII_MAXCOLORS ] =
141 {
142     0x0000, /* color #0  C_BLACK    */
143     0x0FFF, /* color #1  C_WHITE    */
144     0x0830, /* color #2  C_BROWN    */
145     0x07ac, /* color #3  C_CYAN     */
146     0x0181, /* color #4  C_GREEN    */
147     0x0C06, /* color #5  C_MAGENTA  */
148     0x023E, /* color #6  C_BLUE     */
149     0x0c00, /* color #7  C_RED      */
150 };
151 
152 unsigned short amiv_init_map[ AMII_MAXCOLORS ] =
153 {
154     0x0000, /* color #0  C_BLACK    */
155     0x0fff, /* color #1  C_WHITE    */
156     0x00bf, /* color #2  C_CYAN     */
157     0x0f60, /* color #3  C_ORANGE   */
158     0x000f, /* color #4  C_BLUE     */
159     0x0090, /* color #5  C_GREEN    */
160     0x069b, /* color #6  C_GREY     */
161     0x0f00, /* color #7  C_RED      */
162     0x06f0, /* color #8  C_LTGREEN  */
163     0x0ff0, /* color #9  C_YELLOW   */
164     0x0f0f, /* color #10 C_MAGENTA  */
165     0x0940, /* color #11 C_BROWN    */
166     0x0466, /* color #12 C_GREYBLUE */
167     0x0c40, /* color #13 C_LTBROWN  */
168     0x0ddb, /* color #14 C_LTGREY   */
169     0x0fb9, /* color #15 C_PEACH    */
170 
171     /* Pens for dripens etc under AA or better */
172     0x0222, /* color #16 */
173     0x0fdc, /* color #17 */
174     0x0000, /* color #18 */
175     0x0ccc, /* color #19 */
176     0x0bbb, /* color #20 */
177     0x0BA9, /* color #21 */
178     0x0999, /* color #22 */
179     0x0987, /* color #23 */
180     0x0765, /* color #24 */
181     0x0666, /* color #25 */
182     0x0555, /* color #26 */
183     0x0533, /* color #27 */
184     0x0333, /* color #28 */
185     0x018f, /* color #29 */
186     0x0f81, /* color #30 */
187     0x0fff, /* color #31 */
188 };
189 
190 #if !defined( TTY_GRAPHICS ) || defined( SHAREDLIB )	/* this should be shared better */
191 char morc;  /* the character typed in response to a --more-- prompt */
192 #endif
193 char spaces[ 76 ] =
194 "                                                                           ";
195 
196 winid WIN_BASE = WIN_ERR;
197 winid WIN_OVER = WIN_ERR;
198 winid amii_rawprwin = WIN_ERR;
199 
200 /* Changed later during window/screen opens... */
201 int txwidth = FONTWIDTH, txheight = FONTHEIGHT, txbaseline = FONTBASELINE;
202 
203 /* If a 240 or more row screen is in front when we start, this will be
204  * set to 1, and the windows will be given borders to allow them to be
205  * arranged differently.  The Message window may eventually get a scroller...
206  */
207 int bigscreen = 0;
208 
209 /* This gadget data is replicated for menu/text windows... */
210 struct PropInfo PropScroll = { AUTOKNOB|FREEVERT,
211 					0xffff,0xffff, 0xffff,0xffff, };
212 struct Image Image1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
213 struct Gadget MenuScroll = {
214     NULL, -15,10, 15,-19, GRELRIGHT|GRELHEIGHT,
215     RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
216     PROPGADGET, (APTR)&Image1, NULL, NULL, NULL, (APTR)&PropScroll,
217     1, NULL
218 };
219 
220 /* This gadget is for the message window... */
221 struct PropInfo MsgPropScroll = { AUTOKNOB|FREEVERT,
222 					0xffff,0xffff, 0xffff,0xffff, };
223 struct Image MsgImage1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
224 struct Gadget MsgScroll = {
225     NULL, -15,10, 14,-19, GRELRIGHT|GRELHEIGHT,
226     RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
227     PROPGADGET, (APTR)&MsgImage1, NULL, NULL, NULL, (APTR)&MsgPropScroll,
228     1, NULL
229 };
230 
231 int wincnt=0;   /* # of nh windows opened */
232 
233 /* We advertise a public screen to allow some people to do other things
234  * while they are playing...  like compiling...
235  */
236 
237 #ifdef  INTUI_NEW_LOOK
238 struct TagItem tags[] =
239 {
240     { WA_PubScreenName, (ULONG)"NetHack" },
241     { TAG_DONE, 0 },
242 };
243 #endif
244 
245 /*
246  * The default dimensions and status values for each window type.  The
247  * data here is generally changed in create_nhwindow(), so beware that
248  * what you see here may not be exactly what you get.
249  */
250 struct win_setup new_wins[] =
251 {
252 
253     /* First entry not used, types are based at 1 */
254     {{0}},
255 
256     /* NHW_MESSAGE */
257     {{0,1,640,11,
258     0xff,0xff,
259     NEWSIZE|GADGETUP|GADGETDOWN|MOUSEMOVE|MOUSEBUTTONS|RAWKEY,
260     BORDERLESS|ACTIVATE|SMART_REFRESH
261 #ifdef  INTUI_NEW_LOOK
262     |WFLG_NW_EXTENDED
263 #endif
264     ,
265     NULL,NULL,(UBYTE*)"Messages",NULL,NULL,320,40,0xffff,0xffff,CUSTOMSCREEN,
266 #ifdef  INTUI_NEW_LOOK
267     tags
268 #endif
269     },
270     0,0,1,1,80,80},
271 
272     /* NHW_STATUS */
273     {{0,181,640,24,
274     0xff,0xff,
275     RAWKEY|MENUPICK|DISKINSERTED,
276     BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
277 #ifdef  INTUI_NEW_LOOK
278     |WFLG_NW_EXTENDED
279 #endif
280     ,
281     NULL,NULL,(UBYTE*)"Game Status",NULL,NULL,0,0,0xffff,0xffff,CUSTOMSCREEN,
282 #ifdef  INTUI_NEW_LOOK
283     tags
284 #endif
285     },
286     0,0,2,2,78,78},
287 
288     /* NHW_MAP */
289     {{0,0,WIDTH,WINDOWHEIGHT,
290     0xff,0xff,
291     RAWKEY|MENUPICK|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE,
292     BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
293 #ifdef  INTUI_NEW_LOOK
294     |WFLG_NW_EXTENDED
295 #endif
296     ,
297     NULL,NULL,(UBYTE*)"Dungeon Map",NULL,NULL,64,64,0xffff,0xffff,CUSTOMSCREEN,
298 #ifdef  INTUI_NEW_LOOK
299     tags
300 #endif
301     },
302     0,0,22,22,80,80},
303 
304     /* NHW_MENU */
305     {{400,10,10,10,
306     0xff,0xff,
307     RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|MOUSEBUTTONS|
308     GADGETUP|GADGETDOWN|CLOSEWINDOW|VANILLAKEY|NEWSIZE|INACTIVEWINDOW,
309     WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
310 #ifdef  INTUI_NEW_LOOK
311     |WFLG_NW_EXTENDED
312 #endif
313     ,
314     &MenuScroll,NULL,NULL,NULL,NULL,64,32,0xffff,0xffff,CUSTOMSCREEN,
315 #ifdef  INTUI_NEW_LOOK
316     tags
317 #endif
318     },
319     0,0,1,1,22,78},
320 
321     /* NHW_TEXT */
322     {{0,0,640,200,
323     0xff,0xff,
324     RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|
325     GADGETUP|CLOSEWINDOW|VANILLAKEY|NEWSIZE,
326     WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
327 #ifdef  INTUI_NEW_LOOK
328     |WFLG_NW_EXTENDED
329 #endif
330     ,
331     &MenuScroll,NULL,(UBYTE*)NULL,NULL,NULL,100,32,0xffff,0xffff,CUSTOMSCREEN,
332 #ifdef  INTUI_NEW_LOOK
333     tags
334 #endif
335     },
336     0,0,1,1,22,78},
337 
338     /* NHW_BASE */
339     {{0,0,WIDTH,WINDOWHEIGHT,
340     0xff,0xff,
341     RAWKEY|MENUPICK|MOUSEBUTTONS,
342     BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
343 #ifdef  INTUI_NEW_LOOK
344     |WFLG_NW_EXTENDED
345 #endif
346     ,
347     NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff,CUSTOMSCREEN,
348 #ifdef  INTUI_NEW_LOOK
349     tags
350 #endif
351     },
352     0,0,22,22,80,80},
353 
354     /* NHW_OVER */
355     {{320,20,319,179,
356     0xff,0xff,
357     RAWKEY|MENUPICK|MOUSEBUTTONS,
358     BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
359 #ifdef  INTUI_NEW_LOOK
360     |WFLG_NW_EXTENDED
361 #endif
362     ,
363     NULL,NULL,(UBYTE*)NULL,NULL,NULL,64,32,0xffff,0xffff,CUSTOMSCREEN,
364 #ifdef  INTUI_NEW_LOOK
365     tags
366 #endif
367     },
368     0,0,22,22,80,80},
369 };
370 
371 const char winpanicstr[] = "Bad winid %d in %s()";
372 
373 /* The opened windows information */
374 struct amii_WinDesc *amii_wins[ MAXWIN + 1 ];
375 
376 #ifdef  INTUI_NEW_LOOK
377 /*
378  * NUMDRIPENS varies based on headers, so don't use it
379  * here, its value is used elsewhere.
380  */
381 UWORD amii_defpens[ 20 ];
382 
383 struct TagItem scrntags[] =
384 {
385     { SA_PubName, (ULONG)"NetHack" },
386     { SA_Overscan, OSCAN_TEXT },
387     { SA_AutoScroll, TRUE },
388 #if LIBRARY_VERSION >= 39
389     { SA_Interleaved, TRUE },
390 #endif
391     { SA_Pens, (ULONG)0 },
392     { SA_DisplayID, 0 },
393     { TAG_DONE, 0 },
394 };
395 
396 #endif
397 
398 struct NewScreen NewHackScreen =
399 {
400     0, 0, WIDTH, SCREENHEIGHT, 3,
401     0, 1,     /* DetailPen, BlockPen */
402     HIRES,
403     CUSTOMSCREEN
404 #ifdef  INTUI_NEW_LOOK
405     |NS_EXTENDED
406 #endif
407     ,
408     &Hack80,  /* Font */
409     NULL,     /*(UBYTE *)" NetHack X.Y.Z" */
410     NULL,     /* Gadgets */
411     NULL,     /* CustomBitmap */
412 #ifdef  INTUI_NEW_LOOK
413     scrntags
414 #endif
415 };
416 
417 /*
418  * plname is filled either by an option (-u Player  or  -uPlayer) or
419  * explicitly (by being the wizard) or by askname.
420  * It may still contain a suffix denoting pl_character.
421  * Always called after init_nhwindows() and before display_gamewindows().
422  */
423 void
amii_askname()424 amii_askname()
425 {
426     *plname = 0;
427     do {
428 	amii_getlin( "Who are you?", plname );
429     } while( strlen( plname ) == 0 );
430 
431     if( *plname == '\33' )
432     {
433 	clearlocks();
434 	exit_nhwindows(NULL);
435 	terminate(0);
436     }
437 }
438 
439 /* Discarded ... -jhsa
440 #include "NH:sys/amiga/char.c"
441 */
442 
443 /* Get the player selection character */
444 
445 #if 0 /* New function at the bottom */
446 void
amii_player_selection()447 amii_player_selection()
448 {
449     register struct Window *cwin;
450     register struct IntuiMessage *imsg;
451     register int aredone = 0;
452     register struct Gadget *gd;
453     static int once = 0;
454     long class, code;
455 
456     amii_clear_nhwindow( WIN_BASE );
457     if (validrole(flags.initrole))
458 	return;
459     else {
460 	flags.initrole=randrole();
461 	return;
462     }
463 #if 0 /* Don't query the user ... instead give random character -jhsa */
464 
465 #if 0	/* OBSOLETE */
466     if( *pl_character ){
467 	pl_character[ 0 ] = toupper( pl_character[ 0 ] );
468 	if( index( pl_classes, pl_character[ 0 ] ) )
469 	    return;
470     }
471 #endif
472 
473     if( !once ){
474 	if( bigscreen ){
475 	    Type_NewWindowStructure1.TopEdge =
476 	      (HackScreen->Height/2) - (Type_NewWindowStructure1.Height/2);
477 	}
478 	for( gd = Type_NewWindowStructure1.FirstGadget; gd;
479 	  gd = gd->NextGadget )
480 	{
481 	    if( gd->GadgetID != 0 )
482 		SetBorder( gd );
483 	}
484 	once = 1;
485     }
486 
487     if( WINVERS_AMIV )
488     {
489 # ifdef	INTUI_NEW_LOOK
490 	Type_NewWindowStructure1.Extension = wintags;
491 	Type_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
492 	fillhook.h_Entry = (ULONG(*)())LayerFillHook;
493 	fillhook.h_Data = (void *)-2;
494 	fillhook.h_SubEntry = 0;
495 #endif
496     }
497 
498     Type_NewWindowStructure1.Screen = HackScreen;
499     if( ( cwin = OpenShWindow( (void *)&Type_NewWindowStructure1 ) ) == NULL )
500     {
501 	return;
502     }
503 #if 0
504     WindowToFront( cwin );
505 #endif
506 
507     while( !aredone )
508     {
509 	WaitPort( cwin->UserPort );
510 	while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
511 	{
512 	    class = imsg->Class;
513 	    code = imsg->Code;
514 	    gd = (struct Gadget *)imsg->IAddress;
515 	    ReplyMsg( (struct Message *)imsg );
516 
517 	    switch( class )
518 	    {
519 	    case VANILLAKEY:
520 		if( index( pl_classes, toupper( code ) ) )
521 		{
522 		    pl_character[0] = toupper( code );
523 		    aredone = 1;
524 		}
525 		else if( code == ' ' || code == '\n' || code == '\r' )
526 		{
527 		    flags.initrole = randrole();
528 #if 0	/* OBSOLETE */
529 #ifdef  TOURIST
530 		    strcpy( pl_character, roles[ rnd( 11 ) ] );
531 #else
532 		    strcpy( pl_character, roles[ rnd( 10 ) ] );
533 #endif
534 #endif
535 		    aredone = 1;
536 		    amii_clear_nhwindow( WIN_BASE );
537 		    CloseShWindow( cwin );
538 		    RandomWindow( pl_character );
539 		    return;
540 		}
541 		else if( code == 'q' || code == 'Q' )
542 		{
543 		CloseShWindow( cwin );
544 		clearlocks();
545 		exit_nhwindows(NULL);
546 		terminate(0);
547 		}
548 		else
549 		    DisplayBeep( NULL );
550 		break;
551 
552 	    case GADGETUP:
553 		switch( gd->GadgetID )
554 		{
555 		case 1: /* Random Character */
556 		    flags.initrole = randrole();
557 #if 0	/* OBSOLETE */
558 #ifdef  TOURIST
559 		    strcpy( pl_character, roles[ rnd( 11 ) ] );
560 #else
561 		    strcpy( pl_character, roles[ rnd( 10 ) ] );
562 #endif
563 #endif
564 		    amii_clear_nhwindow( WIN_BASE );
565 		    CloseShWindow( cwin );
566 		    RandomWindow( pl_character );
567 		    return;
568 
569 		default:
570 		    pl_character[0] = gd->GadgetID;
571 		    break;
572 		}
573 		aredone = 1;
574 		break;
575 
576 	    case CLOSEWINDOW:
577 		CloseShWindow( cwin );
578 		clearlocks();
579 		exit_nhwindows(NULL);
580 		terminate(0);
581 		break;
582 	    }
583 	}
584     }
585     amii_clear_nhwindow( WIN_BASE );
586     CloseShWindow( cwin );
587 #endif /* Do not query user ... -jhsa */
588 }
589 #endif /* Function elsewhere */
590 
591 #if 0 /* Unused ... -jhsa */
592 
593 #include "NH:sys/amiga/randwin.c"
594 
595 void
RandomWindow(name)596 RandomWindow( name )
597     char *name;
598 {
599     struct MsgPort *tport;
600     struct timerequest *trq;
601     static int once = 0;
602     struct Gadget *gd;
603     struct Window *w;
604     struct IntuiMessage *imsg;
605     int ticks = 0, aredone = 0, timerdone = 0;
606     long mask, got;
607 
608     tport = CreatePort( 0, 0 );
609     trq = (struct timerequest *)CreateExtIO( tport, sizeof( *trq ) );
610     if( tport == NULL || trq == NULL )
611     {
612 allocerr:
613 	if( tport ) DeletePort( tport );
614 	if( trq ) DeleteExtIO( (struct IORequest *)trq );
615 	Delay( 8 * 50 );
616 	return;
617     }
618 
619     if( OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)trq, 0L ) != 0 )
620 	goto allocerr;
621 
622     trq->tr_node.io_Command = TR_ADDREQUEST;
623     trq->tr_time.tv_secs = 8;
624     trq->tr_time.tv_micro = 0;
625 
626     SendIO( (struct IORequest *)trq );
627 
628     /* Place the name in the center of the screen */
629     Rnd_IText5.IText = name;
630     Rnd_IText6.LeftEdge = Rnd_IText4.LeftEdge +
631 		(strlen(Rnd_IText4.IText)+1)*8;
632     Rnd_NewWindowStructure1.Width = (
633 	    (strlen( Rnd_IText2.IText )+1) * 8 ) +
634 	    HackScreen->WBorLeft + HackScreen->WBorRight;
635     Rnd_IText5.LeftEdge = (Rnd_NewWindowStructure1.Width -
636 	    (strlen(name)*8))/2;
637 
638     gd = Rnd_NewWindowStructure1.FirstGadget;
639     gd->LeftEdge = (Rnd_NewWindowStructure1.Width - gd->Width)/2;
640 	/* Chose correct modifier */
641     Rnd_IText6.IText = "a";
642     switch( *name )
643     {
644     case 'a': case 'e': case 'i': case 'o':
645     case 'u': case 'A': case 'E': case 'I':
646     case 'O': case 'U':
647 	Rnd_IText6.IText = "an";
648 	break;
649     }
650 
651     if( !once )
652     {
653 	if( bigscreen )
654 	{
655 	    Rnd_NewWindowStructure1.TopEdge =
656 		(HackScreen->Height/2) - (Rnd_NewWindowStructure1.Height/2);
657 	}
658 	for( gd = Rnd_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget )
659 	{
660 	    if( gd->GadgetID != 0 )
661 		SetBorder( gd );
662 	}
663 	Rnd_NewWindowStructure1.IDCMPFlags |= VANILLAKEY;
664 
665 	once = 1;
666     }
667 
668     if( WINVERS_AMIV )
669     {
670 #ifdef	INTUI_NEW_LOOK
671 	Rnd_NewWindowStructure1.Extension = wintags;
672 	Rnd_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
673 	fillhook.h_Entry = (ULONG(*)())LayerFillHook;
674 	fillhook.h_Data = (void *)-2;
675 	fillhook.h_SubEntry = 0;
676 #endif
677     }
678 
679     Rnd_NewWindowStructure1.Screen = HackScreen;
680     if( ( w = OpenShWindow( (void *)&Rnd_NewWindowStructure1 ) ) == NULL )
681     {
682 	AbortIO( (struct IORequest *)trq );
683 	WaitIO( (struct IORequest *)trq );
684 	CloseDevice( (struct IORequest *)trq );
685 	DeleteExtIO( (struct IORequest *) trq );
686 	DeletePort( tport );
687 	Delay( 50 * 8 );
688 	return;
689     }
690 
691     PrintIText( w->RPort, &Rnd_IntuiTextList1, 0, 0 );
692 
693     mask = (1L << tport->mp_SigBit)|(1L << w->UserPort->mp_SigBit);
694     while( !aredone )
695     {
696 	got = Wait( mask );
697 	if( got & (1L << tport->mp_SigBit ) )
698 	{
699 	    aredone = 1;
700 	    timerdone = 1;
701 	    GetMsg( tport );
702         }
703         while( w && ( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) ) )
704         {
705 	    switch( (long)imsg->Class )
706 	    {
707 		/* Must be up for a little while... */
708 	    case INACTIVEWINDOW:
709 		if( ticks >= 40 )
710 		    aredone = 1;
711 		break;
712 
713 	    case INTUITICKS:
714 		++ticks;
715 		break;
716 
717 	    case GADGETUP:
718 		aredone = 1;
719 		break;
720 
721 	    case VANILLAKEY:
722 		if(imsg->Code=='\n' || imsg->Code==' ' || imsg->Code=='\r')
723 		    aredone = 1;
724 		break;
725 	    }
726 	    ReplyMsg( (struct Message *)imsg );
727         }
728     }
729 
730     if( !timerdone )
731     {
732 	AbortIO( (struct IORequest *)trq );
733 	WaitIO( (struct IORequest *)trq );
734     }
735 
736     CloseDevice( (struct IORequest *)trq );
737     DeleteExtIO( (struct IORequest *) trq );
738     DeletePort( tport );
739     if(w) CloseShWindow( w );
740 }
741 #endif /* Discarded randwin ... -jhsa */
742 
743 /* this should probably not be needed (or be renamed)
744 void
745 flush_output(){} */
746 
747 /* Read in an extended command - doing command line completion for
748  * when enough characters have been entered to make a unique command.
749  */
750 int
amii_get_ext_cmd(void)751 amii_get_ext_cmd( void )
752 {
753     menu_item *mip;
754     anything id;
755     struct amii_WinDesc *cw;
756 #ifdef EXTMENU
757     winid win;
758     int i;
759     char buf[256];
760 #endif
761     int colx;
762     int bottom = 0;
763     struct Window *w;
764     char obufp[ 100 ];
765     register char *bufp = obufp;
766     register int c;
767     int com_index, oindex;
768     int did_comp=0;	/* did successful completion? */
769     int sel = -1;
770 
771     if( WIN_MESSAGE == WIN_ERR || ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL )
772 	panic(winpanicstr, WIN_MESSAGE, "get_ext_cmd");
773     w = cw->win;
774     bottom = amii_msgborder( w );
775     colx = 3;
776 
777 #ifdef	EXTMENU
778     if (iflags.extmenu) {
779     win = amii_create_nhwindow( NHW_MENU );
780     amii_start_menu( win );
781     pline("#");
782     amii_putstr( WIN_MESSAGE, -1, " " );
783 
784     for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
785     {
786 	id.a_char = *extcmdlist[ i ].ef_txt;
787 	sprintf( buf, "%-10s - %s ",
788 		 extcmdlist[ i ].ef_txt,
789 		 extcmdlist[ i ].ef_desc );
790 	amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED);
791     }
792 
793     amii_end_menu( win, (char*)0 );
794     sel = amii_select_menu( win, PICK_ONE, &mip );
795     amii_destroy_nhwindow( win );
796 
797     if( sel == 1 )
798     {
799 	sel = mip->item.a_char;
800 	for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
801 	{
802 	    if( sel == extcmdlist[i].ef_txt[0] )
803 		break;
804 	}
805 
806 	/* copy in the text */
807 	if( extcmdlist[ i ].ef_txt != NULL )
808 	{
809 	    amii_clear_nhwindow( WIN_MESSAGE );
810 	    (void) put_ext_cmd( (char *)extcmdlist[i].ef_txt, 0, cw, bottom );
811 	    return( i );
812 	}
813 	else
814 	    DisplayBeep( NULL );
815     }
816 
817     return( -1 );
818     } else {
819 #else
820 
821     amii_clear_nhwindow( WIN_MESSAGE ); /* Was NHW_MESSAGE */
822     if( scrollmsg )
823     {
824 	pline("#");
825 	amii_addtopl(" ");
826     }
827     else
828     {
829 	pline("# ");
830     }
831 
832     sel = -1;
833     while((c = WindowGetchar()) != EOF)
834     {
835 	amii_curs( WIN_MESSAGE, colx, bottom );
836 	if(c == '?' )
837 	{
838 	    int win, i;
839 	    char buf[ 100 ];
840 
841 	    if(did_comp){
842 		while(bufp!=obufp)
843 		{
844 		    bufp--;
845 		    amii_curs(WIN_MESSAGE, --colx, bottom);
846 		    Text(w->RPort,spaces,1);
847 		    amii_curs(WIN_MESSAGE,colx,bottom);
848 		    did_comp=0;
849 		}
850 	    }
851 
852 	    win = amii_create_nhwindow( NHW_MENU );
853 	    amii_start_menu( win );
854 
855 	    for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
856 	    {
857 		id.a_char = extcmdlist[i].ef_txt[0];
858 		sprintf( buf, "%-10s - %s ",
859 			 extcmdlist[ i ].ef_txt,
860 			 extcmdlist[ i ].ef_desc );
861 		amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0,
862 		   0, buf, MENU_UNSELECTED);
863 	    }
864 
865 	    amii_end_menu( win, (char*)0 );
866 	    sel = amii_select_menu( win, PICK_ONE, &mip );
867 	    amii_destroy_nhwindow( win );
868 
869 	    if( sel == 0 )
870 	    {
871 		return( -1 );
872 	    }
873 	    else
874 	    {
875 		sel = mip->item.a_char;
876 		for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
877 		{
878 		    if( sel == extcmdlist[i].ef_txt[0] )
879 			break;
880 		}
881 
882 		/* copy in the text */
883 		if( extcmdlist[ i ].ef_txt != NULL )
884 		{
885 		    amii_clear_nhwindow( WIN_MESSAGE );
886 		    strcpy( bufp = obufp, extcmdlist[ i ].ef_txt );
887 		    (void) put_ext_cmd( obufp, colx, cw, bottom );
888 		    return( i );
889 		}
890 		else
891 		    DisplayBeep( NULL );
892 	    }
893 	}
894 	else if(c == '\033')
895 	{
896 	    return( -1 );
897 	}
898 	else if(c == '\b')
899 	{
900 	    if(did_comp){
901 		while(bufp!=obufp){
902 		    bufp--;
903 		    amii_curs(WIN_MESSAGE, --colx, bottom);
904 		    Text(w->RPort,spaces,1);
905 		    amii_curs(WIN_MESSAGE,colx,bottom);
906 		    did_comp=0;
907 		    sel = -1;
908 		}
909 	    }
910 	    else if(bufp != obufp)
911 	    {
912 		sel = -1;
913 		bufp--;
914 		amii_curs( WIN_MESSAGE, --colx, bottom);
915 		Text( w->RPort, spaces, 1 );
916 		amii_curs( WIN_MESSAGE, colx, bottom);
917 	    }
918 	    else
919 		DisplayBeep( NULL );
920 	}
921 	else if( c == '\n' || c == '\r' )
922 	{
923 	    return(sel);
924 	}
925 	else if( c >= ' ' && c < '\177')
926 	{
927 		/* avoid isprint() - some people don't have it
928 		   ' ' is not always a printing char */
929 	    *bufp = c;
930 	    bufp[1] = 0;
931 	    oindex = 0;
932 	    com_index = -1;
933 
934 	    while(extcmdlist[oindex].ef_txt != NULL)
935 	    {
936 		if(!strnicmp(obufp, (char *)extcmdlist[oindex].ef_txt, strlen(obufp)))
937 		{
938 		    if(com_index == -1) /* No matches yet*/
939 			com_index = oindex;
940 		    else /* More than 1 match */
941 			com_index = -2;
942 		}
943 		oindex++;
944 	    }
945 
946 	    if(com_index >= 0 && *obufp )
947 	    {
948 		Strcpy(obufp, extcmdlist[com_index].ef_txt);
949 		/* finish printing our string */
950 		colx = put_ext_cmd( obufp, colx, cw, bottom );
951 		bufp = obufp; /* reset it */
952 		if(strlen(obufp) < BUFSZ-1 && strlen(obufp) < COLNO)
953 		    bufp += strlen(obufp);
954 		did_comp=1;
955 		sel = com_index;
956 	    }
957 	    else
958 	    {
959 		colx = put_ext_cmd( obufp, colx, cw, bottom );
960 		if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
961 		    bufp++;
962 	    }
963 	}
964 	else if(c == ('X'-64) || c == '\177')
965 	{
966 	    colx = 0;
967 	    amii_clear_nhwindow( WIN_MESSAGE );
968 	    pline( "# " );
969 	    bufp = obufp;
970 	} else
971 	    DisplayBeep( NULL );
972     }
973     return(-1);
974 #endif
975 }
976 
977 static int
978 put_ext_cmd( obufp, colx, cw, bottom )
979     char *obufp;
980     int colx, bottom;
981     struct amii_WinDesc *cw;
982 {
983     struct Window *w = cw->win;
984     char *t;
985 
986     t = (char *)alloc( strlen( obufp ) + 7 );
987     if( t != NULL )
988     {
989 	if( scrollmsg )
990 	{
991 	    sprintf( t, "xxx%s", obufp );
992 	    t[0] = 1;
993 	    t[1] = 1;
994 	    t[2] = '#';
995 	    amii_curs( WIN_MESSAGE, 0, bottom);
996 	    SetAPen( w->RPort, C_WHITE );
997 	    Text(w->RPort, "># ", 3 );
998 	    /* SetAPen( w->RPort, C_BLACK ); */ /* Black text on black screen doesn't look too well ... -jhsa */
999 	    Text(w->RPort, t+3, strlen( t ) - 3 );
1000 	}
1001 	else
1002 	{
1003 	    sprintf( t, "# %s", obufp );
1004 	    amii_curs( WIN_MESSAGE, 0, bottom);
1005 	    SetAPen( w->RPort, C_WHITE );
1006 	    Text(w->RPort, t, strlen( t ) );
1007 	}
1008 	if( scrollmsg )
1009 	    SetAPen( w->RPort, C_WHITE );
1010 	if( cw->data[ cw->maxrow - 1 ] )
1011 	    free( cw->data[ cw->maxrow - 1 ] );
1012 	cw->data[ cw->maxrow - 1 ] = t;
1013     }
1014     else
1015     {
1016 	amii_curs( WIN_MESSAGE, 0, bottom);
1017 	SetAPen( w->RPort, C_WHITE );
1018 	Text(w->RPort, "# ", 2 );
1019 	/* SetAPen( w->RPort, C_BLACK ); */ /* Black on black ... -jhsa */
1020 	Text(w->RPort, obufp, strlen( obufp ) );
1021 	SetAPen( w->RPort, C_WHITE );
1022     }
1023     amii_curs( WIN_MESSAGE, colx = strlen( obufp ) + 3 + ( scrollmsg != 0 ), bottom);
1024     return( colx );
1025 }
1026 
1027 /* Ask a question and get a response */
1028 
1029 char amii_yn_function(query, resp, def)
1030 const char *query,*resp;
1031 char def;
1032 /*
1033  *   Generic yes/no function. 'def' is the default (returned by space or
1034  *   return; 'esc' returns 'q', or 'n', or the default, depending on
1035  *   what's in the string. The 'query' string is printed before the user
1036  *   is asked about the string.
1037  *   If resp is NULL, any single character is accepted and returned.
1038  *   If not-NULL, only characters in it are allowed (exceptions:  the
1039  *   quitchars are always allowed, and if it contains '#' then digits
1040  *   are allowed); if it includes an <esc>, anything beyond that won't
1041  *   be shown in the prompt to the user but will be acceptable as input.
1042  */
1043 {
1044 	register char q;
1045 	char rtmp[40];
1046 	boolean digit_ok, allow_num;
1047 	char prompt[QBUFSZ];
1048 	register struct amii_WinDesc *cw;
1049 
1050 	if( cw = amii_wins[ WIN_MESSAGE ] )
1051 	    cw->disprows = 0;
1052 	if (resp) {
1053 	    char *rb, respbuf[QBUFSZ];
1054 
1055   	    allow_num = (index(resp, '#') != 0);
1056 	    Strcpy(respbuf, resp);
1057 	    /* any acceptable responses that follow <esc> aren't displayed */
1058 	    if ((rb = index(respbuf, '\033')) != 0) *rb = '\0';
1059 	    Sprintf(prompt, "%s [%s] ", query, respbuf);
1060 	    if (def) Sprintf(eos(prompt), "(%c) ", def);
1061   	    pline("%s", prompt);
1062 	} else {
1063 	    amii_putstr(WIN_MESSAGE, 0, query);
1064 	    cursor_on(WIN_MESSAGE);
1065 	    q = WindowGetchar();
1066 	    cursor_off(WIN_MESSAGE);
1067 	    *rtmp = q;
1068 	    rtmp[ 1 ] = 0;
1069 	    amii_addtopl(rtmp);
1070 	    goto clean_up;
1071 	}
1072 
1073 	do {	/* loop until we get valid input */
1074 	    cursor_on(WIN_MESSAGE);
1075 	    q = lowc(WindowGetchar());
1076 	    cursor_off(WIN_MESSAGE);
1077 #if 0
1078 /* fix for PL2 */
1079 	    if (q == '\020') { /* ctrl-P */
1080 		if(!doprev) (void) tty_doprev_message(); /* need two initially */
1081 		(void) tty_doprev_message();
1082 		q = (char)0;
1083 		doprev = 1;
1084 		continue;
1085 	    } else if(doprev) {
1086 		tty_clear_nhwindow(WIN_MESSAGE);
1087 		cw->maxcol = cw->maxrow;
1088 		doprev = 0;
1089 		amii_addtopl(prompt);
1090 		continue;
1091 	    }
1092 #endif
1093 	    digit_ok = allow_num && isdigit(q);
1094 	    if (q == '\033') {
1095 		if (index(resp, 'q'))
1096 		    q = 'q';
1097 		else if (index(resp, 'n'))
1098 		    q = 'n';
1099 		else
1100 		    q = def;
1101 		break;
1102 	    } else if (index(quitchars, q)) {
1103 		q = def;
1104 		break;
1105 	    }
1106 	    if (!index(resp, q) && !digit_ok) {
1107 		amii_bell();
1108 		q = (char)0;
1109 	    } else if (q == '#' || digit_ok) {
1110 		char z, digit_string[2];
1111 		int n_len = 0;
1112 		long value = 0;
1113 		amii_addtopl("#"),  n_len++;
1114 		digit_string[1] = '\0';
1115 		if (q != '#') {
1116 		    digit_string[0] = q;
1117 		    amii_addtopl(digit_string),  n_len++;
1118 		    value = q - '0';
1119 		    q = '#';
1120 		}
1121 		do {	/* loop until we get a non-digit */
1122 		    cursor_on(WIN_MESSAGE);
1123 		    z = lowc(WindowGetchar());
1124 		    cursor_off(WIN_MESSAGE);
1125 		    if (isdigit(z)) {
1126 			value = (10 * value) + (z - '0');
1127 			if (value < 0) break;	/* overflow: try again */
1128 			digit_string[0] = z;
1129 			amii_addtopl(digit_string),  n_len++;
1130 		    } else if (z == 'y' || index(quitchars, z)) {
1131 			if (z == '\033')  value = -1;	/* abort */
1132 			z = '\n';	/* break */
1133 		    } else if ( z == '\b') {
1134 			if (n_len <= 1) { value = -1;  break; }
1135 			else { value /= 10;  removetopl(1),  n_len--; }
1136 		    } else {
1137 			value = -1;	/* abort */
1138 			amii_bell();
1139 			break;
1140 		    }
1141 		} while (z != '\n');
1142 		if (value > 0) yn_number = value;
1143 		else if (value == 0) q = 'n';		/* 0 => "no" */
1144 		else {	/* remove number from top line, then try again */
1145 			removetopl(n_len),  n_len = 0;
1146 			q = '\0';
1147 		}
1148 	    }
1149 	} while(!q);
1150 
1151 	if (q != '#' && q != '\033') {
1152 	    Sprintf(rtmp, "%c", q);
1153 	    amii_addtopl(rtmp);
1154 	}
1155     clean_up:
1156 	cursor_off(WIN_MESSAGE);
1157 	clear_nhwindow(WIN_MESSAGE);
1158 	return q;
1159 }
1160 
1161 void
1162 amii_display_file(fn, complain)
1163 const char *fn;
1164 boolean complain;
1165 {
1166     register struct amii_WinDesc *cw;
1167     register int win;
1168     register dlb *fp;
1169     register char *t;
1170     register char buf[ 200 ];
1171 
1172     if( fn == NULL )
1173 	panic("NULL file name in display_file()");
1174 
1175     if( ( fp = dlb_fopen( fn, RDTMODE ) ) == (dlb *)NULL )
1176     {
1177 	if (complain) {
1178 	    sprintf( buf, "Can't display %s: %s", fn,
1179 #ifdef _DCC
1180 			strerror(errno)
1181 #else
1182 # ifdef  __SASC_60
1183 			__sys_errlist[ errno ]
1184 # else
1185 			sys_errlist[ errno ]
1186 # endif
1187 #endif
1188 			);
1189 	    amii_addtopl( buf );
1190 	}
1191 	return;
1192     }
1193     win = amii_create_nhwindow( NHW_TEXT );
1194 
1195     /* Set window title to file name */
1196     if( cw = amii_wins[ win ] )
1197 	cw->morestr = (char *)fn;
1198 
1199     while( dlb_fgets( buf, sizeof( buf ), fp ) != NULL )
1200     {
1201 	if( t = index( buf, '\n' ) )
1202 	    *t = 0;
1203 	amii_putstr( win, 0, buf );
1204     }
1205     dlb_fclose( fp );
1206 
1207     /* If there were lines in the file, display those lines */
1208 
1209     if( amii_wins[ win ]->cury > 0 )
1210 	amii_display_nhwindow( win, TRUE );
1211 
1212     amii_wins[win]->morestr = NULL;		/* don't free title string */
1213     amii_destroy_nhwindow( win );
1214 }
1215 
1216 /* Put a 3-D motif border around the gadget.  String gadgets or those
1217  * which do not have highlighting are rendered down.  Boolean gadgets
1218  * are rendered in the up position by default.
1219  */
1220 
1221 void
1222 SetBorder( gd )
1223     register struct Gadget *gd;
1224 {
1225     register struct Border *bp;
1226     register short *sp;
1227     register int i, inc = -1, dec = -1;
1228     int borders = 6;
1229     int hipen = flags.amii_dripens[ SHINEPEN ], shadowpen = flags.amii_dripens[ SHADOWPEN ];
1230 #ifdef	INTUI_NEW_LOOK
1231     struct DrawInfo *dip;
1232 #endif
1233 
1234 #ifdef	INTUI_NEW_LOOK
1235     if( IntuitionBase->LibNode.lib_Version >= 37 )
1236     {
1237 	if( dip = GetScreenDrawInfo( HackScreen ) )
1238 	{
1239 	    hipen = dip->dri_Pens[ SHINEPEN ];
1240 	    shadowpen = dip->dri_Pens[ SHADOWPEN ];
1241 	    FreeScreenDrawInfo( HackScreen, dip );
1242 	}
1243     }
1244 #endif
1245     /* Allocate two border structures one for up image and one for down
1246      * image, plus vector arrays for the border lines.
1247      */
1248 
1249     if( gd->GadgetType == STRGADGET )
1250 	borders = 12;
1251 
1252     if( ( bp = (struct Border *)alloc( ( ( sizeof( struct Border ) * 2 ) +
1253 			( sizeof( short ) * borders ) ) * 2 ) ) == NULL )
1254     {
1255 	return;
1256     }
1257 
1258     /* For a string gadget, we expand the border beyond the area where
1259      * the text will be entered.
1260      */
1261 
1262     /* Remove any special rendering flags to avoid confusing intuition
1263      */
1264 
1265     gd->Flags &= ~(GADGHIGHBITS|GADGIMAGE);
1266 
1267     sp = (short *)(bp + 4);
1268     if( gd->GadgetType == STRGADGET || ( gd->GadgetType == BOOLGADGET &&
1269 			    ( gd->Flags & GADGHIGHBITS ) == GADGHNONE ) )
1270     {
1271 	sp[0] = -1;
1272 	sp[1] = gd->Height - 1;
1273 	sp[2] = -1;
1274 	sp[3] = -1;
1275 	sp[4] = gd->Width - 1;
1276 	sp[5] = -1;
1277 
1278 	sp[6] = gd->Width + 1;
1279 	sp[7] = -2;
1280 	sp[8] = gd->Width + 1;
1281 	sp[9] = gd->Height + 1;
1282 	sp[10] = -2;
1283 	sp[11] = gd->Height + 1;
1284 
1285 	sp[12] = -2;
1286 	sp[13] = gd->Height;
1287 	sp[14] = -2;
1288 	sp[15] = -2;
1289 	sp[16] = gd->Width;
1290 	sp[17] = -2;
1291 	sp[18] = gd->Width;
1292 	sp[19] = gd->Height;
1293 	sp[20] = -2;
1294 	sp[21] = gd->Height;
1295 
1296 	for( i = 0; i < 3; ++i )
1297 	{
1298 	    bp[ i ].LeftEdge = bp[ i ].TopEdge = -1;
1299 	    bp[ i ].FrontPen = ( i == 0 || i == 1 ) ? shadowpen : hipen;
1300 
1301 	    /* Have to use JAM2 so that the old colors disappear. */
1302 	    bp[ i ].BackPen = C_BLACK;
1303 	    bp[ i ].DrawMode = JAM2;
1304 	    bp[ i ].Count = ( i == 0 || i == 1 ) ? 3 : 5;
1305 	    bp[ i ].XY = &sp[ i*6 ];
1306 	    bp[ i ].NextBorder = ( i == 2 ) ? NULL : &bp[ i + 1 ];
1307 	}
1308 
1309 	/* bp[0] and bp[1] two pieces for the up image */
1310 	gd->GadgetRender = (APTR) bp;
1311 
1312 	/* No image change for select */
1313 	gd->SelectRender = (APTR) bp;
1314 
1315 	gd->LeftEdge++;
1316 	gd->TopEdge++;
1317 	gd->Flags |= GADGHCOMP;
1318     }
1319     else
1320     {
1321 	/* Create the border vector values for up and left side, and
1322 	 * also the lower and right side.
1323 	 */
1324 
1325 	sp[0] = dec;
1326 	sp[1] = gd->Height + inc;
1327 	sp[2] = dec;
1328 	sp[3] = dec;
1329 	sp[4] = gd->Width + inc;
1330 	sp[5] = dec;
1331 
1332 	sp[6] = gd->Width + inc;
1333 	sp[7] = dec;
1334 	sp[8] = gd->Width + inc;
1335 	sp[9] = gd->Height + inc;
1336 	sp[10] = dec;
1337 	sp[11] = gd->Height + inc;
1338 
1339 	/* We are creating 4 sets of borders, the two sides of the
1340 	 * rectangle share the border vectors with the opposite image,
1341 	 * but specify different colors.
1342 	 */
1343 
1344 	for( i = 0; i < 4; ++i )
1345 	{
1346 	    bp[ i ].TopEdge = bp[ i ].LeftEdge = 0;
1347 
1348 	    /* A GADGHNONE is always down */
1349 
1350 	    if( gd->GadgetType == BOOLGADGET &&
1351 			    ( gd->Flags & GADGHIGHBITS ) != GADGHNONE )
1352 	    {
1353 		bp[ i ].FrontPen =
1354 			    ( i == 1 || i == 2 ) ? shadowpen : hipen;
1355 	    }
1356 	    else
1357 	    {
1358 		bp[ i ].FrontPen =
1359 			    ( i == 1 || i == 3 ) ? hipen : shadowpen;
1360 	    }
1361 
1362 	    /* Have to use JAM2 so that the old colors disappear. */
1363 	    bp[ i ].BackPen = C_BLACK;
1364 	    bp[ i ].DrawMode = JAM2;
1365 	    bp[ i ].Count = 3;
1366 	    bp[ i ].XY = &sp[ 6 * ((i &1) != 0) ];
1367 	    bp[ i ].NextBorder =
1368 			    ( i == 1 || i == 3 ) ? NULL : &bp[ i + 1 ];
1369 	}
1370 
1371 	/* bp[0] and bp[1] two pieces for the up image */
1372 	gd->GadgetRender = (APTR) bp;
1373 
1374 	/* bp[2] and bp[3] two pieces for the down image */
1375 	gd->SelectRender = (APTR) (bp + 2);
1376 	gd->Flags |= GADGHIMAGE;
1377     }
1378 }
1379 
1380 /* Following function copied from wintty.c */
1381 /* Modified slightly to fit amiga needs */
1382 
1383 void
1384 amii_player_selection()
1385 {
1386 	int i, k, n;
1387 	char pick4u = 'n', thisch, lastch = 0;
1388 	char pbuf[QBUFSZ];
1389 	winid win;
1390 	anything any;
1391 	menu_item *selected = 0;
1392 
1393 	/* Should we randomly pick for the player? */
1394 	if (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
1395 		flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) {
1396 	    const char *prompt = "Shall I pick a character for you?";
1397 	    pick4u = amii_yn_function(prompt, "ynq", 'y');
1398 
1399 	    if (pick4u != 'y' && pick4u != 'n') {
1400 give_up:	/* Quit */
1401 		if (selected) free((genericptr_t) selected);
1402 		exit_nhwindows(NULL);
1403 		terminate(0);
1404 		/*NOTREACHED*/
1405 		return;
1406 	    }
1407 	}
1408 
1409 	/* Select a role, if necessary */
1410 	/* we'll try to be compatible with pre-selected race/gender/alignment,
1411 	 * but may not succeed */
1412 	if (flags.initrole < 0) {
1413 	    /* Process the choice */
1414 	    if (pick4u == 'y' || flags.initrole == ROLE_RANDOM) {
1415 		/* Pick a random role */
1416 		flags.initrole = pick_role(flags.initrace, flags.initgend,
1417 						flags.initalign);
1418 		if (flags.initrole < 0) {
1419 		    amii_putstr(WIN_MESSAGE, 0, "Incompatible role!");
1420 		    flags.initrole = randrole();
1421 		}
1422 	    } else {
1423 		/* Prompt for a role */
1424 		win = create_nhwindow(NHW_MENU);
1425 		start_menu(win);
1426 		any.a_void = 0;         /* zero out all bits */
1427 		for (i = 0; roles[i].name.m; i++) {
1428 		    if (ok_role(i, flags.initrace, flags.initgend,
1429 							flags.initalign)) {
1430 			any.a_int = i+1;	/* must be non-zero */
1431 			thisch = lowc(roles[i].name.m[0]);
1432 			if (thisch == lastch) thisch = highc(thisch);
1433 			add_menu(win, NO_GLYPH, &any, thisch,
1434 			    0, ATR_NONE, an(roles[i].name.m), MENU_UNSELECTED);
1435 			lastch = thisch;
1436 		    }
1437 		}
1438 		any.a_int = pick_role(flags.initrace, flags.initgend,
1439 				    flags.initalign)+1;
1440 		if (any.a_int == 0)	/* must be non-zero */
1441 		    any.a_int = randrole()+1;
1442 		add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1443 				"Random", MENU_UNSELECTED);
1444 		any.a_int = i+1;	/* must be non-zero */
1445 		add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1446 				"Quit", MENU_UNSELECTED);
1447 		end_menu(win, "Pick a role");
1448 		n = select_menu(win, PICK_ONE, &selected);
1449 		destroy_nhwindow(win);
1450 
1451 		/* Process the choice */
1452 		if (n != 1 || selected[0].item.a_int == any.a_int)
1453 		    goto give_up;		/* Selected quit */
1454 
1455 		flags.initrole = selected[0].item.a_int - 1;
1456 		free((genericptr_t) selected),	selected = 0;
1457 	    }
1458 	}
1459 
1460 	/* Select a race, if necessary */
1461 	/* force compatibility with role, try for compatibility with
1462 	 * pre-selected gender/alignment */
1463 	if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
1464 	    /* pre-selected race not valid */
1465 	    if (pick4u == 'y' || flags.initrace == ROLE_RANDOM) {
1466 		flags.initrace = pick_race(flags.initrole, flags.initgend,
1467 							flags.initalign);
1468 		if (flags.initrace < 0) {
1469 		    amii_putstr(WIN_MESSAGE, 0, "Incompatible race!");
1470 		    flags.initrace = randrace(flags.initrole);
1471 		}
1472 	    } else {	/* pick4u == 'n' */
1473 		/* Count the number of valid races */
1474 		n = 0;	/* number valid */
1475 		k = 0;	/* valid race */
1476 		for (i = 0; races[i].noun; i++) {
1477 		    if (ok_race(flags.initrole, i, flags.initgend,
1478 							flags.initalign)) {
1479 			n++;
1480 			k = i;
1481 		    }
1482 		}
1483 		if (n == 0) {
1484 		    for (i = 0; races[i].noun; i++) {
1485 			if (validrace(flags.initrole, i)) {
1486 			    n++;
1487 			    k = i;
1488 			}
1489 		    }
1490 		}
1491 
1492 		/* Permit the user to pick, if there is more than one */
1493 		if (n > 1) {
1494 		    win = create_nhwindow(NHW_MENU);
1495 		    start_menu(win);
1496 		    any.a_void = 0;         /* zero out all bits */
1497 		    for (i = 0; races[i].noun; i++)
1498 			if (ok_race(flags.initrole, i, flags.initgend,
1499 							flags.initalign)) {
1500 			    any.a_int = i+1;	/* must be non-zero */
1501 			    add_menu(win, NO_GLYPH, &any, races[i].noun[0],
1502 				0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
1503 			}
1504 		    any.a_int = pick_race(flags.initrole, flags.initgend,
1505 					flags.initalign)+1;
1506 		    if (any.a_int == 0)	/* must be non-zero */
1507 			any.a_int = randrace(flags.initrole)+1;
1508 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1509 				    "Random", MENU_UNSELECTED);
1510 		    any.a_int = i+1;	/* must be non-zero */
1511 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1512 				    "Quit", MENU_UNSELECTED);
1513 		    Sprintf(pbuf, "Pick the race of your %s",
1514 				    roles[flags.initrole].name.m);
1515 		    end_menu(win, pbuf);
1516 		    n = select_menu(win, PICK_ONE, &selected);
1517 		    destroy_nhwindow(win);
1518 		    if (n != 1 || selected[0].item.a_int == any.a_int)
1519 			goto give_up;		/* Selected quit */
1520 
1521 		    k = selected[0].item.a_int - 1;
1522 		    free((genericptr_t) selected),	selected = 0;
1523 		}
1524 		flags.initrace = k;
1525 	    }
1526 	}
1527 
1528 	/* Select a gender, if necessary */
1529 	/* force compatibility with role/race, try for compatibility with
1530 	 * pre-selected alignment */
1531 	if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
1532 						flags.initgend)) {
1533 	    /* pre-selected gender not valid */
1534 	    if (pick4u == 'y' || flags.initgend == ROLE_RANDOM) {
1535 		flags.initgend = pick_gend(flags.initrole, flags.initrace,
1536 						flags.initalign);
1537 		if (flags.initgend < 0) {
1538 		    amii_putstr(WIN_MESSAGE, 0, "Incompatible gender!");
1539 		    flags.initgend = randgend(flags.initrole, flags.initrace);
1540 		}
1541 	    } else {	/* pick4u == 'n' */
1542 		/* Count the number of valid genders */
1543 		n = 0;	/* number valid */
1544 		k = 0;	/* valid gender */
1545 		for (i = 0; i < ROLE_GENDERS; i++) {
1546 		    if (ok_gend(flags.initrole, flags.initrace, i,
1547 							flags.initalign)) {
1548 			n++;
1549 			k = i;
1550 		    }
1551 		}
1552 		if (n == 0) {
1553 		    for (i = 0; i < ROLE_GENDERS; i++) {
1554 			if (validgend(flags.initrole, flags.initrace, i)) {
1555 			    n++;
1556 			    k = i;
1557 			}
1558 		    }
1559 		}
1560 
1561 		/* Permit the user to pick, if there is more than one */
1562 		if (n > 1) {
1563 		    win = create_nhwindow(NHW_MENU);
1564 		    start_menu(win);
1565 		    any.a_void = 0;         /* zero out all bits */
1566 		    for (i = 0; i < ROLE_GENDERS; i++)
1567 			if (ok_gend(flags.initrole, flags.initrace, i,
1568 							    flags.initalign)) {
1569 			    any.a_int = i+1;
1570 			    add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
1571 				0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
1572 			}
1573 		    any.a_int = pick_gend(flags.initrole, flags.initrace,
1574 					    flags.initalign)+1;
1575 		    if (any.a_int == 0)	/* must be non-zero */
1576 			any.a_int = randgend(flags.initrole, flags.initrace)+1;
1577 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1578 				    "Random", MENU_UNSELECTED);
1579 		    any.a_int = i+1;	/* must be non-zero */
1580 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1581 				    "Quit", MENU_UNSELECTED);
1582 		    Sprintf(pbuf, "Pick the gender of your %s %s",
1583 				    races[flags.initrace].adj,
1584 				    roles[flags.initrole].name.m);
1585 		    end_menu(win, pbuf);
1586 		    n = select_menu(win, PICK_ONE, &selected);
1587 		    destroy_nhwindow(win);
1588 		    if (n != 1 || selected[0].item.a_int == any.a_int)
1589 			goto give_up;		/* Selected quit */
1590 
1591 		    k = selected[0].item.a_int - 1;
1592 		    free((genericptr_t) selected),	selected = 0;
1593 		}
1594 		flags.initgend = k;
1595 	    }
1596 	}
1597 
1598 	/* Select an alignment, if necessary */
1599 	/* force compatibility with role/race/gender */
1600 	if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
1601 							flags.initalign)) {
1602 	    /* pre-selected alignment not valid */
1603 	    if (pick4u == 'y' || flags.initalign == ROLE_RANDOM) {
1604 		flags.initalign = pick_align(flags.initrole, flags.initrace,
1605 							flags.initgend);
1606 		if (flags.initalign < 0) {
1607 		    amii_putstr(WIN_MESSAGE, 0, "Incompatible alignment!");
1608 		    flags.initalign = randalign(flags.initrole, flags.initrace);
1609 		}
1610 	    } else {	/* pick4u == 'n' */
1611 		/* Count the number of valid alignments */
1612 		n = 0;	/* number valid */
1613 		k = 0;	/* valid alignment */
1614 		for (i = 0; i < ROLE_ALIGNS; i++) {
1615 		    if (ok_align(flags.initrole, flags.initrace, flags.initgend,
1616 							i)) {
1617 			n++;
1618 			k = i;
1619 		    }
1620 		}
1621 		if (n == 0) {
1622 		    for (i = 0; i < ROLE_ALIGNS; i++) {
1623 			if (validalign(flags.initrole, flags.initrace, i)) {
1624 			    n++;
1625 			    k = i;
1626 			}
1627 		    }
1628 		}
1629 
1630 		/* Permit the user to pick, if there is more than one */
1631 		if (n > 1) {
1632 		    win = create_nhwindow(NHW_MENU);
1633 		    start_menu(win);
1634 		    any.a_void = 0;         /* zero out all bits */
1635 		    for (i = 0; i < ROLE_ALIGNS; i++)
1636 			if (ok_align(flags.initrole, flags.initrace,
1637 							flags.initgend, i)) {
1638 			    any.a_int = i+1;
1639 			    add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
1640 				 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
1641 			}
1642 		    any.a_int = pick_align(flags.initrole, flags.initrace,
1643 					    flags.initgend)+1;
1644 		    if (any.a_int == 0)	/* must be non-zero */
1645 			any.a_int = randalign(flags.initrole, flags.initrace)+1;
1646 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1647 				    "Random", MENU_UNSELECTED);
1648 		    any.a_int = i+1;	/* must be non-zero */
1649 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1650 				    "Quit", MENU_UNSELECTED);
1651 		    Sprintf(pbuf, "Pick the alignment of your %s %s %s",
1652 			    genders[flags.initgend].adj,
1653 			    races[flags.initrace].adj,
1654 			    (flags.initgend && roles[flags.initrole].name.f) ?
1655 			    roles[flags.initrole].name.f :
1656 			    roles[flags.initrole].name.m);
1657 		    end_menu(win, pbuf);
1658 		    n = select_menu(win, PICK_ONE, &selected);
1659 		    destroy_nhwindow(win);
1660 		    if (n != 1 || selected[0].item.a_int == any.a_int)
1661 			goto give_up;		/* Selected quit */
1662 
1663 		    k = selected[0].item.a_int - 1;
1664 		    free((genericptr_t) selected),	selected = 0;
1665 		}
1666 		flags.initalign = k;
1667 	    }
1668 	}
1669 	/* Success! */
1670 }
1671 #endif /* AMIGA_INTUITION */
1672