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