1 /*    SCCS Id: @(#)wb.c     2.1   93/01/08			  */
2 /*    Copyright (c) Kenneth Lorber, Bethesda Maryland, 1991	  */
3 /*    Copyright (c) Gregg Wonderly, Naperville IL, 1992, 1993	  */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 /* Friendly Intuition interface for NetHack 3.1 on the Amiga */
7 
8 #ifdef AZTEC_C
9 /* Aztec doesn't recognize __chip syntax */
10 # define __chip
11 #endif
12 
13 
14 #include "patchlevel.h"
15 
16 #include "NH:sys/amiga/wbdefs.h"		/* Miscellany information */
17 #ifdef  INTUI_NEW_LOOK
18 #define NewWindow   ExtNewWindow
19 #define NewScreen   ExtNewScreen
20 #endif
21 #include "NH:sys/amiga/wbstruct.h"
22 #include "NH:sys/amiga/wbprotos.h"
23 
24 #include "NH:sys/amiga/wbdata.c"		/* All structures and global data */
25 #include "NH:sys/amiga/wbwin.c"		/* Has static definitions */
26 
27 #define	OPTION_LISTS_ONLY
28 #include <time.h>
29 #include "hack.h"
30 #undef exit
31 #include "NH:src/options.c"
32 
33 #include "NH:sys/amiga/wbgads.c"
34 
35 #ifdef _DCC
36 /* DICE doesn't have a putenv() */
putenv(varstr)37 void putenv(varstr)
38 char *varstr;
39 {
40 	FILE *f;
41 	char var[64],str[256];
42 	int i,j;
43 
44 	for(i = 0; varstr[i] != '='; i++);
45 	for(j = i - 1; varstr[j] == ' '; j--);
46 	strncpy(var, varstr, j+1); var[j+1] = 0;
47 	while(varstr[++i] == ' ');
48 	varstr += i;
49 	i = 0;
50 	if(*varstr == '"') {
51 		while(varstr[++i] != '"');
52 		strncpy(str, varstr+1, i-1); str[i-1] = 0;
53 	} else
54 		strcpy(str, varstr);
55 	setenv(var, str);
56 }
57 #endif
58 
59 #define C_GREY  0
60 #define C_BLACK 1
61 #define C_WHITE 2
62 #define C_BLUE  3
63 
64 #if !defined(__SASC_60) && !defined(_DCC)
65 extern char *sys_errlist[];
66 #endif
67 extern int errno;
68 
69 #ifdef	static
70 static can not be redefined for this file to compile correctly
71 #endif
72 
73 char pubscreen[ 80 ] = { "HackWB" };
74 
75 #ifdef  INTUI_NEW_LOOK
76 int scrlocked = 0;
77 UWORD scrnpens[] = {
78 	0,
79 	1,
80 	2,
81 	2,
82 	1,
83 	3,
84 	2,
85 	0,
86 	3,
87 };
88 
89 struct TagItem scrntags[] =
90 {
91     (Tag)SA_Pens, (ULONG)scrnpens,
92     TAG_DONE, 0,
93     TAG_DONE, 0,
94     TAG_DONE, 0,
95     TAG_DONE, 0,
96     TAG_DONE, 0,
97     TAG_DONE, 0,
98     TAG_DONE, 0,
99 };
100 #endif
101 
102 char scrntitle[ 90 ];
103 
104 #define SPLIT			/* use splitter, if available */
105 #ifdef SPLIT
106 int running_split=0;		/* if 0, using normal LoadSeg/UnLoadSeg */
107 #endif
108 
109 #ifdef AZTEC_C
110 extern char *strdup(char *);
111 #endif
112 
113 #ifndef max
114 # define max(a, b) ((a) > (b) ? (a) : (b))
115 #endif
116 #ifndef min
117 # define min(x,y) ((x) < (y) ? (x) : (y))
118 #endif
119 
120 void diskobj_filter(struct DiskObject *);
121 static void UpdateInfoWin( struct Window *cwin );
122 BPTR s_LoadSeg(char *);
123 void s_UnLoadSeg(void);
124 
125 #ifdef _DCC
126 /* Provide DICE with the wbmain() entry point it wants. */
127 wbmain(struct WBStartup *WBMsg)
128 {
129 	main(0, (char **)WBMsg);
130 }
131 #endif
132 
133 main( argc, argv )
134     int argc;
135     char **argv;
136 {
137     long mask, rmask;
138     struct WBStartup *wbs;
139     struct WBArg *wba;
140     GPTR gptr;
141     struct IntuiMessage *imsg;
142     struct IntuiMessage mimsg;
143     int i;
144 
145     /* Initialize and load libraries. */
146     InitWB( argc, (struct WBStartup *)argv );
147 
148     /* open window, build menus */
149     SetupWB( );
150 
151     /* Initialize the bool and comp option values */
152     ZapOptions();
153 
154     errmsg( NO_FLASH, "Welcome to NetHack Version %d.%d.%d!",
155       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
156 
157     CopyRight( );
158 
159     ReadConfig( );
160 
161     /* Initially, no game selected so disable menu items */
162 
163     ChgGameItems( &MenuList1, 0 );
164 
165     MapGadgets( R_DISK, 1 ); /* Display the icons */
166 
167     /* Wait till user quits */
168 
169     while( !quit )
170     {
171 	/* Wait for a message */
172 
173 	mask = ( 1L << dosport->mp_SigBit ) ;
174 	if( wbopen )
175 	    mask |= ( 1L << win->UserPort->mp_SigBit );
176 
177 	rmask = Wait( mask );
178 
179 	/* Process the messages on the port unless the workbench is
180 	 * shutdown by a request to play a game.
181 	 */
182 
183 	while( wbopen && ( imsg = ( struct IntuiMessage * )
184 	    GetMsg( win->UserPort ) ) )
185 	{
186 	    /* Copy the message.  This does not guarantee that all
187 	     * fields will still be valid, but appears to work
188 	     * here.  Note that we have to reply to the message
189 	     * before the workbench window is closed.
190 	     */
191 
192 	    mimsg = *imsg;
193 	    ReplyMsg( (struct Message *)imsg );
194 
195 	    switch( mimsg.Class )
196 	    {
197 	    case NEWSIZE:
198 		((struct Border *) Message.GadgetRender)->XY[2] =
199 		    win->Width - win->BorderLeft -
200 		    win->BorderRight - 1;
201 		RefreshGList( &Message, win, NULL, 1 );
202 		MapGadgets( R_SCROLL, 1 ); /* redisplay the icons */
203 #ifdef  INTUI_NEW_LOOK
204 		if( IntuitionBase->LibNode.lib_Version >= 37 )
205 		    RefreshWindowFrame( win );
206 #endif
207 		break;
208 
209 	    case MENUPICK:
210 		if( errup > 0 )
211 		{
212 		    errmsg( NO_FLASH, "" );
213 		    errup = -1;
214 		}
215 		do_menu( &MenuList1, mimsg.Code );
216 		flushIDCMP( win->UserPort );
217 		break;
218 
219 	    case RAWKEY:
220 		if( mimsg.Code == 0x5f )
221 		{
222 		    if( errup > 0 )
223 		    {
224 			errmsg( NO_FLASH, "" );
225 			errup = -1;
226 		    }
227 
228 		    /* Pick the correct help message */
229 
230 		    SetPointer( win, waitPointer, 16, 16, -6, 0 );
231 		    if( lastgaddown == NULL )
232 		    {
233 			text_requester( &Help1_NewWindowStructure7,
234 			    &Help1_IntuiTextList7 );
235 		    }
236 		    else
237 		    {
238 			text_requester( &Help2_NewWindowStructure8,
239 			    &Help2_IntuiTextList8 );
240 		    }
241 		    ClearPointer( win );
242 		}
243 		flushIDCMP( win->UserPort );
244 		break;
245 
246 	    case CLOSEWINDOW:
247 		SetPointer( win, waitPointer, 16, 16, -6, 0 );
248 		if( Ask( "Ready to Quit?" ) )
249 		    do_closewindow( );
250 		ClearPointer( win );
251 		break;
252 
253 	    case GADGETDOWN:
254 		if( errup > 0 )
255 		{
256 		    errmsg( NO_FLASH, "" );
257 		    errup = -1;
258 		}
259 		do_gadgetdown( &mimsg );
260 		break;
261 
262 	    case GADGETUP:
263 		do_gadgetup( &mimsg );
264 		break;
265 
266 	    case DISKINSERTED:
267 		if( errup > 0 )
268 		{
269 		    errmsg( NO_FLASH, "" );
270 		    errup = -1;
271 		}
272 		MapGadgets( R_DISK, 1 );
273 		break;
274 
275 	    case MOUSEBUTTONS:
276 		if( errup > 0 )
277 		{
278 		    errmsg( NO_FLASH, "" );
279 		    errup = -1;
280 		}
281 		do_buttons( &mimsg );
282 		flushIDCMP( win->UserPort );
283 		break;
284 	    }
285 	}
286 	if( errup == -1 )
287 	    errup = 0;
288 
289 	if( rmask & ( 1L << dosport->mp_SigBit ) )
290 	{
291 	    /* Get process termination messages */
292 
293 	    while( wbs = (struct WBStartup *) GetMsg( dosport ) )
294 	    {
295 		/* Find the game that has terminated */
296 
297 		for( gptr = gamehead; gptr && gptr->seglist != wbs->sm_Segment;)
298 		    gptr = gptr->next;
299 
300 		/* Make sure it is there */
301 
302 		if( gptr )
303 		{
304 #ifdef SPLIT
305 		    if(!running_split)
306 #endif
307 		    {
308 			/* Unload the code */
309 			UnLoadSeg( wbs->sm_Segment );
310 		    }
311 
312 		    /* Free the startup message resources */
313 		    wba = (struct WBArg *)
314 			((long)wbs + sizeof( struct WBStartup ));
315 		    for( i = 0; i < wbs->sm_NumArgs; ++i )
316 		    {
317 			FreeMem( wba[i].wa_Name,
318 			    strlen( wba[i].wa_Name ) + 1 );
319 			UnLock( wba[i].wa_Lock );
320 		    }
321 		    FreeMem( wbs, wbs->sm_Message.mn_Length );
322 		    wbs = NULL;
323 
324 		    /* Say the game has completed */
325 
326 		    gptr->prc = NULL;
327 		    gptr->active = 0;
328 		    active_count--;
329 		}
330 		else
331 		{
332 		    errmsg( FLASH, "Game termination detected, but game not found" );
333 		}
334 	    }
335 
336 	    /* If the workbench was closed, open it back up */
337 
338 	    if( !wbopen )
339 		SetupWB( );
340 
341 	    /* Reload to clear any deleted games */
342 
343 	    MapGadgets( R_DISK, 1 );
344 	}
345     }
346     cleanup( 0 );
347 }
348 
349 void
350 flushIDCMP( port )
351 	struct MsgPort *port;
352 {
353 	struct Message *msg;
354 
355 	while( msg = GetMsg( port ) )
356 		ReplyMsg( msg );
357 
358 	SetSignal( 0L, ( 1L << port->mp_SigBit ) );
359 }
360 
361 void CopyRight( )
362 {
363     extern char *copyright_text[];
364     int line;
365 
366     SetDrMd( win->RPort, JAM2 );
367     SetAPen( win->RPort, C_WHITE );
368     SetBPen( win->RPort, C_GREY );
369 
370     for(line=0;copyright_text[line];line++){
371 	Move( win->RPort, ORIGINX+3, ORIGINY + win->RPort->TxBaseline +
372 		(line*win->RPort->TxHeight));
373 	if(copyright_text[line][0])
374 	     RPText( win->RPort, copyright_text[line]);
375     }
376 
377     Delay( 150 );
378     ClearWindow( win );
379 }
380 
381 /*
382  * Do the one time initialization things.
383  */
384 
385 void
386 InitWB( argc, wbs )
387     int argc;
388     register struct WBStartup *wbs;
389 {
390     register int c, i, j;
391     BPTR odir;
392     char *s, **tools, **argv;
393     register struct DiskObject *dobj;
394     register struct WBArg *wba;
395 
396     /* Open Libraries */
397     GfxBase= (struct GfxBase *) OldOpenLibrary("graphics.library");
398     IconBase= OldOpenLibrary("icon.library");
399     DiskfontBase= (struct DiskfontBase *)OldOpenLibrary("diskfont.library");
400     IntuitionBase= (struct IntuitionBase *)OldOpenLibrary("intuition.library");
401 
402     if(!GfxBase || !IconBase || !DiskfontBase || !IntuitionBase)
403     {
404 	error("library open failed");
405 	cleanup( 1 );
406     }
407 
408     /* Get Port for replied WBStartup messages */
409 
410     if( ( dosport = CreatePort( NULL, 0 ) ) == NULL )
411     {
412 	error("failed to create dosport" );
413 	cleanup( 1 );
414     }
415 
416     /* If started from CLI */
417     if( argc != 0 )
418     {
419 	argv = (char **)wbs;
420 	for( i = 1; i < argc; ++i )
421 	{
422 	    if( argv[i][0] == '?' )goto usage;
423 	    if( argv[i][0] != '-' )
424 		break;
425 	    for( j = 1; c = argv[i][j]; ++j )
426 	    {
427 		switch( c )
428 		{
429 		case 'm':   /* Close screen and window during game to
430 			     * save memory  */
431 		    shutdown++;
432 		    break;
433 
434 		case 'c':       /* Configuration to load */
435 		    if( i + 1 < argc && argv[i][j+1] == 0 )
436 		    {
437 			strcpy( StrConf, argv[ ++i ] );
438 			goto nextargv;
439 		    }
440 		    else
441 		    {
442 			fprintf( stderr,
443 			    "%s: missing config name after -c\n",
444 			    argv[ 0 ] );
445 			cleanup( 1 );
446 		    }
447 		    break;
448 
449 		case 'N':       /* Public screen name */
450 		    if( i + 1 < argc && argv[i][j+1] == 0 )
451 		    {
452 			strcpy( pubscreen, argv[ ++i ] );
453 			goto nextargv;
454 		    }
455 		    else
456 		    {
457 			fprintf( stderr,
458 			    "%s: missing screen name after -N\n",
459 			    argv[ 0 ] );
460 			cleanup( 1 );
461 		    }
462 		    break;
463 
464 		default:
465 		    fprintf( stderr, "%s: invalid option %c\n",
466 			argv[0], c );
467 usage:
468 		    fprintf( stderr,
469 "usage: %s [-m] [-f .def filename] [-c config filename] [ -N screen]\n",
470 			argv[ 0 ] );
471 		    cleanup( 1 );
472 		}
473 	    }
474 nextargv:;
475 	}
476     }
477     else
478     {
479 	/* Process icon's ToolTypes */
480 
481 	wba = wbs->sm_ArgList;
482 	odir = CurrentDir( wba->wa_Lock );
483 	if( dobj = GetDiskObject( wba->wa_Name ) )
484 	{
485 	    tools = (char **) dobj->do_ToolTypes;
486 
487 	    if( s = FindToolType( tools, "OPTIONS" ) )
488 	    {
489 		/* OPTIONS=SHUTDOWN will cause the screen to be closed
490 		 * when a game is started
491 		 */
492 		if( MatchToolValue( s, "SHUTDOWN" ) )
493 		    ++shutdown;
494 	    }
495 
496 	    /* A different configuration file name */
497 
498 	    if( s = FindToolType( tools, "CONFIG" ) )
499 	    {
500 		strcpy( StrConf, s );
501 	    }
502 
503 	    /* A Public screen to open onto */
504 
505 	    if( s = FindToolType( tools, "SCREEN" ) )
506 	    {
507 		strcpy( pubscreen, s );
508 	    }
509 
510 	    FreeDiskObject( dobj );
511 	}
512 	if( odir )
513 	    CurrentDir( odir );
514     }
515 }
516 
517 /*
518  * Read a nethack.cnf like file and collect the configuration
519  * information from it.
520  */
521 void ReadConfig()
522 {
523     register FILE *fp;
524     register char *buf, *t;
525 
526     /* Use a dynamic buffer to limit stack use */
527 
528     if( ( buf = xmalloc( 1024 ) ) == NULL )
529     {
530 	error( "Can't alloc space to read config file" );
531 	cleanup( 1 );
532     }
533 
534     /* If the file is not there, can't load it */
535 
536     if( ( fp = fopen( StrConf, "r" ) ) == NULL )
537     {
538 	errmsg( FLASH, "Can't load config file %s", StrConf );
539 	free( buf );
540 	return;
541     }
542 
543     /* Read the lines... */
544 
545     while( fgets( buf, 1024, fp ) != NULL )
546     {
547 	if( *buf == '#' )
548 	    continue;
549 
550 	if( ( t = strchr( buf, '\n' ) ) != NULL )
551 	    *t = 0;
552 
553 	if( strnicmp( buf, "PATH=", 5 ) == 0 )
554 	{
555 	    setoneopt( PATH_IDX, buf + 5 );
556 	}
557 	else if( strnicmp( buf, "PENS=", 4 ) == 0 )
558 	{
559 	    setoneopt( PENS_IDX, buf + 5 );
560 	}
561 	else if( strnicmp( buf, "OPTIONS=", 8 ) == 0 )
562 	{
563 	    setoneopt( OPTIONS_IDX, buf + 8 );
564 	    ParseOptionStr( buf + 8 );
565 	}
566 	else if( strnicmp( buf, "HACKDIR=", 8 ) == 0 )
567 	{
568 	    setoneopt( HACKDIR_IDX, buf + 8 );
569 	}
570 	else if( strnicmp( buf, "LEVELS=", 7 ) == 0 )
571 	{
572 	    setoneopt( LEVELS_IDX, buf + 7 );
573 	}
574 	else if( strnicmp( buf, "SAVE=", 5 ) == 0 )
575 	{
576 	    setoneopt( SAVE_IDX, buf + 5 );
577 	}
578 	else
579 	{
580 	    /* We don't allow manipulation of the other information */
581 	}
582     }
583     fclose( fp );
584     free( buf );
585 }
586 
587 /*
588  * Read a nethack.cnf like file and process the OPTIONS
589  * information from it.
590  */
591 void ReadCfgOptions( void )
592 {
593     register FILE *fp;
594     register char *buf, *t;
595 
596     /* Use a dynamic buffer to limit stack use */
597 
598     if( ( buf = xmalloc( 1024 ) ) == NULL )
599     {
600 	error( "Can't alloc space to read config file" );
601 	cleanup( 1 );
602     }
603 
604     /* If the file is not there, can't load it */
605 
606     if( ( fp = fopen( StrConf, "r" ) ) == NULL )
607     {
608 	errmsg( FLASH, "Can't load config file %s", StrConf );
609 	free( buf );
610 	return;
611     }
612 
613     /* Read the lines... */
614 
615     while( fgets( buf, 1024, fp ) != NULL )
616     {
617 	if( *buf == '#' )
618 	    continue;
619 
620 	if( ( t = strchr( buf, '\n' ) ) != NULL )
621 	    *t = 0;
622 
623 	/* Set options based on parsing them. */
624 	if( strnicmp( buf, "OPTIONS=", 8 ) == 0 )
625 	    ParseOptionStr( buf + 8 );
626     }
627     fclose( fp );
628     free( buf );
629 }
630 
631 /* Close the workbench screen and window */
632 
633 void CloseDownWB( )
634 {
635     ((struct Process *)FindTask( NULL ))->pr_WindowPtr = (APTR)oldwin;
636 
637     if( win && win->RPort->TmpRas )
638     {
639 	FreeRaster( tmprasp, width, height );
640     }
641 
642     if( win )
643 	SafeCloseWindow( win );
644 
645 #ifdef  INTUI_NEW_LOOK
646     if( IntuitionBase->LibNode.lib_Version >= 37 )
647     {
648 	while( !scrlocked && CloseScreen( scrn ) == FALSE )
649 	{
650 	    Ask("Close all vistor Windows to exit" );
651 	}
652     }
653     else
654 #endif
655     {
656 	CloseScreen( scrn );
657     }
658     wbopen = 0;
659 }
660 
661 /* Open the workbench screen and window. */
662 
663 char mytitle[ 90 ];
664 void SetupWB( )
665 {
666     int cpyrwid, i;
667     int txtdiff;
668 #ifdef  INTUI_NEW_LOOK
669     int pubopen = 0;
670 #endif
671     static int once = 0;
672 
673     scrlocked = 0;
674 #ifdef  INTUI_NEW_LOOK
675     NewScreenStructure.Extension = scrntags;
676     NewScreenStructure.Type |= NS_EXTENDED;
677 #endif
678 
679     NewScreenStructure.Width = GfxBase->NormalDisplayColumns;
680     NewScreenStructure.Height = GfxBase->NormalDisplayRows;
681 
682     {
683     sprintf(scrntitle,"WorkBench for V%d.%d.%d of NetHack",
684       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
685     NewScreenStructure.DefaultTitle = scrntitle;
686     }
687 
688 #ifdef  INTUI_NEW_LOOK
689     if( IntuitionBase->LibNode.lib_Version < 37 )
690     {
691 #endif
692 	if( ( scrn = OpenScreen( (void *)
693 		&NewScreenStructure ) ) == NULL )
694 	{
695 	    error( "Can't create screen" );
696 	    cleanup( 1 );
697 	}
698 
699 	/* Only set the pens on the screen we open */
700 	LoadRGB4( &scrn->ViewPort, Palette, PaletteColorCount );
701 #ifdef  INTUI_NEW_LOOK
702     }
703     else
704     {
705     	struct DimensionInfo dims;
706     	ULONG modeid;
707     	DisplayInfoHandle handle;
708     	struct DisplayInfo disp;
709 
710 	/* No tags beyond here yet */
711 	scrntags[1].ti_Tag = TAG_DONE;
712 
713 	if( *pubscreen != 0 )
714 	{
715 	    if( ( scrn = LockPubScreen( pubscreen ) ) == 0 )
716 	    {
717 		/* Now add our pub screen name */
718 		scrntags[1].ti_Tag = SA_PubName;
719 		scrntags[1].ti_Data = (ULONG) pubscreen;
720 		scrntags[2].ti_Tag = TAG_DONE;
721 
722 		/* Get the default pub screen's size */
723 		scrn = LockPubScreen( NULL );
724 		modeid = GetVPModeID( &scrn->ViewPort );
725 		if( modeid == INVALID_ID ||
726 		    ModeNotAvailable( modeid ) ||
727 		    ( handle = FindDisplayInfo( modeid ) ) == NULL ||
728 		    GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ),
729 			DTAG_DIMS, modeid ) <= 0 ||
730 		    GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ),
731 			DTAG_DISP, modeid ) <= 0 )
732 		{
733 		    /* If the display database seems to not work, use the screen
734 		     * dimensions
735 		     */
736 		    NewScreenStructure.Height = scrn->Height;
737 		    NewScreenStructure.Width = scrn->Width;
738 
739 		    /*
740 		     * Request LACE if it looks laced.  For 2.1/3.0, we will get
741 		     * promoted to the users choice of modes (if promotion is allowed)
742 		     * If the user is using a dragable screen, things will get hosed
743 		     * but that is life...
744 		     */
745 		    if( NewScreenStructure.Height > 300 )
746 			    NewScreenStructure.ViewModes |= LACE;
747 		}
748 		else
749 		{
750 		    /* Use the display database to get the correct information */
751 		    if( disp.PropertyFlags & DIPF_IS_LACE )
752 			NewScreenStructure.ViewModes |= LACE;
753 		    NewScreenStructure.Height = dims.StdOScan.MaxY;
754 		    NewScreenStructure.Width = dims.StdOScan.MaxX;
755 		    scrntags[2].ti_Tag = SA_DisplayID;
756 		    scrntags[2].ti_Data = modeid;
757 		    scrntags[3].ti_Tag = TAG_DONE;
758 		}
759 		UnlockPubScreen( NULL, scrn );
760 
761 		if( ( scrn = OpenScreen( (void *)
762 		    &NewScreenStructure ) ) == NULL )
763 		{
764 		    NewScreenStructure.Height = GfxBase->NormalDisplayRows;
765 		    NewScreenStructure.Width = GfxBase->NormalDisplayColumns;
766 		    if( ( scrn = OpenScreen( (void *)
767 			&NewScreenStructure ) ) == NULL )
768 		    {
769 			error( "Can't create screen" );
770 			cleanup( 1 );
771 		    }
772 		}
773 
774 		/* Only set the pens on the screen we open */
775 		LoadRGB4( &scrn->ViewPort, Palette, PaletteColorCount );
776 
777 		pubopen = 1;
778 		scrlocked = 0;
779 	    }
780 	    else
781 	    {
782 		pubopen = 0;
783 		scrlocked = 1;
784 	    }
785 	}
786 	else
787 	{
788 	    if( ( scrn = LockPubScreen( NULL ) ) == 0 )
789 	    {
790 		error( "Can't lock Workbench screen" );
791 		cleanup( 1 );
792 	    }
793 	    scrlocked = 1;
794 	}
795     }
796 #endif
797 
798     cpyrwid = 0;
799     for( i = 0; copyright_text[i]; ++i )
800 	{
801 		int len = strlen( copyright_text[i] );
802 		cpyrwid = max(cpyrwid, len );
803 	}
804 
805     /* 28 is magic for the width of the sizing gadget under 2.04 and
806      * later.
807      */
808     NewWindowStructure1.Width = (cpyrwid * scrn->RastPort.TxWidth) +
809 	    scrn->WBorLeft + scrn->WBorRight + 28;
810 
811     width = NewWindowStructure1.Width;
812 
813     if( NewWindowStructure1.LeftEdge + width > scrn->Width )
814     {
815 	if( width > scrn->Width )
816 	{
817 	    NewWindowStructure1.LeftEdge = 0;
818 	    NewWindowStructure1.Width = scrn->Width;
819 	}
820 	else
821 	{
822 	    NewWindowStructure1.LeftEdge = (scrn->Width - width)/2;
823 	}
824     }
825     height = NewWindowStructure1.Height;
826     NewWindowStructure1.Screen = scrn;
827 
828     txtdiff = scrn->RastPort.TxHeight - 8;
829 
830     if( scrlocked )
831 	sprintf( mytitle, "NetHack WB %d.%d.%d - Select a GAME or press HELP",
832 	  VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
833 
834     else
835 	strcpy( mytitle, "Select a GAME or press HELP" );
836 
837     NewWindowStructure1.Title = mytitle;
838 #ifdef  INTUI_NEW_LOOK
839     if( IntuitionBase->LibNode.lib_Version >= 37 )
840 	((struct PropInfo *)Scroll.SpecialInfo)->Flags |= PROPNEWLOOK;
841 #endif
842 
843     if( !once )
844     {
845 	((struct Border *) Message.GadgetRender)->XY[2] =
846 		NewWindowStructure1.Width +
847 		Message.Width - Message.LeftEdge;
848 	Message.TopEdge = scrn->RastPort.TxHeight + scrn->WBorTop + 1;
849 	Message.Height = scrn->RastPort.TxHeight + 3;
850 	    ((struct Border *) Message.GadgetRender)->XY[1] =
851 	    (((struct Border *) Message.GadgetRender)->XY[3] +=
852 		scrn->RastPort.TxHeight - 6 );
853     }
854 
855     if( ( win = MyOpenWindow( &NewWindowStructure1 ) ) == NULL )
856     {
857 #ifdef  INTUI_NEW_LOOK
858 	if( IntuitionBase->LibNode.lib_Version >= 37 )
859 	{
860 	    if( scrlocked )
861 		UnlockPubScreen( NULL, scrn );
862 	}
863 #endif
864 	error( "Can't create window" );
865 	cleanup( 1 );
866     }
867 #ifdef  INTUI_NEW_LOOK
868     if( IntuitionBase->LibNode.lib_Version >= 37 )
869     {
870 	/* If we did not create this screen, unlock it.
871 	 * otherwise, advertise it for other applications
872 	 * to use.
873 	 */
874 	if( scrlocked )
875 	    UnlockPubScreen( NULL, scrn );
876 	else if( pubopen )
877 	    PubScreenStatus( scrn, 0 );
878     }
879 #endif
880 
881     ((struct Border *) Message.GadgetRender)->XY[2] =
882 	    win->Width - win->BorderLeft -
883 		win->BorderRight - 1;
884 
885     RefreshGList( &Message, win, NULL, 1 );
886 #ifdef  INTUI_NEW_LOOK
887     if( IntuitionBase->LibNode.lib_Version >= 37 )
888 	RefreshWindowFrame( win );
889 #endif
890 
891     oldwin = (struct Window *)((struct Process *)FindTask( NULL ))->pr_WindowPtr;
892     ((struct Process *)FindTask( NULL ))->pr_WindowPtr = (APTR)win;
893 
894     if( ( tmprasp = (void *) AllocRaster( width, height ) ) == NULL )
895     {
896 	win->RPort->TmpRas = NULL;
897 	fprintf( stderr, "No Space for raster %d x %d\n", height, width );
898 	cleanup( 1 );
899     }
900 
901     InitTmpRas( &tmpras, tmprasp, RASSIZE( width, height ) );
902 
903     win->RPort->TmpRas = &tmpras;
904 
905     SetUpMenus( &MenuList1, scrn );
906     SetMenuStrip( win, &MenuList1 );
907     wbopen = 1;
908     once = 1;
909 }
910 
911 /* Map the gadgets onto the screen at the correct location */
912 
913 void MapGadgets( reason, update )
914     int reason;
915     int update;
916 {
917     GPTR gptr;
918 
919     if( active_count != 0 )
920     {
921     	errmsg( FLASH, "Can't reload games while a game is running" );
922     	return;
923     }
924 
925     /* Make sure that any down gadget is popped back up */
926 
927     if( lastgaddown )
928 	SetGadgetUP( &lastgaddown->dobj->do_Gadget );
929     lastgaddown = NULL;
930 
931     /* Grey Menu Items, no Game icon will be selected */
932 
933     ChgGameItems( &MenuList1, 0 );
934 
935     /* Remove them first */
936 
937     for( gptr = windowgads; gptr; gptr = gptr->nextwgad )
938     {
939 	RemoveGadget( win, &gptr->dobj->do_Gadget );
940     }
941     windowgads = NULL;
942 
943     /* Remove any non-existant games */
944 
945     ClearDelGames( );
946 
947     /* If disk changed, reload existing icons */
948 
949     if( reason == R_DISK )
950     {
951 	LoadIcons( );
952     }
953 
954     /* Always move back to home unless we were scrolling */
955 
956     if( reason != R_SCROLL )
957     {
958 	curcol = 0;
959     }
960 
961     /* Calculate locations and display gadgets */
962 
963     CalcLocs( update );
964 }
965 
966 void ClearWindow( win )
967     struct Window *win;
968 {
969     /* Clear the old gadgets from the window */
970 
971     SetAPen( win->RPort, C_GREY );
972     SetOPen( win->RPort, C_GREY );
973     SetDrPt( win->RPort, 0xffff );
974     SetDrMd( win->RPort, JAM2 );
975 
976     RectFill( win->RPort, ORIGINX, ORIGINY, CORNERX-1, CORNERY-1 );
977 }
978 
979 /* Calculate the place for and attach the gadgets to the window */
980 
981 void
982 CalcLocs( update )
983     int update;
984 {
985     register GPTR gptr;
986     register USHORT ox, oy, cx, cy;
987     int gadid = GADNEWGAME;
988     int addx = 0, sizex, sizey;
989 
990     cols = vcols = 0;
991     scol = -1;
992 
993     /* Upper left corner of window */
994 
995     ox = ORIGINX;
996     oy = ORIGINY;
997 
998     /* Lower right corner of window */
999 
1000     cx = CORNERX;
1001 
1002     /* Account for text labels at the bottom by pulling the bottom up. */
1003     cy = CORNERY - win->RPort->TxHeight;
1004 
1005     ClearWindow( win );
1006 
1007     /* Map the current list */
1008 
1009     for( gptr = gamehead; gptr; gptr = gptr->next )
1010     {
1011 	/* If not to the horizontal offset yet, don't display */
1012 
1013 	sizex = GADWIDTH( &gptr->dobj->do_Gadget );
1014 	sizey = gptr->dobj->do_Gadget.Height;
1015 	addx = max( sizex, addx );
1016 
1017 	/* If the current column comes before the visible column... */
1018 	if( cols < curcol )
1019 	{
1020 	    oy += sizey + GADINCY + 3;
1021 	    if( gptr->next )
1022 	    {
1023 		if( oy + gptr->next->dobj->do_Gadget.Height + 3 >= cy )
1024 		{
1025 		    cols++;
1026 		    ox += addx + GADINCX;
1027 		    if( GADWIDTH( &gptr->next->dobj->do_Gadget ) >
1028 			gptr->next->dobj->do_Gadget.Width )
1029 		    {
1030 			ox += ( GADWIDTH( &gptr->next->dobj->do_Gadget ) -
1031 			gptr->next->dobj->do_Gadget.Width ) / 2 + 1;
1032 		    }
1033 		    oy = ORIGINY;
1034 		    addx = 0;
1035 		}
1036 	    }
1037 	    continue;
1038 	}
1039 
1040 	if( scol == -1 )
1041 	{
1042 	    ox = ORIGINX;
1043 	    scol = cols;
1044 	}
1045 
1046 	/* If visible, draw it */
1047 
1048 	if( ox + sizex + GADINCX < cx )
1049 	{
1050 	    /* Link to mapped gadgets list */
1051 
1052 	    gptr->nextwgad = windowgads;
1053 	    windowgads = gptr;
1054 
1055 	    /* Set screen locations, if text is longer, scoot the
1056 	     * gadget over to make room for it.
1057 	     */
1058 
1059 	    if( GADWIDTH( &gptr->dobj->do_Gadget ) >
1060 		    gptr->dobj->do_Gadget.Width )
1061 	    {
1062 		gptr->dobj->do_Gadget.LeftEdge = ox +
1063 		    ( GADWIDTH( &gptr->dobj->do_Gadget ) -
1064 			gptr->dobj->do_Gadget.Width ) / 2 + 1;
1065 	    }
1066 	    else
1067 		gptr->dobj->do_Gadget.LeftEdge = ox;
1068 	    addx = max( addx, GADWIDTH( &gptr->dobj->do_Gadget) );
1069 	    gptr->dobj->do_Gadget.TopEdge = oy;
1070 	    gptr->dobj->do_Gadget.GadgetID = gadid++;
1071 
1072 	    AddGadget( win, &gptr->dobj->do_Gadget, 0 );
1073 	}
1074 
1075 	/* Stack vertically first, then horizontally */
1076 
1077 	if( gptr->next )
1078 	{
1079 	    oy += sizey + GADINCY + 3;
1080 	    if( oy + gptr->next->dobj->do_Gadget.Height + 3 >= cy )
1081 	    {
1082 		ox += addx + GADINCX;
1083 		cols++;
1084 		if( ox + GADWIDTH( &gptr->next->dobj->do_Gadget) < cx )
1085 		    vcols++;
1086 		addx = 0;
1087 		oy = ORIGINY;
1088 	    }
1089 	}
1090     }
1091 
1092     /* Display all of the gadgets */
1093 
1094     RefreshGList( win->FirstGadget, win, NULL, -1 );
1095 
1096     /* Set up the slider if forcing a new position, otherwise
1097      * the slider was probably moved and its position should be
1098      * left where the user put it instead of jerking it around
1099      */
1100     if( update )
1101 	UpdatePropGad( win, &Scroll, vcols+1, cols+1, scol );
1102 }
1103 
1104 /* Open the indicated window and place the IntuiText list passed in that
1105  * window.  Then wait for the OKAY gadget to be clicked on.
1106  */
1107 void text_requester( newwin, tlist )
1108     register struct NewWindow *newwin;
1109     struct IntuiText *tlist;
1110 {
1111     register struct Window *win;
1112     register struct IntuiMessage *imsg;
1113     register struct Gadget *gd;
1114     int done = 0;
1115     int i;
1116     long class;
1117     struct NewWindow **aonce;
1118     static struct NewWindow *once[ 6+1 ];
1119     int lines[ 10 ], lcnt = 0, avone = -1;
1120     register int txtdiff = scrn->RastPort.TxHeight - 8;
1121 
1122     newwin->Screen = scrn;
1123 
1124     /* See if we have already configured this window for the current font */
1125     for( i = 0; i < 6; ++i )
1126     {
1127 	if( newwin == once[i] )
1128 	    break;
1129 	if( once[i] == 0 && avone == -1 )
1130 	    avone = i;
1131     }
1132     aonce = &once[avone];
1133 
1134     /* If spacing not correct, fix it up now */
1135     if( *aonce == NULL )
1136     {
1137 	register struct IntuiText *ip = tlist;
1138 	for( ; ip; ip = ip->NextText )
1139 	{
1140 	    if( lcnt == 0 )
1141 		lines[ lcnt++ ] = ip->TopEdge;
1142 	    else
1143 	    {
1144 		register found = 0;
1145 		for( i = 0; i < lcnt; ++i )
1146 		{
1147 		    if( lines[ i ] > ip->TopEdge )
1148 			break;
1149 		    if( lines[ i ] == ip->TopEdge )
1150 		    {
1151 			found = 1;
1152 			break;
1153 		    }
1154 		}
1155 
1156 		if( !found )
1157 		{
1158 		    if( i < lcnt )
1159 		    {
1160 			int j;
1161 			for( j = lcnt; j > i; --j )
1162 			    lines[ j ] = lines[ j - 1 ];
1163 		    }
1164 		    lcnt++;
1165 		    lines[ i ] = ip->TopEdge;
1166 		}
1167 	    }
1168 	}
1169 
1170 	for( ip = tlist; ip; ip = ip->NextText )
1171 	{
1172 	    for( i = 0; i < lcnt; ++i )
1173 	    {
1174 		if( ip->TopEdge == lines[ i ] )
1175 		{
1176 		    ip->TopEdge += txtdiff*i;
1177 		    break;
1178 		}
1179 	    }
1180 	}
1181 
1182 	gd = FindGadget( NULL, newwin, GADHELPOKAY );
1183 	gd->TopEdge += (lcnt+1)*txtdiff;
1184 	gd->Height += txtdiff;
1185 	SetBorder( gd, -1 );
1186 	newwin->Height += txtdiff * (lcnt+2);
1187 	*aonce = newwin;
1188     }
1189 
1190     if( ( win = MyOpenWindow( newwin ) ) == NULL )
1191     {
1192 	errmsg( FLASH, "Can't create window" );
1193 	return;
1194     }
1195 
1196     PrintIText( win->RPort, tlist, 0, txtdiff );
1197 
1198     while( !done )
1199     {
1200 	WaitPort( win->UserPort );
1201 	while( ( imsg = (struct IntuiMessage * )
1202 	    GetMsg( win->UserPort ) ) != NULL )
1203 	{
1204 	    class = imsg->Class;
1205 	    ReplyMsg( (struct Message *) imsg );
1206 	    switch( class )
1207 	    {
1208 		case CLOSEWINDOW: done = 1; break;
1209 		case VANILLAKEY: done = 1; break;
1210 		/* Should be GADHELPOKAY */
1211 		case GADGETUP: done = 1; break;
1212 	    }
1213 	}
1214     }
1215     SafeCloseWindow( win );
1216 }
1217 
1218 /* Scroll through a file which is passed by name */
1219 
1220 char title[90];
1221 void help_requester( file )
1222     char *file;
1223 {
1224     register struct Window *win;
1225     register struct IntuiMessage *imsg;
1226     register struct Gadget *gd;
1227     FILE *fp;
1228     int done = 0, line = 0, lines, topline, tlines, i;
1229     static int once = 0, lastdown;
1230     char buf[ 100 ];
1231     long loff[ 100 ];
1232     long class, code;
1233     int txtdiff = scrn->RastPort.TxHeight - 8;
1234 
1235     if( ( fp = fopen( file, "r" ) ) == NULL )
1236     {
1237 #if defined(__SASC_60) || defined(_DCC)
1238 	errmsg( FLASH, "Can't open %s: %s", file, strerror(errno) );
1239 #else
1240 	errmsg( FLASH, "Can't open %s: %s", file, sys_errlist[errno] );
1241 #endif
1242 	return;
1243     }
1244     for( tlines = 0; tlines < 100 ; ++tlines )
1245     {
1246 	loff[ tlines ] = ftell( fp );
1247 	if( fgets( buf, sizeof( buf ), fp ) == NULL )
1248 	    break;
1249     }
1250 
1251     if( !once )
1252     {
1253 	for( gd = Help3_NewWindowStructure10.FirstGadget;
1254 		    gd; gd = gd->NextGadget )
1255 	{
1256 	    if( gd->GadgetID != 0 )
1257 	    {
1258 		if( gd->GadgetID == GADHELPFRWD ||
1259 		    gd->GadgetID == GADHELPBKWD )
1260 		{
1261 		    gd->Height += txtdiff;
1262 		}
1263 		SetBorder( gd, -1 );
1264 	    }
1265 	}
1266 	once = 1;
1267 	Help3_NewWindowStructure10.Height += txtdiff;
1268     }
1269 
1270     {
1271     sprintf(title,"Help for NetHack WorkBench V%d.%d.%d",
1272       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
1273     Help3_NewWindowStructure10.Title = title;
1274     }
1275 
1276     Help3_NewWindowStructure10.Screen = scrn;
1277     if( ( win = MyOpenWindow( &Help3_NewWindowStructure10 ) ) == NULL )
1278     {
1279 	errmsg( FLASH, "Can't create requester window" );
1280 	fclose( fp );
1281 	return;
1282     }
1283     lines = ( (win->Height - win->BorderTop - 25 ) / win->RPort->TxHeight );
1284     topline = win->BorderTop + win->RPort->TxBaseline + 2;
1285     Move( win->RPort, win->BorderLeft, topline );
1286 
1287     SetAPen( win->RPort, C_BLACK );
1288     SetBPen( win->RPort, C_GREY );
1289     SetDrMd( win->RPort, JAM2 );
1290 
1291     for( i = 0; i < min( lines, tlines ); ++i )
1292     {
1293 	getline( fp, loff, i, buf, sizeof( buf ) );
1294 	Move( win->RPort, win->BorderLeft + 2,
1295 	    topline + (i * win->RPort->TxHeight) );
1296 	Text( win->RPort, buf, strlen( buf )-1 );
1297     }
1298 
1299     while( !done )
1300     {
1301 	WaitPort( win->UserPort );
1302 	while( ( imsg = (void *) GetMsg( win->UserPort ) ) != NULL )
1303 	{
1304 	    class = imsg->Class;
1305 	    code = imsg->Code;
1306 	    gd = (struct Gadget *)imsg->IAddress;
1307 
1308 	    ReplyMsg( (struct Message *) imsg );
1309 
1310 	    switch( class )
1311 	    {
1312 		case VANILLAKEY:
1313 		    if( code == 'u' || code == ('U'-64))
1314 		    {
1315 			goto bkwd;
1316 		    }
1317 		    else if( code == 'd' || code == ('D'-64))
1318 		    {
1319 			goto frwd;
1320 		    }
1321 		    else if( code == '\33' || code == 'q' )
1322 		    {
1323 			done = 1;
1324 		    }
1325 		    break;
1326 
1327 		case CLOSEWINDOW:
1328 		    done = 1;
1329 		    break;
1330 
1331 		case MOUSEBUTTONS:
1332 		case INACTIVEWINDOW:
1333 		case ACTIVEWINDOW:
1334 		case GADGETUP:
1335 		    lastdown = 0;
1336 		    break;
1337 
1338 		case GADGETDOWN:
1339 		    lastdown = gd->GadgetID;
1340 		    break;
1341 
1342 		case INTUITICKS:
1343 		    if( lastdown == GADHELPFRWD )
1344 		    {
1345 			frwd:
1346 			if( line + lines < tlines )
1347 			{
1348 			    line++;
1349 			    WaitTOF();
1350 			    ScrollRaster( win->RPort, 0,
1351 				win->RPort->TxHeight,
1352 				win->BorderLeft,
1353 				win->BorderTop + 2,
1354 				win->Width - win->BorderRight - 1,
1355 				win->BorderTop + 1 +
1356 				(lines*win->RPort->TxHeight) );
1357 			    getline( fp, loff, line + lines - 1,
1358 				buf, sizeof( buf ) );
1359 			    Move( win->RPort, win->BorderLeft + 2,
1360 				topline + ( ( lines - 1 ) *
1361 				win->RPort->TxHeight ) );
1362 			    WaitTOF();
1363 			    Text( win->RPort, buf, strlen( buf )-1 );
1364 			}
1365 			else
1366 			{
1367 			    /* EOF */
1368 			    DisplayBeep( scrn );
1369 			    lastdown = 0;
1370 			}
1371 		    }
1372 		    else if( lastdown == GADHELPBKWD )
1373 		    {
1374 			bkwd:
1375 			if( line > 0 )
1376 			{
1377 			    line--;
1378 			    WaitTOF();
1379 			    ScrollRaster( win->RPort, 0,
1380 				-win->RPort->TxHeight,
1381 				win->BorderLeft,
1382 				win->BorderTop + 2,
1383 				win->Width - win->BorderRight - 1,
1384 				win->BorderTop + 1 +
1385 				(lines*win->RPort->TxHeight) );
1386 			    getline( fp, loff, line, buf, sizeof( buf ) );
1387 			    Move( win->RPort, win->BorderLeft + 2, topline );
1388 			    WaitTOF();
1389 			    Text( win->RPort, buf, strlen( buf )-1 );
1390 			}
1391 			else
1392 			{
1393 			    DisplayBeep( scrn );
1394 			    lastdown = 0;
1395 			}
1396 		    }
1397 		    break;
1398 
1399 	    }
1400 	}
1401     }
1402     SafeCloseWindow( win );
1403     fclose( fp );
1404 }
1405 
1406 /* Act on the menu item number passed */
1407 
1408 void
1409 do_menu( mptr, mcode)
1410     struct Menu *mptr;
1411     register int mcode;
1412 {
1413     SetPointer( win, waitPointer, 16, 16, -6, 0 );
1414     while( mcode != MENUNULL )
1415     {
1416 	switch(MENUNUM(mcode))
1417 	{
1418 	    case MENU_PROJECT:
1419 		switch(ITEMNUM(mcode))
1420 		{
1421 		    case ITEM_HELP:
1422 			help_requester( "NetHack:HackWB.hlp" );
1423 			break;
1424 
1425 		    case ITEM_ABOUT:
1426 			text_requester( &About_NewWindowStructure9,
1427 				&About_IntuiTextList9 );
1428 			break;
1429 
1430 		    case ITEM_SCORES:
1431 			menu_scores( );
1432 			break;
1433 
1434 		    case ITEM_RECOVER:
1435 			menu_recover( );
1436 			break;
1437 
1438 		    case ITEM_CONFIG:
1439 			menu_config( );
1440 			break;
1441 
1442 		    case ITEM_QUIT:
1443 			quit = Ask( "Ready to Quit?" );
1444 			break;
1445 
1446 		}
1447 		break;
1448 
1449 	    case MENU_GAME:
1450 		switch( ITEMNUM( mcode ) )
1451 		{
1452 
1453 		    case ITEM_INFO:
1454 			menu_info( );
1455 			break;
1456 
1457 		    case ITEM_COPYOPT:
1458 			menu_copyopt( );
1459 			break;
1460 
1461 		    case ITEM_DISCARD:
1462 			menu_discard( );
1463 			break;
1464 
1465 		    case ITEM_RENAME:
1466 			menu_rename( );
1467 			break;
1468 		}
1469 	}
1470         mcode = ((struct MenuItem *)ItemAddress( mptr, (long)mcode ))->NextSelect;
1471     }
1472     ClearPointer( win );
1473 }
1474 
1475 void
1476 menu_discard()
1477 {
1478     register GPTR gptr;
1479 
1480     if( ( gptr = NeedGame() ) == NULL )
1481 	return;
1482 
1483     if( Ask("Discard Selected Game?") )
1484     {
1485 	lastgaddown = NULL;
1486 	if( DeleteGame( gptr ) == 0 )
1487 	{
1488 	    errmsg( FLASH, "Discard may have failed for %s",
1489 		    GameName( gptr, NULL ) );
1490 	}
1491 
1492 	MapGadgets( R_DISK, 1 );
1493     }
1494 }
1495 
1496 char tw[90];
1497 
1498 void
1499 run_game( gptr )
1500     register GPTR gptr;
1501 {
1502     extern UWORD __chip waitPointer[];
1503     struct Task *ctask;
1504     register struct MsgPort *proc = NULL;
1505     char buf[ 100 ];
1506     char namebuf[ 100 ];
1507     int once, tidx;
1508 
1509     if( gptr->active )
1510     {
1511 	errmsg( FLASH, "%s is already in progress", gptr->name );
1512 	return;
1513     }
1514 
1515     if( running_split && active_count > 0 )
1516     {
1517 	errmsg( FLASH, "A game is already in progress" );
1518 	return;
1519     }
1520 
1521     tidx = 0;
1522 
1523     /* If newgame gadget, then check game name */
1524 
1525     if( gptr->dobj->do_Gadget.GadgetID == GADNEWGAME )
1526     {
1527 	once = 0;
1528 	sprintf( buf, "%s/%s.sav", options[ SAVE_IDX ], gptr->name );
1529 	while( access( buf, 0 ) == 0 )
1530 	{
1531 	    if( StrRequest( "Game Already Exists, Enter a New Name",
1532 		namebuf, once ? namebuf : gptr->gname ) == 0 )
1533 	    {
1534 		return;
1535 	    }
1536 	    once = 1;
1537 	    sprintf( buf, "%s/%s.sav", options[ SAVE_IDX ], namebuf );
1538 	}
1539     }
1540     gptr->gname = xmalloc( 20 + strlen( gptr->name ) );
1541 
1542     /*
1543      * options[] are no longer put into the tooltypes because they are in the options
1544      * string now.
1545      */
1546 
1547     gptr->wbs = AllocMem( sizeof( struct WBStartup ) +
1548 	    ( sizeof( struct WBArg ) * 2 ), MEMF_PUBLIC | MEMF_CLEAR );
1549 
1550     /* Check if we got everything */
1551 
1552     if( !gptr->gname || !gptr->wbs )
1553     {
1554 	fprintf( stderr, "Can't allocate memory\n" );
1555 	goto freemem;
1556     }
1557 
1558     /* Get the arguments structure space */
1559 
1560     gptr->wba = ( struct WBArg * ) ((long)gptr->wbs +
1561 		sizeof( struct WBStartup ) );
1562 
1563     /* Close down window and screen if requested */
1564 
1565     if( shutdown )
1566 	CloseDownWB( );
1567 
1568     SetPointer( win, waitPointer, 16, 16, -6, 0 );
1569 
1570     /* Load the game into memory */
1571 
1572 #ifdef SPLIT
1573     /* Which version do we run? */
1574     {
1575 	char gi[80];
1576 
1577 	sprintf( gi, "%s.dir", GAMEIMAGE );
1578 	if( access( gi, 0 ) == 0 ){
1579 	    gptr->seglist = (BPTR)s_LoadSeg( gi );
1580 	    if( gptr->seglist ) running_split=1;
1581 	}else{
1582 	    gptr->seglist = (BPTR)LoadSeg( GAMEIMAGE );
1583 	}
1584     }
1585 #else
1586     gptr->seglist = (BPTR)LoadSeg( GAMEIMAGE );
1587 #endif
1588     ClearPointer( win );
1589 
1590     if( gptr->seglist == NULL)
1591     {
1592 	if( !wbopen )
1593 	    SetupWB( );
1594 	errmsg( FLASH, "Can't load %s", GAMEIMAGE );
1595 	goto freemem;
1596     }
1597     /* Build WBStartup from current game info */
1598 
1599     /* Set the game name for the status command */
1600 
1601     sprintf( gptr->gname, "NetHack %d.%d.%d %s",
1602       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, gptr->name );
1603 
1604     /* Create a process for the game to execute in */
1605 
1606     ctask = FindTask( NULL );
1607     proc = CreateProc( gptr->gname, ctask->tc_Node.ln_Pri,
1608 	gptr->seglist, GAMESTACK );
1609 
1610     /* Check if the create failed */
1611 
1612     if( proc == NULL )
1613     {
1614     fprintf(stderr, "Error creating process %d\n", IoErr() );
1615 #ifdef SPLIT
1616 	if(!running_split)
1617 #endif
1618 	    UnLoadSeg( gptr->seglist );
1619 freemem:
1620     if( gptr->gname ) free( gptr->gname );
1621     gptr->gname = NULL;
1622 
1623     if( gptr->wbs ) FreeMem( gptr->wbs,
1624 	sizeof( struct WBStartup ) + sizeof( struct WBArg ) * 2 );
1625     gptr->wbs = NULL;
1626     if( !wbopen )
1627 	SetupWB( );
1628     return;
1629     }
1630 
1631     /* Get the Process structure pointer */
1632 
1633     gptr->prc = (struct Process *) (((long)proc) - sizeof( struct Task ));
1634 
1635     /* Set the current directory */
1636 
1637     gptr->prc->pr_CurrentDir=((struct Process *)FindTask(NULL))->pr_CurrentDir;
1638 
1639     /* Fill in the startup message */
1640 
1641     gptr->wbs->sm_Process = proc;
1642     gptr->wbs->sm_Segment = gptr->seglist;
1643     gptr->wbs->sm_NumArgs = 2;
1644     sprintf(tw,"con:0/0/350/50/Amiga NetHack %d.%d.%d",
1645       VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL );
1646     gptr->wbs->sm_ToolWindow = tw;
1647     gptr->wbs->sm_ArgList = gptr->wba;
1648 
1649     /* Fill in the args */
1650 
1651     gptr->wba[0].wa_Name = Strdup( GAMEIMAGE );
1652     gptr->wba[0].wa_Lock = Lock( dirname( GAMEIMAGE ), ACCESS_READ );
1653 
1654     gptr->wba[1].wa_Name = Strdup( gptr->name );
1655     gptr->wba[1].wa_Lock = Lock( "t:", ACCESS_READ );
1656     if( gptr->wba[1].wa_Lock == NULL )
1657 	gptr->wba[1].wa_Lock = Lock( gptr->dname, ACCESS_READ );
1658     else
1659     {
1660 	/* Write the updated tools types entries */
1661 	WriteDObj( gptr, gptr->wba[1].wa_Lock );
1662     }
1663 
1664     /* Set the message fields correctly */
1665 
1666     gptr->wbs->sm_Message.mn_Node.ln_Type = NT_MESSAGE;
1667     gptr->wbs->sm_Message.mn_Node.ln_Pri = 0;
1668     gptr->wbs->sm_Message.mn_ReplyPort = dosport;
1669     gptr->wbs->sm_Message.mn_Length =
1670 	sizeof( struct WBStartup ) + ( sizeof( struct WBArg ) * 2 );
1671 
1672     /* mark game as in use */
1673 
1674     active_count++;
1675     gptr->active = 1;
1676 
1677     /* Send the WB Startup message to let the game go... */
1678 
1679     PutMsg( proc, &gptr->wbs->sm_Message );
1680 }
1681 
1682 void CloseLibraries( )
1683 {
1684     if( IntuitionBase )     CloseLibrary( (void *) IntuitionBase );
1685     IntuitionBase = 0;
1686     if( DiskfontBase )      CloseLibrary( (void *) DiskfontBase );
1687     DiskfontBase = 0;
1688     if( IconBase )          CloseLibrary(  IconBase );
1689     IconBase = 0;
1690     if( GfxBase )           CloseLibrary( (void *) GfxBase );
1691     GfxBase = 0;
1692 }
1693 
1694 void cleanup( code )
1695     int code;
1696 {
1697     if( active_count )
1698     {
1699 	errmsg( FLASH, "There %s still %d game%s active...",
1700 		active_count > 1 ? "are" : "is",
1701 		active_count,
1702 		active_count > 1 ? "s" : "" );
1703 	return;
1704     }
1705 
1706     if( dosport ) DeletePort( dosport );
1707     dosport = NULL;
1708 
1709     CloseDownWB( );
1710     CleanUpLists( );
1711     CloseLibraries( );
1712 
1713 #ifdef SPLIT
1714     if(running_split)s_UnLoadSeg();
1715 #endif
1716     exit( code );
1717 }
1718 
1719 GPTR AllocGITEM( )
1720 {
1721     register GPTR gptr;
1722 
1723     if( gameavail )
1724     {
1725 	gptr = gameavail;
1726 	gameavail = gameavail->next;
1727     }
1728     else
1729     {
1730 	gptr = xmalloc( sizeof( GAMEITEM ) );
1731     }
1732 
1733     if( gptr )
1734 	memset( gptr, 0, sizeof( GAMEITEM ) );
1735 
1736     return( gptr );
1737 }
1738 
1739 void FreeGITEM( gptr )
1740     register GPTR gptr;
1741 {
1742     /* Free all of the pieces first */
1743 
1744     if( gptr->talloc )
1745 	FreeTools( gptr );
1746     gptr->talloc = 0;
1747 
1748     if( gptr->dobj )
1749 	FreeDObj( gptr->dobj );
1750     gptr->dobj = NULL;
1751 
1752     if( gptr->name )
1753 	free( gptr->name );
1754     gptr->name = NULL;
1755 
1756     if( gptr->dname )
1757 	free( gptr->dname );
1758     gptr->dname = NULL;
1759 
1760     if( gptr->fname )
1761 	free( gptr->fname );
1762     gptr->fname = NULL;
1763 
1764     /* Connect it to free list */
1765 
1766     gptr->next = gameavail;
1767     gameavail = gptr;
1768 }
1769 
1770 struct DiskObject *AllocDObj( str )
1771     register char *str;
1772 {
1773     register struct DiskObject *doptr;
1774     register char *t, *t1;
1775 
1776     if( ( t = strrchr( str, '.' ) ) && stricmp( t, ".info" ) == 0 )
1777 	*t = 0;
1778     else
1779 	t = NULL;
1780 
1781     if( doptr = GetDiskObject( str ) )
1782     {
1783 	struct IntuiText *ip;
1784 
1785 	diskobj_filter(doptr);  /* delete INTERNALCLI */
1786 
1787 	if( ip = xmalloc( sizeof( struct IntuiText ) ) )
1788 	{
1789 	    memset( ip, 0, sizeof( struct IntuiText ) );
1790 	    ip->FrontPen = C_BLACK;
1791 	    ip->DrawMode = JAM1;
1792 	    ip->LeftEdge = (doptr->do_Gadget.Width -
1793 		( strlen( str ) * win->RPort->TxWidth ))/2;
1794 	    ip->TopEdge = doptr->do_Gadget.Height;
1795 	    ip->IText = strdup( str );
1796 	    doptr->do_Gadget.GadgetText = ip;
1797 
1798 	    /* Trim any .sav off of the end. */
1799 
1800 	    if( ( t1 = strrchr( ip->IText, '.' ) ) &&
1801 		    stricmp( t1, ".sav" ) == 0 )
1802 	    {
1803 		*t1 = 0;
1804 		ip->LeftEdge += (2 * win->RPort->TxWidth);
1805 	    }
1806 	}
1807     }
1808     if( t ) *t = '.';
1809 
1810     return( doptr );
1811 }
1812 
1813 void LoadIcons( )
1814 {
1815     register GPTR gptr, newgame;
1816     register BPTR savedir;
1817     register char *t;
1818     register struct FileInfoBlock *finfo;
1819     char buf[ 200 ];
1820 
1821     /* Check if we can access the new save directory */
1822 
1823     if( t = strchr( options[ SAVE_IDX ], ';' ) )
1824     {
1825 	strncpy( buf, options[ SAVE_IDX ], sizeof( buf ) - 1 );
1826 	buf[ sizeof( buf ) - 1 ] = 0;
1827 	if( ( t = strchr( buf, ';' ) ) && strcmp( t, ";n" ) == 0 )
1828 	    *t = 0;
1829 	if( ( savedir = Lock( buf, ACCESS_READ ) ) == NULL )
1830 	{
1831 	    errmsg( FLASH,
1832 		    "Can't access save directory: %s", buf );
1833 	    return;
1834 	}
1835     }
1836     else if( ( savedir = Lock( options[ SAVE_IDX ], ACCESS_READ ) ) == NULL )
1837     {
1838 	errmsg( FLASH,
1839 		"Can't access save directory: %s", options[ SAVE_IDX ] );
1840 	return;
1841     }
1842 
1843     if( ( finfo = (struct FileInfoBlock *)
1844 		    xmalloc( sizeof( struct FileInfoBlock ) ) ) == NULL )
1845     {
1846 	UnLock( savedir );
1847 	errmsg( FLASH, "Can't alloc memory" );
1848 	return;
1849     }
1850 
1851     if( ( newgame = gamehead ) && newgame->dobj->do_Gadget.GadgetID == GADNEWGAME )
1852 	gamehead = gamehead->next;
1853     else
1854 	newgame = NULL;
1855 
1856     if( !Examine( savedir, finfo ) )
1857     {
1858 	UnLock( savedir );
1859 	free( finfo );
1860 	errmsg( FLASH, "Can't Examine save directory" );
1861 	return;
1862     }
1863 
1864     /* Collect all of the entries */
1865 
1866     while( ExNext( savedir, finfo ) )
1867     {
1868 	/* If already got this game, continue */
1869 
1870 	if( gptr = FindGame( finfo->fib_FileName ) )
1871 	    continue;
1872 
1873 	/* Get just the ones we are interested in */
1874 
1875 	if( ( t = strrchr( finfo->fib_FileName, '.' ) ) == NULL ||
1876 		    stricmp( t, ".info" ) != 0 )
1877 	    continue;
1878 
1879 	if( t == finfo->fib_FileName )
1880 	    continue;
1881 
1882 	/* Get a gadget item */
1883 
1884 	if( gptr = GetWBIcon( savedir, options[ SAVE_IDX ], finfo ) )
1885 	{
1886 	    gptr->next = gamehead;
1887 	    gamehead = gptr;
1888 	}
1889     }
1890 
1891     /* Get the NewGame gadget */
1892 
1893     UnLock( savedir );
1894     if( newgame == NULL )
1895     {
1896 	/* Pick up the new game if not there yet. */
1897 
1898 	sprintf( buf, "%sNewGame.info", options[ HACKDIR_IDX ] );
1899 	if( savedir = Lock( buf, ACCESS_READ ) )
1900 	{
1901 	    if( Examine( savedir, finfo ) )
1902 	    {
1903 		UnLock( savedir );
1904 		savedir = Lock( options[ HACKDIR_IDX ], ACCESS_READ );
1905 		if( gptr = GetWBIcon( savedir,
1906 			options[ HACKDIR_IDX ], finfo ) )
1907 		{
1908 		    gptr->next = gamehead;
1909 		    gamehead = gptr;
1910 		}
1911 	    }
1912 	    UnLock( savedir );
1913 	    free( finfo );
1914 	}
1915 	else
1916 	{
1917 	    errmsg( FLASH, "No access to %s", buf );
1918 	}
1919     }
1920     else
1921     {
1922 	newgame->next = gamehead;
1923 	gamehead = newgame;
1924     }
1925 }
1926 
1927 void menu_recover()
1928 {
1929     int execit = 1;
1930     long class, code;
1931     struct Gadget *gd, *lastact = 0;
1932     int done = 0;
1933     struct IntuiMessage *imsg;
1934     struct Window *w;
1935     static int once = 0;
1936     int txtdiff = scrn->RastPort.TxHeight - 8;
1937     struct IntuiText *ip;
1938 
1939     if( !once )
1940     {
1941 	for( gd = Rst_NewWindowStructure11.FirstGadget;
1942 		    gd; gd = gd->NextGadget )
1943 	{
1944 	    switch( gd->GadgetID )
1945 	    {
1946 		case GADRESTDIR:
1947 		    gd->TopEdge += txtdiff;
1948 		    gd->Height += txtdiff;
1949 		    SetBorder( gd, -1 );
1950 		    strcpy(RstDir,options[LEVELS_IDX]);
1951 		    break;
1952 		case GADRESTOLD:
1953 		    gd->TopEdge += txtdiff*2;
1954 		    gd->Height += txtdiff;
1955 		    SetBorder( gd, -1 );
1956 		    strcpy(RstOld,"levels");
1957 		    break;
1958 		case GADRESTNEW:
1959 		    gd->TopEdge += txtdiff*3;
1960 		    gd->Height += txtdiff;
1961 		    SetBorder( gd, -1 );
1962 		    break;
1963 		case GADRESTOKAY:
1964 		    gd->TopEdge += txtdiff*4;
1965 		    gd->Height += txtdiff;
1966 		    SetBorder( gd, -1 );
1967 		    break;
1968 		case GADRESTCAN:
1969 		    gd->TopEdge += txtdiff*4;
1970 		    gd->Height += txtdiff;
1971 		    SetBorder( gd, -1 );
1972 		    break;
1973 	    }
1974 	}
1975 	Rst_NewWindowStructure11.Height += txtdiff*5;
1976 	for( ip = &Rst_IntuiTextList11; ip; ip = ip->NextText )
1977 	{
1978 	    if( *ip->IText == 'O' )
1979 		ip->TopEdge += txtdiff;
1980 	    else if( *ip->IText == 'N' )
1981 		ip->TopEdge += txtdiff*2;
1982 	}
1983 	once = 1;
1984     }
1985 
1986     Rst_NewWindowStructure11.Screen = scrn;
1987     if( ( w = MyOpenWindow( &Rst_NewWindowStructure11 ) ) == NULL )
1988     {
1989 	errmsg( FLASH, "Can't create requester window" );
1990 	return;
1991     }
1992     PrintIText( w->RPort, &Rst_IntuiTextList11, 0, txtdiff );
1993     lastact = FindGadget( w, NULL, GADRESTDIR );
1994 
1995     while( !done )
1996     {
1997 	WaitPort( w->UserPort );
1998 	while( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) )
1999 	{
2000 	    class = imsg->Class;
2001 	    code = imsg->Code;
2002 	    gd = (struct Gadget *)imsg->IAddress;
2003 	    ReplyMsg( (struct Message *) imsg );
2004 	    switch( class )
2005 	    {
2006 		case CLOSEWINDOW:
2007 		    done = 1;
2008 		    execit = 0;
2009 		    break;
2010 
2011 		case ACTIVEWINDOW:
2012 		    ActivateGadget( lastact, w, NULL );
2013 		    break;
2014 
2015 		case GADGETUP:
2016 		    if( gd->GadgetID == GADRESTOKAY )
2017 			done = 1;
2018 		    else if( gd->GadgetID == GADRESTCAN )
2019 		    {
2020 			execit = 0;
2021 			done = 1;
2022 		    }
2023 		    else if( gd->GadgetID == GADRESTDIR )
2024 		    {
2025 			if( gd = FindGadget( w, NULL, GADRESTOLD ) )
2026 			    ActivateGadget( lastact = gd, w, NULL );
2027 		    }
2028 		    else if( gd->GadgetID == GADRESTOLD )
2029 		    {
2030 			if( gd = FindGadget( w, NULL, GADRESTNEW ) )
2031 			    ActivateGadget( lastact = gd, w, NULL );
2032 		    }
2033 		    break;
2034 
2035 		case VANILLAKEY:
2036 		    if( code == '\33' )
2037 		    {
2038 			done = 1;
2039 			execit = 0;
2040 		    }
2041 		    break;
2042 	    }
2043 	}
2044     }
2045 
2046     SafeCloseWindow( w );
2047 
2048     if( execit )
2049     {
2050 	char buf[255];
2051 	sprintf( buf, "stack 65000\nNetHack:Recover -d %s %s", RstDir, RstOld );
2052 	Execute( buf, NULL, NULL );
2053 	MapGadgets( R_DISK, 1);
2054     }
2055 }
2056 
2057 void menu_config()
2058 {
2059     register struct Window *cwin;
2060     int done = 0, quit;
2061     long class, code, qual;
2062     register struct IntuiMessage *imsg;
2063     struct IntuiText *ip;
2064     register struct Gadget *gd;
2065     static int once = 0;
2066     int txtdiff = scrn->RastPort.TxHeight - 8;
2067     char *env;
2068 
2069     strcpy( StrPath, options[ PATH_IDX ] );
2070     strcpy( StrHackdir, options[ HACKDIR_IDX ] );
2071     strcpy( StrPens, options[ PENS_IDX ] );
2072     strcpy( StrLevels, options[ LEVELS_IDX ] );
2073     strcpy( StrSave, options[ SAVE_IDX ] );
2074 
2075     if( !once )
2076     {
2077 	for( gd = Conf_NewWindowStructure4.FirstGadget;
2078 		    gd; gd = gd->NextGadget )
2079 	{
2080 	    switch( gd->GadgetID )
2081 	    {
2082 		case GADSTRPATH:
2083 		    /* Look for "Path:" string */
2084 		    for( ip = &Conf_IntuiTextList4;
2085 			    ip && *ip->IText != 'P'; )
2086 			ip = ip->NextText;
2087 		    gd->TopEdge += txtdiff;
2088 		    gd->Height += txtdiff;
2089 		    SetBorder( gd, -1 );
2090 		    break;
2091 		case GADSTRHACKDIR:
2092 		    /* Look for "Hackdir:" string */
2093 		    for( ip = &Conf_IntuiTextList4;
2094 			    ip && *ip->IText != 'H'; )
2095 			ip = ip->NextText;
2096 		    if( ip )
2097 			ip->TopEdge += txtdiff;
2098 		    gd->TopEdge += txtdiff*2;
2099 		    gd->Height += txtdiff;
2100 		    SetBorder( gd, -1 );
2101 		    break;
2102 		case GADSTRPENS:
2103 		    /* Look for "Pens:" string */
2104 		    for( ip = &Conf_IntuiTextList4; ip &&
2105 			!(*ip->IText == 'P' && ip->IText[1] == 'e'); )
2106 		    {
2107 			ip = ip->NextText;
2108 		    }
2109 		    if( ip )
2110 			ip->TopEdge += txtdiff*2;
2111 		    gd->TopEdge += txtdiff*3;
2112 		    gd->Height += txtdiff;
2113 		    SetBorder( gd, -1 );
2114 		    break;
2115 		case GADSTRLEVELS:
2116 		    /* Look for "Levels:" string */
2117 		    for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'L'; )
2118 			ip = ip->NextText;
2119 		    if( ip )
2120 			ip->TopEdge += txtdiff*3;
2121 		    gd->TopEdge += txtdiff*4;
2122 		    gd->Height += txtdiff;
2123 		    SetBorder( gd, -1 );
2124 		    break;
2125 		case GADSTRSAVE:
2126 		    /* Look for "Save Dir:" string */
2127 		    for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'S'; )
2128 			ip = ip->NextText;
2129 		    if( ip )
2130 			ip->TopEdge += txtdiff*4;
2131 		    gd->TopEdge += txtdiff*5;
2132 		    gd->Height += txtdiff;
2133 		    SetBorder( gd, -1 );
2134 		    break;
2135 		case GADCONFLOAD:
2136 		case GADCONFSAVE:
2137 		    gd->TopEdge += txtdiff*6;
2138 		    gd->Height += txtdiff;
2139 		    SetBorder( gd, -1 );
2140 		    break;
2141 		case GADCONFNAME:
2142 		    for( ip = &Conf_IntuiTextList4; ip && *ip->IText != 'C'; )
2143 			ip = ip->NextText;
2144 		    if( ip )
2145 			ip->TopEdge += txtdiff*6;
2146 		    gd->TopEdge += txtdiff*7;
2147 		    gd->Height += txtdiff;
2148 		    SetBorder( gd, -1 );
2149 		    break;
2150 
2151 		default:
2152 		    break;
2153 	    }
2154 	}
2155 	Conf_NewWindowStructure4.Height += txtdiff*8;
2156 	if( Conf_NewWindowStructure4.TopEdge +
2157 	    Conf_NewWindowStructure4.Height > scrn->Height )
2158 	{
2159 	    Conf_NewWindowStructure4.TopEdge -=
2160 		( Conf_NewWindowStructure4.TopEdge +
2161 		Conf_NewWindowStructure4.Height ) - scrn->Height + 1;
2162 	    if( Conf_NewWindowStructure4.TopEdge < 0 )
2163 	    {
2164 		Conf_NewWindowStructure4.TopEdge = 0;
2165 		Conf_NewWindowStructure4.Height = scrn->Height - 1;
2166 	    }
2167 	}
2168 	once = 1;
2169     }
2170 
2171     Conf_NewWindowStructure4.Screen = scrn;
2172     if( ( cwin = MyOpenWindow( &Conf_NewWindowStructure4 ) ) == NULL )
2173     {
2174 	errmsg( FLASH, "Can't create requester window" );
2175 	return;
2176     }
2177 
2178     PrintIText( cwin->RPort, &Conf_IntuiTextList4, 0, txtdiff );
2179     while( !done )
2180     {
2181 	WaitPort( cwin->UserPort );
2182 	while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
2183 	{
2184 	    class = imsg->Class;
2185 	    code = imsg->Code;
2186 	    qual = imsg->Qualifier;
2187 	    gd = (struct Gadget *)imsg->IAddress;
2188 
2189 	    ReplyMsg( (struct Message *)imsg );
2190 
2191 	    switch( class )
2192 	    {
2193 		case VANILLAKEY:
2194 		    if( code == '\33' || (code == 'b' && (qual&AMIGALEFT)))
2195 		    {
2196 			done = 0;
2197 			quit = 1;
2198 		    }
2199 		    break;
2200 
2201 		case ACTIVEWINDOW:
2202 		    if( gd = FindGadget( cwin, NULL, GADCONFNAME ) )
2203 			ActivateGadget( gd, cwin, NULL );
2204 		    break;
2205 
2206 		case CLOSEWINDOW:
2207 		    done = 1;
2208 		    quit = 0;
2209 		    break;
2210 
2211 		case GADGETUP:
2212 		    switch( gd->GadgetID )
2213 		    {
2214 			case GADSTRPATH:
2215 			    if( gd = FindGadget( cwin, NULL,GADSTRHACKDIR) )
2216 				ActivateGadget( gd, cwin, NULL );
2217 			    break;
2218 			case GADSTRHACKDIR:
2219 			    if( gd = FindGadget( cwin, NULL,GADSTRPENS) )
2220 				ActivateGadget( gd, cwin, NULL );
2221 			    break;
2222 			case GADSTRPENS:
2223 			    if( gd = FindGadget( cwin, NULL,GADSTRLEVELS) )
2224 				ActivateGadget( gd, cwin, NULL );
2225 			    break;
2226 			case GADSTRLEVELS:
2227 			    if( gd = FindGadget( cwin, NULL, GADSTRSAVE ) )
2228 				ActivateGadget( gd, cwin, NULL );
2229 			    break;
2230 			case GADSTRSAVE:
2231 			    if( gd = FindGadget( cwin, NULL, GADCONFNAME ) )
2232 				ActivateGadget( gd, cwin, NULL );
2233 			    break;
2234 
2235 			case GADCONFNAME:	/* Do nothing... */
2236 			    break;
2237 
2238 			case GADCONFLOAD:
2239 			    ReadConfig( );
2240                             env = malloc( strlen( StrConf ) + 3 +
2241 						strlen( "NETHACKOPTIONS" ) );
2242 			    sprintf( env, "NETHACKOPTIONS=@%s", StrConf );
2243 			    putenv( env );
2244 			    free( env );
2245 			    strcpy( StrPath, options[ PATH_IDX ] );
2246 			    strcpy( StrHackdir, options[ HACKDIR_IDX ] );
2247 			    strcpy( StrPens, options[ PENS_IDX ] );
2248 			    strcpy( StrLevels, options[ LEVELS_IDX ] );
2249 			    strcpy( StrSave, options[ SAVE_IDX ] );
2250 			    RefreshGList( cwin->FirstGadget, cwin, NULL, -1 );
2251 			    break;
2252 
2253 			case GADCONFSAVE:
2254         		    {
2255         		    	FILE *fp, *nfp;
2256         		    	char buf[ 300 ], *t, nname[ 100 ], oname[100], *b;
2257 
2258                                 setoneopt( PATH_IDX, StrPath );
2259                                 setoneopt( HACKDIR_IDX, StrHackdir );
2260                                 setoneopt( PENS_IDX, StrPens );
2261                                 setoneopt( LEVELS_IDX, StrLevels );
2262                                 setoneopt( SAVE_IDX, StrSave );
2263 
2264         			fp = fopen( StrConf, "r" );
2265         			if( !fp )
2266         			{
2267 				    fp = fopen( "NetHack:NetHack.cnf", "r" );
2268 				    strcpy( StrConf, "NetHack:NetHack.cnf" );
2269 				}
2270         			if( !fp )
2271         			{
2272                         	    errmsg( FLASH, "Can't open config file" );
2273                         	    break;
2274                         	}
2275 
2276                           	t = dirname( StrConf );
2277                         	b = basename( StrConf );
2278                           	if( t[ strlen(t)-1 ] == ':' )
2279                           	{
2280                           	    sprintf( nname, "%snew_%s", t, b);
2281                           	    sprintf( oname, "%sold_%s", t, b);
2282                         	}
2283                      		else
2284 				{
2285                             	    sprintf( oname, "%s/old_%s", t, b);
2286                             	    sprintf( nname, "%s/new_%s", t, b);
2287                         	}
2288 
2289         			nfp = fopen( nname, "w" );
2290         			if( !nfp )
2291         			{
2292                         	    errmsg( FLASH, "Can't open new config file for write" );
2293                         	    fclose( fp );
2294                         	    break;
2295                         	}
2296 
2297         			while( fgets( buf, sizeof( buf ), fp ) )
2298         			{
2299         			    if( strncmp( buf, "PATH=", 5 ) == 0 )
2300         			    	fprintf( nfp, "PATH=%s\n",
2301 						options[ PATH_IDX ] );
2302         			    else if( strncmp( buf, "LEVELS=", 7 ) == 0 )
2303         			    	fprintf( nfp, "LEVELS=%s\n",
2304 						options[ LEVELS_IDX ] );
2305         			    else if( strncmp( buf, "PENS=", 5 ) == 0 )
2306         			    	fprintf( nfp, "PENS=%s\n",
2307 						options[ PENS_IDX ] );
2308         			    else if( strncmp( buf, "SAVE=", 5 ) == 0 )
2309         			    	fprintf( nfp, "SAVE=%s\n",
2310 						options[ SAVE_IDX ] );
2311         			    else if( strncmp( buf, "HACKDIR=", 8 ) == 0 )
2312         			    	fprintf( nfp, "HACKDIR=%s\n",
2313 						options[ HACKDIR_IDX ] );
2314         			    else
2315         			    {
2316         			    	fputs( buf, nfp );
2317         			    }
2318         			}
2319         			fclose( fp );
2320         			fclose( nfp );
2321         			unlink( oname );
2322         			rename( StrConf, oname );
2323         			rename( nname, StrConf );
2324         		    }
2325 			    break;
2326 
2327 			default:
2328 			    break;
2329 		    }
2330 		    break;
2331 	    }
2332 	}
2333     }
2334 
2335     setoneopt( PATH_IDX, StrPath );
2336     setoneopt( HACKDIR_IDX, StrHackdir );
2337     setoneopt( PENS_IDX, StrPens );
2338     setoneopt( LEVELS_IDX, StrLevels );
2339     setoneopt( SAVE_IDX, StrSave );
2340 
2341     SafeCloseWindow( cwin );
2342 
2343     /* Display icons in possibly new save directory */
2344 
2345     MapGadgets( R_DISK, 1 );
2346 }
2347 
2348 void
2349 UpdateCnfFile()
2350 {
2351     FILE *fp, *nfp;
2352     char buf[ 300 ];
2353     char path=0,option=0,dir=0,pens=0,levels=0,save=0;
2354     char oname[ 300 ], nname[ 300 ];
2355 
2356     setoneopt( PATH_IDX, StrPath );
2357     setoneopt( HACKDIR_IDX, StrHackdir );
2358     setoneopt( PENS_IDX, StrPens );
2359     setoneopt( LEVELS_IDX, StrLevels );
2360     setoneopt( SAVE_IDX, StrSave );
2361 
2362     strcpy( oname, dirname( StrConf ) );
2363     if( oname[ strlen(oname)-1 ] != ':' )
2364     {
2365 	sprintf( nname, "%s/new_nethack.cnf", oname );
2366 	strcat( oname, "/" );
2367 	strcat( oname, "old_nethack.cnf" );
2368     }
2369     else
2370     {
2371 	sprintf( nname, "%snew_nethack.cnf", oname );
2372 	strcat( oname, "old_nethack.cnf" );
2373     }
2374 
2375     fp = fopen( StrConf, "r" );
2376     if( !fp )
2377     {
2378         errmsg( FLASH, "Can't open nethack.cnf" );
2379 		return;
2380     }
2381     nfp = fopen( nname, "w" );
2382     if( !nfp )
2383     {
2384         sprintf( buf, "Can't open %s for write", nname );
2385         errmsg( FLASH, buf );
2386         fclose( fp );
2387         return;
2388     }
2389     while( fgets( buf, sizeof( buf ), fp ) )
2390     {
2391         if( strncmp( buf, "PATH=", 5 ) == 0 )
2392 	{
2393             fprintf( nfp, "PATH=%s\n", options[ PATH_IDX ] );
2394 	    path=1;
2395 	}
2396         else if( strncmp( buf, "LEVELS=", 7 ) == 0 )
2397 	{
2398             fprintf( nfp, "LEVELS=%s\n", options[ LEVELS_IDX ] );
2399 	    levels=1;
2400 	}
2401         else if( strncmp( buf, "OPTIONS=", 8 ) == 0 )
2402 	{
2403             fprintf( nfp, "OPTIONS=%s\n", options[ OPTIONS_IDX ] );
2404 	    option=1;
2405 	}
2406         else if( strncmp( buf, "PENS=", 5 ) == 0 )
2407 	{
2408             fprintf( nfp, "PENS=%s\n", options[ PENS_IDX ] );
2409 	    pens=1;
2410 	}
2411         else if( strncmp( buf, "SAVE=", 5 ) == 0 )
2412 	{
2413             fprintf( nfp, "SAVE=%s\n", options[ SAVE_IDX ] );
2414 	    save=1;
2415 	}
2416         else if( strncmp( buf, "HACKDIR=", 8 ) == 0 )
2417 	{
2418             fprintf( nfp, "HACKDIR=%s\n", options[ HACKDIR_IDX ] );
2419 	    dir=1;
2420 	}
2421         else
2422         {
2423        	    fputs( buf, nfp );
2424         }
2425     }
2426 
2427     /* Write any that weren't already in the file */
2428     if( !path )
2429         fprintf( nfp, "PATH=%s\n", options[ PATH_IDX ] );
2430     if( !levels )
2431         fprintf( nfp, "LEVELS=%s\n", options[ LEVELS_IDX ] );
2432     if( !pens )
2433         fprintf( nfp, "PENS=%s\n", options[ PENS_IDX ] );
2434     if( !option )
2435         fprintf( nfp, "OPTIONS=%s\n", options[ OPTIONS_IDX ] );
2436     if( !save )
2437         fprintf( nfp, "SAVE=%s\n", options[ SAVE_IDX ] );
2438     if( !dir )
2439         fprintf( nfp, "HACKDIR=%s\n", options[ HACKDIR_IDX ] );
2440 
2441     /* Close up and rename files */
2442     fclose( fp );
2443     fclose( nfp );
2444     unlink( oname );
2445     if( filecopy( StrConf, oname ) == 0 )
2446 	filecopy( nname, StrConf );
2447 }
2448 
2449 filecopy( from, to )
2450     char *from, *to;
2451 {
2452     char *buf;
2453     int i = 0;
2454 
2455     buf = malloc( strlen(to) + strlen(from) + 20 );
2456     if( buf )
2457     {
2458     	sprintf( buf, "c:copy \"%s\" \"%s\" clone", from, to );
2459 
2460     	/* Check SysBase instead?  Shouldn't matter  */
2461 	if( IntuitionBase->LibNode.lib_Version >= 37 )
2462 	    i = System( buf, NULL );
2463 	else
2464 	    Execute( buf, NULL, NULL );
2465     	free( buf );
2466     }
2467     else
2468     {
2469     	errmsg( FLASH, "Failed to allocate memory for copy command" );
2470     	return( -1 );
2471     }
2472     return( i );
2473 }
2474 
2475 void do_gadgetup( imsg )
2476     register struct IntuiMessage *imsg;
2477 {
2478     register struct Gadget *gd;
2479     register unsigned long hid;
2480     int ncol, pot;
2481 
2482     gd = (struct Gadget *) imsg->IAddress;
2483 
2484     switch( gd->GadgetID )
2485     {
2486 	case GADSCROLL:
2487 	    hid = max( cols - vcols, 0 );
2488 	    pot = ( ( struct PropInfo * ) gd->SpecialInfo )->HorizPot;
2489 	    ncol = (hid * pot) / MAXPOT;
2490 	    if( ncol != curcol )
2491 	    {
2492 		curcol = ncol;
2493 		MapGadgets( R_SCROLL, 0 ); /* redisplay the icons */
2494 	    }
2495 	    break;
2496     }
2497 }
2498 
2499 void do_buttons( imsg )
2500     register struct IntuiMessage *imsg;
2501 {
2502     if( imsg->Code == SELECTDOWN || imsg->Code == SELECTUP )
2503     {
2504 	if( lastgaddown )
2505 	{
2506 	    SetGadgetUP( &lastgaddown->dobj->do_Gadget );
2507 	    lastgaddown->secs = 0;
2508 	    lastgaddown->mics = 0;
2509 	}
2510 	lastgaddown = NULL;
2511 	ChgGameItems( &MenuList1, 0 );
2512     }
2513 }
2514 
2515 void do_gadgetdown( imsg )
2516     register struct IntuiMessage *imsg;
2517 {
2518     register GPTR gptr;
2519     register struct Gadget *gd;
2520 
2521     gd = (struct Gadget *) imsg->IAddress;
2522 
2523     /* Don't do anything for these gadgets */
2524 
2525     if( gd->GadgetID < GADNEWGAME )
2526     {
2527 	return;
2528     }
2529 
2530     /* Check just to make sure we got it */
2531 
2532     for( gptr = windowgads; gptr &&
2533 	gptr->dobj->do_Gadget.GadgetID != gd->GadgetID; )
2534     {
2535 	gptr = gptr->nextwgad;
2536     }
2537 
2538     if( !gptr )
2539     {
2540 	errmsg( FLASH, "Bad GadgetID for GadgetDOWN" );
2541 	return;
2542     }
2543 
2544     /* Fix the gadget images */
2545 
2546     if( lastgaddown && &lastgaddown->dobj->do_Gadget != gd )
2547     {
2548 	SetGadgetUP( &lastgaddown->dobj->do_Gadget );
2549 	gptr->secs = 0;
2550 	gptr->mics = 0;
2551     }
2552     SetGadgetDOWN( &((lastgaddown = gptr)->dobj->do_Gadget) );
2553 
2554     /* Only allow game gadgets to be manipulated */
2555 
2556     if( lastgaddown->dobj->do_Gadget.GadgetID == GADNEWGAME )
2557 	ChgNewGameItems( &MenuList1, 1 );
2558     else
2559 	ChgGameItems( &MenuList1, 1 );
2560 
2561     /* Check if this gadget has been double clicked */
2562 
2563     if( DoubleClick( gptr->secs, gptr->mics, imsg->Seconds, imsg->Micros ) )
2564     {
2565 	run_game( gptr );
2566 	gptr->secs = 0;
2567 	gptr->mics = 0;
2568 	return;
2569     }
2570 
2571     gptr->secs = imsg->Seconds;
2572     gptr->mics = imsg->Micros;
2573 }
2574 
2575 /* move the tooltypes options to the options data, edit the options, and then
2576  * move the settings back into the tooltypes.
2577  */
2578 void setopt( gptr )
2579     register GPTR gptr;
2580 {
2581     ZapOptions();		/* Set boolean options to defaults and empty all strings */
2582     ReadCfgOptions();		/* Set options based on NetHack.cnf. */
2583     CopyOptions( gptr );	/* Put the ToolTypes into the options structures */
2584     if( EditOptions( gptr ) )	/* Let the user change them around */
2585 	PutOptions( gptr );		/* Put everything back into the ToolTypes. */
2586 }
2587 
2588 void ZapOptions()
2589 {
2590     int i;
2591 
2592     AllocCompVals();
2593     for( i = 0; boolopt[ i ].name; ++i )
2594     {
2595 	if( boolopt[ i ].addr != NULL )
2596 	    *boolopt[ i ].addr = boolopt[ i ].initvalue;
2597     }
2598 
2599     for( i = 0; compvals && compvals[ i ]; ++i )
2600     {
2601     	*compvals[ i ] = 0;
2602     }
2603 }
2604 
2605 void menu_info()
2606 {
2607     int itemno;
2608     register struct IntuiMessage *imsg;
2609     char *t;
2610     register GPTR gptr, ggptr;
2611     register struct Gadget *gd;
2612     register struct FileInfoBlock *finfo;
2613     register struct Window *cwin;
2614     register int i;
2615     int done = 0;
2616     long lock, olock;
2617     char **sp;
2618     static int once = 0;
2619     long code, class, qual;
2620     static struct IntuiText itext[ 2 ];
2621     char commentstr[ 100 ], *s;
2622     int txtdiff = scrn->RastPort.TxHeight - 8;
2623 
2624     if( ( gptr = NeedGame() ) == NULL )
2625 	return;
2626 
2627     if( ( lock = Lock( GameName( gptr, NULL ), ACCESS_READ ) ) == NULL )
2628     {
2629 	/* Can't get lock, reload and return */
2630 
2631 	errmsg( FLASH, "Can't Lock game save file: %s",
2632 		GameName( gptr, NULL ) );
2633 	MapGadgets( R_DISK, 1 );
2634 	return;
2635     }
2636 
2637     finfo = (struct FileInfoBlock *)xmalloc(sizeof(struct FileInfoBlock));
2638     Examine( lock, finfo );
2639     UnLock( lock );
2640     strncpy( commentstr, finfo->fib_Comment, sizeof( finfo->fib_Comment ) );
2641     commentstr[ sizeof( finfo->fib_Comment ) ] = 0;
2642     free( finfo );
2643 
2644     ReallocTools( gptr, 0 );
2645     Info_NewWindowStructure6.Screen = scrn;
2646 
2647     if( !once )
2648     {
2649 	/* These are static, so just do this once */
2650 	for( i = 0; i < 2; ++i )
2651 	{
2652 	    itext[ i ].FrontPen = C_BLACK;
2653 	    itext[ i ].BackPen = C_GREY;
2654 	    itext[ i ].DrawMode = JAM2;
2655 	    itext[ i ].TopEdge = 2;
2656 	    itext[ i ].LeftEdge = 4;
2657 	}
2658 
2659     	Info_Comment.TopEdge += txtdiff*2;
2660 	Info_NewWindowStructure6.Height += txtdiff * 7;
2661 	for( gd = Info_NewWindowStructure6.FirstGadget;
2662 		gd; gd = gd->NextGadget )
2663 	{
2664 	    if( gd->GadgetID != GADTOOLUP && gd->GadgetID != GADTOOLDOWN )
2665 		gd->Height += txtdiff;
2666 	    gd->TopEdge += txtdiff;
2667 	    switch( gd->GadgetID )
2668 	    {
2669 		case 0:
2670 		    break;
2671 
2672 		case GADEDITOPTS:
2673 		    gd->TopEdge += txtdiff*3;
2674 		    SetBorder( gd, -1 );
2675 		    break;
2676 
2677 		case GADTOOLTYPES:
2678 		    gd->TopEdge += txtdiff*4;
2679 		    if( scrn->Height > 300 )
2680 			gd->TopEdge += 2;
2681 		    SetBorder( gd, -1 );
2682 		    break;
2683 
2684 		case GADDELTOOL:
2685 		    gd->TopEdge += txtdiff*3;
2686 		    SetBorder( gd, -1 );
2687 		    break;
2688 
2689 		case GADADDTOOL:
2690 		    gd->TopEdge += txtdiff*3;
2691 		    SetBorder( gd, -1 );
2692 		    break;
2693 
2694 		case GADSAVEINFO:
2695 		    gd->TopEdge += txtdiff*5;
2696 		    SetBorder( gd, -1 );
2697 		    break;
2698 
2699 		case GADQUITINFO:
2700 		    gd->TopEdge += txtdiff*5;
2701 		    SetBorder( gd, -1 );
2702 		    break;
2703 
2704 		case GADUSEINFO:
2705 		    gd->TopEdge += txtdiff*5;
2706 		    SetBorder( gd, -1 );
2707 		    break;
2708 
2709 		case GADTOOLUP:
2710 		    gd->TopEdge += txtdiff*4;
2711 		    gd->Flags &= ~GADGHIGHBITS;
2712 		    gd->Flags |= GADGIMAGE|GADGHIMAGE;
2713 		    if( scrn->Height > 300 )
2714 		    {
2715 			gd->GadgetRender = (APTR)&tall_up_selectimage;
2716 			gd->SelectRender = (APTR)&tall_up_renderimage;
2717 			gd->Height *= 2;
2718 			if( txtdiff == 0 )
2719 			    gd->TopEdge -= 2;
2720 		    }
2721 		    else
2722 		    {
2723 			gd->GadgetRender = (APTR)&up_selectimage;
2724 			gd->SelectRender = (APTR)&up_renderimage;
2725 		    }
2726 		    break;
2727 
2728 		case GADTOOLDOWN:
2729 		    gd->TopEdge += txtdiff*5;
2730 		    gd->Flags &= ~GADGHIGHBITS;
2731 		    gd->Flags |= GADGIMAGE|GADGHIMAGE;
2732 		    if( scrn->Height > 300 )
2733 		    {
2734 			gd->GadgetRender = (APTR)&tall_down_selectimage;
2735 			gd->SelectRender = (APTR)&tall_down_renderimage;
2736 			gd->Height *= 2;
2737 			if( txtdiff == 0 )
2738 			    gd->TopEdge += 4;
2739 		    }
2740 		    else
2741 		    {
2742 			gd->GadgetRender = (APTR)&down_selectimage;
2743 			gd->SelectRender = (APTR)&down_renderimage;
2744 		    }
2745 		    break;
2746 
2747 		default:
2748 		    if( gd == &Info_Class )
2749 			SetBorder( gd, 2 );
2750 		    else
2751 			SetBorder( gd, -1 );
2752 	    }
2753 	}
2754 
2755 	itext[ 0 ].NextText = Info_Class.GadgetText;
2756 	Info_Class.GadgetText = &itext[ 0 ];
2757 	++once;
2758     }
2759 
2760     strncpy( Sbuff( &Info_Comment ), commentstr, 100 );
2761 
2762     /* The players name */
2763 
2764     strncpy( StrPlayer, ToolsEntry( gptr, "NAME" ), 100 );
2765     if( *StrPlayer == 0 )
2766 	strncpy( StrPlayer, gptr->name, 99 );
2767 
2768     if( ( t = strrchr( StrPlayer, '.' ) ) && stricmp( t, ".sav" ) == 0 )
2769 	*t = 0;
2770 
2771     /* The character class of the player */
2772 
2773     itext[ 0 ].IText = ToolsEntry( gptr, "CHARACTER" );
2774 
2775     /* DCF - Changed "itext[ i ].IText == NULL" to "itext[ 0 ].Itext == NULL" */
2776     if( itext[ 0 ].IText == NULL || *itext[ 0 ].IText == 0 )
2777     {
2778 	itext[ 0 ].IText = players[ 0 ];
2779 	SetToolLine( gptr, "CHARACTER", "" );
2780     }
2781 
2782     /* If there are ToolTypes entries, put the first one into the gadget */
2783 
2784     sp = gptr->dobj->do_ToolTypes;
2785     if( sp && *sp )
2786 	strcpy( StrTools, *sp );
2787 
2788     if( IsEditEntry( StrTools, gptr ) )
2789 	Info_ToolTypes.Flags &= ~GADGDISABLED;
2790     else
2791 	Info_ToolTypes.Flags |= GADGDISABLED;
2792 
2793     if( ( cwin = MyOpenWindow( &Info_NewWindowStructure6 ) ) == NULL )
2794     {
2795 	errmsg( FLASH, "Can't create info window" );
2796 	return;
2797     }
2798 
2799     itemno = 0;
2800     if( s = FindToolType( (char **) gptr->dobj->do_ToolTypes, "CHARACTER" ) )
2801     {
2802 	s += 10;
2803 	for( itemno = 0; players[ itemno ]; ++itemno )
2804 	{
2805 	    if( strnicmp( s, players[ itemno ], strlen( s ) ) == 0 )
2806 		break;
2807 	}
2808     }
2809     if( !players[ itemno ] )
2810 	itemno = 0;
2811 
2812     CheckOnly( &Info_MenuList6, 0, itemno );
2813     SetUpMenus( &Info_MenuList6, scrn );
2814     SetMenuStrip( cwin, &Info_MenuList6 );
2815 
2816     while( !done )
2817     {
2818 	WaitPort( cwin->UserPort );
2819 	while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
2820 	{
2821 	    class = imsg->Class;
2822 	    code = imsg->Code;
2823 	    qual = imsg->Qualifier;
2824 	    gd = (struct Gadget *)imsg->IAddress;
2825 
2826 	    ReplyMsg( (struct Message *)imsg );
2827 
2828 	    switch( class )
2829 	    {
2830 		case VANILLAKEY:
2831 		    if( code == '\33' || (code == 'b' && (qual&AMIGALEFT)) )
2832 		    {
2833 			done = 1;
2834 		    }
2835 		    break;
2836 
2837 		case CLOSEWINDOW:
2838 		    if( sp )
2839 		    {
2840 			if( *sp )
2841 			    free( *sp );
2842 			*sp = strdup( StrTools );
2843 		    }
2844 		    done = 1;
2845 		    break;
2846 
2847 		case GADGETUP:
2848 		    switch( gd->GadgetID )
2849 		    {
2850 		    case GADSAVEINFO:
2851 			/* Write icon and quit. */
2852 			SetToolLine( gptr, "NAME", StrPlayer );
2853 			UpdateGameIcon( gptr );
2854 			lock = Lock( gptr->dname, ACCESS_READ );
2855 			if( lock )
2856 			{
2857 			    olock = CurrentDir( lock );
2858 			    SetComment( gptr->fname, Sbuff( &Info_Comment ) );
2859 			    if( olock ) CurrentDir( olock );
2860 			    done = 1;
2861 			    UnLock( lock );
2862 			}
2863 			else
2864 			{
2865 			    errmsg( FLASH, "Can't access icon's directory" );
2866 			    sp = gptr->dobj->do_ToolTypes;
2867 			    strcpy( StrTools, *sp ? *sp : "" );
2868 			    UpdateInfoWin( cwin );
2869 			}
2870 			break;
2871 
2872 		    case GADUSEINFO:
2873 			/* Quit this loop. */
2874 			done = 1;
2875 			break;
2876 
2877 		    case GADQUITINFO:
2878 			/* Reload icon and quit this loop. */
2879 			for( ggptr = windowgads; ggptr; ggptr = ggptr->nextwgad )
2880 			    RemoveGadget( win, &ggptr->dobj->do_Gadget );
2881 			windowgads = NULL;
2882 			RemoveGITEM( gptr );
2883 			lastgaddown = NULL; /* very important... */
2884 			MapGadgets( R_DISK, 1 );
2885 			done = 1;
2886 			break;
2887 
2888 		    case GADEDITOPTS:
2889 			SetPointer( cwin, waitPointer, 16, 16, -6, 0 );
2890 			setopt( gptr );
2891 			sp = gptr->dobj->do_ToolTypes;
2892 			strcpy( StrTools, *sp ? *sp : "" );
2893 			UpdateInfoWin( cwin );
2894 			ClearPointer( cwin );
2895 			break;
2896 
2897 		    case GADADDTOOL:
2898 			FreeTools( gptr );
2899 			ReallocTools( gptr, 2 );
2900 			sp = gptr->dobj->do_ToolTypes;
2901 			for( i = 0; sp[ i ]; ++i )
2902 			    ;
2903 			sp[i] = strdup( "" );
2904 			sp[i+1] = NULL;
2905 			itext[ 0 ].IText =
2906 			    ToolsEntry( gptr, "CHARACTER" );
2907 			*StrTools = 0;
2908 			Info_ToolTypes.Flags &= ~GADGDISABLED;
2909 			UpdateInfoWin( cwin );
2910 			sp += i;
2911 			break;
2912 
2913 		    case GADDELTOOL:
2914 			while( *sp = sp[1] )
2915 			    ++sp;
2916 			sp = gptr->dobj->do_ToolTypes;
2917 			strcpy( StrTools, *sp ? *sp : "" );
2918 			Info_ToolTypes.Flags &= ~GADGDISABLED;
2919 			UpdateInfoWin( cwin );
2920 			break;
2921 
2922 		    case GADTOOLTYPES:
2923 			if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
2924 			{
2925 			    if( *sp )
2926 				free( *sp );
2927 			    *sp = strdup( StrTools );
2928 			}
2929 			break;
2930 
2931 		    case GADTOOLDOWN:
2932 			if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
2933 			{
2934 			    if( *sp )
2935 				free( *sp );
2936 			    *sp = strdup( StrTools );
2937 			}
2938 
2939 			if( sp && sp[0] && sp[1] )
2940 			{
2941 			    ++sp;
2942 			    strcpy( StrTools, *sp );
2943 			    if( IsEditEntry( StrTools, gptr ) )
2944 				Info_ToolTypes.Flags &= ~GADGDISABLED;
2945 			    else
2946 				Info_ToolTypes.Flags |= GADGDISABLED;
2947 			}
2948 			else
2949 			{
2950 			    if( sp && *sp )
2951 				strcpy( StrTools, *sp );
2952 			    DisplayBeep( NULL );
2953 			}
2954 			break;
2955 
2956 		    case GADTOOLUP:
2957 			if( sp && *sp && CheckAndCopy( StrTools, *sp ) )
2958 			{
2959 			    if( *sp )
2960 				free( *sp );
2961 			    *sp = strdup( StrTools );
2962 			}
2963 			if( sp && sp > gptr->dobj->do_ToolTypes )
2964 			{
2965 			    --sp;
2966 			    if( *sp )
2967 			    {
2968 				strcpy( StrTools, *sp );
2969 				if( IsEditEntry( StrTools, gptr ) )
2970 				    Info_ToolTypes.Flags &= ~GADGDISABLED;
2971 				else
2972 				    Info_ToolTypes.Flags |= GADGDISABLED;
2973 			    }
2974 			}
2975 			else
2976 			{
2977 			    DisplayBeep( NULL );
2978 			}
2979 			break;
2980 
2981 		    case GADPLNAME:
2982 			SetToolLine( gptr, "NAME", StrPlayer );
2983 			sp = gptr->dobj->do_ToolTypes;
2984 			strcpy( StrTools, *sp ? *sp : "" );
2985 			UpdateInfoWin( cwin );
2986 			break;
2987 		    }
2988 		    RefreshGList( &Info_ToolTypes, cwin, NULL, 1 );
2989 		    break;
2990 
2991 	    	case MENUPICK:
2992 	    	    while( code != MENUNULL )
2993 	    	    {
2994 			int idx = ITEMNUM( code );
2995 
2996 			if( idx == 0 )
2997 			{
2998 			    SetToolLine( gptr, "CHARACTER", "" );
2999 			}
3000 			else
3001 			{
3002 			    SetToolLine( gptr, "CHARACTER", players[ idx ] );
3003 			}
3004 			itext[ 0 ].IText = players[ idx ];
3005 			sp = gptr->dobj->do_ToolTypes;
3006 			strcpy( StrTools, (sp && *sp) ? *sp : "" );
3007 			UpdateInfoWin( cwin );
3008 			code = ((struct MenuItem *)ItemAddress(
3009 				&Info_MenuList6, (long)code ))->NextSelect;
3010 		    }
3011 		    break;
3012 	    }
3013 	}
3014     }
3015 
3016     SafeCloseWindow( cwin );
3017 }
3018 
3019 static void
3020 UpdateInfoWin( cwin )
3021     struct Window *cwin;
3022 {
3023     SetAPen( cwin->RPort, 0 );
3024     SetBPen( cwin->RPort, 0 );
3025     SetDrMd( cwin->RPort, JAM2 );
3026     RectFill( cwin->RPort,
3027 	Info_Class.LeftEdge,
3028 	Info_Class.TopEdge,
3029 	Info_Class.LeftEdge + Info_Class.Width-1,
3030 	Info_Class.TopEdge + Info_Class.Height-1 );
3031     RefreshGList( cwin->FirstGadget, cwin, NULL, -1 );
3032 }
3033 
3034 char embuf[ 300 ];
3035 void
3036 errmsg(int flash, char *str, ...)
3037 {
3038     int wid;
3039     va_list vp;
3040 
3041     va_start( vp, str );
3042 
3043     if( !win || !wbopen )
3044     {
3045 	vprintf( str, vp );
3046 	va_end( vp );
3047 	return;
3048     }
3049     errup = 1;
3050     wid = ( win->Width + Message.LeftEdge - win->BorderRight - 3 ) /
3051 		    win->RPort->TxWidth;
3052     vsprintf( embuf, str, vp );
3053     va_end( vp );
3054 
3055     SetAPen( win->RPort, 0 );
3056     SetBPen( win->RPort, 0 );
3057     SetDrMd( win->RPort, JAM2 );
3058     RectFill( win->RPort, Message.LeftEdge, Message.TopEdge,
3059 	win->Width + Message.Width,
3060 	Message.TopEdge + Message.Height - 1 );
3061 
3062     Message.GadgetText->IText = embuf;
3063     RefreshGList( &Message, win, 0, 1 );
3064 
3065     if( flash == FLASH )
3066 	DisplayBeep( scrn );
3067 }
3068 
3069 /*
3070  * Issue an error message to the users window because it can not be done
3071  * any other way.
3072  */
3073 
3074 void error( str )
3075     register const char *str;
3076 {
3077     char s[ 50 ];
3078     if( scrn ) ScreenToBack( scrn );
3079     Delay( 10 );
3080     fprintf( stderr, "%s\n", str );
3081     fprintf( stderr, "Hit Return: " );
3082     fflush( stderr );
3083     gets( s );
3084     if( scrn ) ScreenToFront( scrn );
3085 }
3086 
3087 /*
3088  * Make the gadget deselected
3089  */
3090 
3091 void SetGadgetUP( gad )
3092     register struct Gadget *gad;
3093 {
3094     if( gad->Flags & GADGIMAGE )
3095     {
3096 	DrawImage( win->RPort, (struct Image *)gad->GadgetRender,
3097 		gad->LeftEdge, gad->TopEdge );
3098     }
3099 #if 0
3100     RemoveGadget( win, gad );
3101     gad->Flags &= ~(SELECTED|GADGHIGHBITS);
3102     gad->Flags |= GADGHIMAGE|GADGIMAGE;
3103     gad->Activation |= TOGGLESELECT;
3104     AddGadget( win, gad, 0 );
3105     RefreshGList( gad, win, NULL, 1 );
3106     RemoveGadget( win, gad );
3107     gad->Flags &= ~(GADGHIGHBITS);
3108     gad->Flags |= GADGHNONE;
3109     gad->Activation &= ~TOGGLESELECT;
3110     AddGadget( win, gad, 0 );
3111 #endif
3112 }
3113 
3114 /*
3115  * Make the gadget selected
3116  */
3117 
3118 void SetGadgetDOWN( gad )
3119     register struct Gadget *gad;
3120 {
3121     if( gad->Flags & GADGHIMAGE )
3122     {
3123 	DrawImage( win->RPort, (struct Image *)gad->SelectRender,
3124 		gad->LeftEdge, gad->TopEdge );
3125     }
3126 }
3127 
3128 /*
3129  * Generate a requester for a string value.
3130  */
3131 
3132 int StrRequest( prompt, buff, val )
3133     char *prompt, *buff, *val;
3134 {
3135     struct Window *cwin;
3136     struct IntuiMessage *imsg;
3137     int done = 0, notcan = 1;
3138     long class, code, qual;
3139     struct Gadget *gd;
3140     static int once = 0;
3141     int txtdiff = scrn->RastPort.TxHeight - 8;
3142 
3143     *StrString = 0;
3144     if( val )
3145 	strcpy( StrString, val );
3146     Str_NewWindowStructure5.Title = prompt;
3147 
3148     if( !once )
3149     {
3150 	for( gd = Str_NewWindowStructure5.FirstGadget;
3151 		    gd; gd = gd->NextGadget )
3152 	{
3153 	    if( gd->GadgetID != 0 )
3154 	    {
3155 		gd->TopEdge += txtdiff;
3156 		gd->Height += txtdiff;
3157 		SetBorder( gd, -1 );
3158 	    }
3159 	}
3160 	++once;
3161 	Str_NewWindowStructure5.Height += txtdiff * 2;
3162     }
3163 
3164     Str_NewWindowStructure5.Screen = scrn;
3165     if( ( cwin = MyOpenWindow( &Str_NewWindowStructure5 ) ) == NULL )
3166     {
3167 	errmsg( FLASH, "Can't create requester window" );
3168 	return( 0 );
3169     }
3170 
3171     while( !done )
3172     {
3173 	WaitPort( cwin->UserPort );
3174 	while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
3175 	{
3176 	    class = imsg->Class;
3177 	    code = imsg->Code;
3178 	    qual = imsg->Qualifier;
3179 	    gd = (struct Gadget *) imsg->IAddress;
3180 	    ReplyMsg( (struct Message *) imsg );
3181 	    switch( class )
3182 	    {
3183 		case ACTIVEWINDOW:
3184 		    ActivateGadget( &Str_String, cwin, NULL );
3185 		    break;
3186 
3187 		case GADGETUP:
3188 		    switch( gd->GadgetID )
3189 		    {
3190 			case GADSTRCANCEL:
3191 			    notcan = 0;
3192 			    done = 1;
3193 			    break;
3194 
3195 			default:
3196 			    strcpy( buff, StrString );
3197 			    done = 1;
3198 			    break;
3199 		    }
3200 		    break;
3201 
3202 		case CLOSEWINDOW:
3203 		    strcpy( buff, StrString );
3204 		    done = 1;
3205 		    break;
3206 
3207 		case VANILLAKEY:
3208 		    if( code == '\33' || code == 'b' && (qual&AMIGALEFT) )
3209 		    {
3210 			done = 1;
3211 			notcan = 0;
3212 		    }
3213 		    break;
3214 	    }
3215 	}
3216     }
3217 
3218     SafeCloseWindow( cwin );
3219     return( notcan );
3220 }
3221 
3222 /*
3223  * Ask the user if they really want to do something.
3224  */
3225 
3226 Ask( quest )
3227     char *quest;
3228 {
3229     register struct Window *qwin;
3230     register struct Gadget *gd;
3231     register struct IntuiMessage *imsg;
3232     register int done = 0, quit = 1;
3233     int txtdiff;
3234     long class, code, qual;
3235     static int once = 0;
3236     static WORD areabuffer[ 80 ];
3237     static USHORT apat[] = { 0x5555, 0xaaaa };
3238     static struct AreaInfo areaInfo = { 0 };
3239     PLANEPTR pp;
3240     struct TmpRas tmpras;
3241 
3242     Quest_NewWindowStructure2.Screen = scrn;
3243     txtdiff = scrn->RastPort.TxHeight - 8;
3244     if( !once )
3245     {
3246 	Quest_IntuiTextList2.TopEdge += txtdiff;
3247 	Quest_Borders2.TopEdge += txtdiff;
3248 	Quest_NewWindowStructure2.Height += txtdiff * 2;
3249 	SetBorder( &Quest_Borders2, 3 );
3250 	Quest_Yes.TopEdge += txtdiff;
3251 	Quest_Yes.Height += txtdiff;
3252 	SetBorder( &Quest_Yes, -1 );
3253 	Quest_No.TopEdge += txtdiff;
3254 	Quest_No.Height += txtdiff;
3255 	SetBorder( &Quest_No, -1 );
3256     }
3257 
3258     memset( areabuffer, 0, sizeof( areabuffer ) );
3259     if( ( qwin = MyOpenWindow( &Quest_NewWindowStructure2 ) ) == NULL )
3260     {
3261 	errmsg( FLASH, "Can't create requester window" );
3262 	return( 1 );
3263     }
3264 
3265     pp = AllocRaster( qwin->Width, qwin->Height );
3266     if( pp )
3267     {
3268 	InitArea( &areaInfo, areabuffer, 160/5 );
3269 	qwin->RPort->AreaInfo = &areaInfo;
3270 
3271 	InitTmpRas( &tmpras, pp, RASSIZE( qwin->Width, qwin->Height ) );
3272 	qwin->RPort->TmpRas = &tmpras;
3273 
3274 	SetAPen( qwin->RPort, C_WHITE );
3275 	SetBPen( qwin->RPort, C_GREY );
3276 	SetDrMd( qwin->RPort, JAM2 );
3277 	SetAfPt( qwin->RPort, apat, 1 );
3278 
3279 	AreaMove( qwin->RPort, qwin->BorderLeft, qwin->BorderTop );
3280 	AreaDraw( qwin->RPort, qwin->Width-qwin->BorderRight, qwin->BorderTop );
3281 	AreaDraw( qwin->RPort, qwin->Width - qwin->BorderRight,
3282 		qwin->Height - qwin->BorderBottom );
3283 	AreaDraw( qwin->RPort, qwin->BorderLeft,
3284 		qwin->Height - qwin->BorderBottom );
3285 	AreaDraw( qwin->RPort, qwin->BorderLeft, qwin->BorderTop );
3286 	AreaEnd( qwin->RPort );
3287 
3288 	SetAPen( qwin->RPort, C_GREY );
3289 	SetBPen( qwin->RPort, C_GREY );
3290 	SetDrMd( qwin->RPort, JAM2 );
3291 	SetAfPt( qwin->RPort, NULL, 0 );
3292 
3293 	RectFill( qwin->RPort,
3294 		Quest_Borders2.LeftEdge,
3295 		Quest_Borders2.TopEdge,
3296 		Quest_Borders2.LeftEdge + Quest_Borders2.Width - 1,
3297 		Quest_Borders2.TopEdge + Quest_Borders2.Height - 1 );
3298 	RectFill( qwin->RPort,
3299 		Quest_No.LeftEdge,
3300 		Quest_No.TopEdge,
3301 		Quest_No.LeftEdge + Quest_No.Width - 1,
3302 		Quest_No.TopEdge + Quest_No.Height - 1 );
3303 	RectFill( qwin->RPort,
3304 		Quest_Yes.LeftEdge,
3305 		Quest_Yes.TopEdge,
3306 		Quest_Yes.LeftEdge + Quest_Yes.Width - 1,
3307 		Quest_Yes.TopEdge + Quest_Yes.Height - 1 );
3308 	RefreshGList( qwin->FirstGadget, qwin, NULL, -1 );
3309     }
3310 
3311     Quest_IntuiTextList2.LeftEdge = ( qwin->Width -
3312 	( qwin->RPort->TxWidth * strlen( quest ) ) ) / 2;
3313     Quest_IntuiTextList2.IText = quest;
3314     PrintIText( qwin->RPort, &Quest_IntuiTextList2, 0, 0 );
3315     while( !done )
3316     {
3317 	WaitPort( qwin->UserPort );
3318 	while( ( imsg = (void *) GetMsg( qwin->UserPort ) ) != NULL )
3319 	{
3320 	    class = imsg->Class;
3321 	    code = imsg->Code;
3322 	    qual = imsg->Qualifier;
3323 	    gd = (struct Gadget *)imsg->IAddress;
3324 
3325 	    ReplyMsg( (struct Message *)imsg );
3326 
3327 	    switch( class )
3328 	    {
3329 		case VANILLAKEY:
3330 		    if( imsg->Qualifier & AMIGALEFT )
3331 		    {
3332 			switch( imsg->Code )
3333 			{
3334 			    case 'v': done = 1; quit = 0; break;
3335 			    case '\33':
3336 			    case 'b': done = 1; quit = 1; break;
3337 			}
3338 		    }
3339 		    break;
3340 
3341 		case CLOSEWINDOW:
3342 		    done = 1; quit = 1; break;
3343 		    break;
3344 
3345 		case GADGETUP:
3346 		    switch( gd->GadgetID )
3347 		    {
3348 			case GADQUESTYES: done = 1; quit = 0; break;
3349 			case GADQUESTNO: done = 1; quit = 1; break;
3350 		    }
3351 		    break;
3352 	    }
3353 	}
3354     }
3355 
3356     if( pp )
3357 	FreeRaster( pp, qwin->Width, qwin->Height );
3358     once = 1;
3359     SafeCloseWindow( qwin );
3360     return( quit == 0 );
3361 }
3362 
3363 /* Make sure that a game icon is selected and return the pointer to
3364  * the GPTR structure associated with it.
3365  */
3366 
3367 GPTR NeedGame()
3368 {
3369     register GPTR gptr;
3370 
3371     if( lastgaddown == NULL )
3372     {
3373 	errmsg( FLASH, "Must select a game" );
3374 	return( NULL );
3375     }
3376 
3377     for( gptr = windowgads; gptr; gptr = gptr->nextwgad )
3378     {
3379 	if( &gptr->dobj->do_Gadget == &lastgaddown->dobj->do_Gadget )
3380 	    break;
3381     }
3382 
3383     if( !gptr )
3384     {
3385 	errmsg( FLASH, "BUG: invalid gadget selected for processing" );
3386 	return( NULL );
3387     }
3388     return( gptr );
3389 }
3390 
3391 /* Set menu items SELECT flag based on 'enable' */
3392 
3393 void ChgGameItems( menup, enable )
3394     struct Menu *menup;
3395     int enable;
3396 {
3397     struct MenuItem *ip;
3398     int i;
3399     int ino;
3400 
3401     /* Make sure the 'Game' menu is there. */
3402 
3403     if( !menup || !(menup = menup->NextMenu) || !( ip = menup->FirstItem ) )
3404     {
3405 	errmsg( FLASH, "BUG: invalid menu to disable with" );
3406 	return;
3407     }
3408 
3409     /* Go through all items */
3410 
3411     for( i = 0; ip; ip = ip->NextItem, ++i )
3412     {
3413 	switch( i )
3414 	{
3415 	    case ITEM_INFO:
3416 	    case ITEM_COPYOPT:
3417 	    case ITEM_DISCARD:
3418 	    case ITEM_RENAME:
3419 		ino = MENUITEMNO( 1,i,NOSUB );
3420 		if( enable )
3421 		    OnMenu( win, ino );
3422 		else
3423 		    OffMenu( win, ino );
3424 		break;
3425 	}
3426     }
3427 }
3428 
3429 /* Set menu items SELECT flag based on 'enable' for NEWGAME gadget */
3430 
3431 void ChgNewGameItems( menup, enable )
3432     struct Menu *menup;
3433     int enable;
3434 {
3435     struct MenuItem *ip;
3436     int i;
3437     int ino;
3438 
3439     /* Make sure the 'Game' menu is there. */
3440 
3441     if( !menup || !(menup = menup->NextMenu) || !( ip = menup->FirstItem ) )
3442     {
3443 	errmsg( FLASH, "BUG: invalid menu to disable with" );
3444 	return;
3445     }
3446 
3447     /* Go through all items */
3448 
3449     for( i = 0; ip; ip = ip->NextItem, ++i )
3450     {
3451 	switch( i )
3452 	{
3453 	    case ITEM_RENAME:
3454 	    case ITEM_DISCARD:
3455 		ino = MENUITEMNO( 1,i,NOSUB );
3456 		OffMenu( win, ino );
3457 		break;
3458 
3459 	    case ITEM_COPYOPT:
3460 	    case ITEM_INFO:
3461 		ino = MENUITEMNO( 1,i,NOSUB );
3462 		if( enable )
3463 		    OnMenu( win, ino );
3464 		else
3465 		    OffMenu( win, ino );
3466 		break;
3467 	}
3468     }
3469 }
3470 
3471 /* Edit the OPTIONS= lines with a window. */
3472 
3473 USHORT lastoptx, lastopty, lastoptw, lastopth;
3474 int EditOptions( gptr )
3475     GPTR gptr;
3476 {
3477     int txtdiff = scrn->RastPort.TxHeight - 8;
3478     struct RastPort *rp;
3479     struct Gadget *gd, *lastgad = 0;
3480     struct TextAttr textfont;
3481     long code, class;
3482     int done = 0, save = 0;
3483     struct IntuiMessage *imsg;
3484     struct Window *w;
3485     int cury = -1, gadid = 1, compgadid;
3486     struct OPTGAD *gp;
3487     struct OPTGAD *boolgads, *compgads;
3488     static int once = 0;
3489 
3490     Options_NewWindowStructure3.Screen = scrn;
3491     Options_NewWindowStructure3.TopEdge = 0;
3492     Options_NewWindowStructure3.LeftEdge = 0;
3493     Options_NewWindowStructure3.Width = scrn->Width;
3494     Options_NewWindowStructure3.Height = scrn->Height;
3495     Options_NewWindowStructure3.Title = "Edit Options";
3496 
3497     if( lastoptw != 0 )
3498     {
3499 	Options_NewWindowStructure3.LeftEdge = lastoptx;
3500 	Options_NewWindowStructure3.TopEdge = lastopty;
3501 	Options_NewWindowStructure3.Width = lastoptw;
3502 	Options_NewWindowStructure3.Height = lastopth;
3503     }
3504 
3505     if( !once )
3506     {
3507 	for( gd = Options_NewWindowStructure3.FirstGadget;
3508 		gd; gd = gd->NextGadget )
3509 	{
3510 	    switch( gd->GadgetID )
3511 	    {
3512 		case GADOPTOKAY:
3513 		case GADOPTCANCEL:
3514 		    gd->TopEdge -= txtdiff;
3515 		    gd->Height += txtdiff;
3516 		    SetBorder( gd, -1 );
3517 		    break;
3518 	    }
3519 	}
3520 	once = 1;
3521     }
3522 
3523     w = MyOpenWindow( (void *)&Options_NewWindowStructure3 );
3524     if( w )
3525     {
3526     	rp = w->RPort;
3527 	textfont.ta_Name = w->RPort->Font->tf_Message.mn_Node.ln_Name;
3528 	textfont.ta_YSize = w->RPort->Font->tf_YSize;
3529 	textfont.ta_Style = w->RPort->Font->tf_Style;
3530 	textfont.ta_Flags = w->RPort->Font->tf_Flags;
3531 
3532 	boolgads = LayoutBoolOpts( w->Width - w->BorderLeft - w->BorderRight - 3,
3533 			w->Height - w->BorderTop - w->BorderBottom - 6,
3534 			w->RPort, &cury, &gadid );
3535 
3536 	if( boolgads )
3537 	{
3538 	    for( gp = boolgads; gp; gp = gp->next )
3539 	    {
3540 		gd = &gp->gad;
3541 		if( *boolopt[ gd->GadgetID - 1 ].addr != FALSE )
3542 		    gd->Flags |= SELECTED;
3543 		else
3544 		    gd->Flags &= ~SELECTED;
3545 		AddGList( w, gd, 0, 1, NULL );
3546 		RefreshGList( gd, w, NULL, 1 );
3547 		if( ( gd->Flags & SELECTED ) == 0 )
3548 		{
3549 		    SetAPen( rp, 0 );
3550 		    SetBPen( rp, 0 );
3551 		    SetDrMd( rp, JAM2 );
3552 		    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3553 				    gd->LeftEdge + gd->Width - 1,
3554 				    gd->TopEdge + gd->Height - 1 );
3555 		    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3556 		}
3557 		else
3558 		{
3559 		    SetAPen( rp, 3 );
3560 		    SetBPen( rp, 3 );
3561 		    SetDrMd( rp, JAM2 );
3562 		    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3563 				    gd->LeftEdge + gd->Width - 1,
3564 				    gd->TopEdge + gd->Height - 1 );
3565 		    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3566 		}
3567   	    }
3568 	}
3569 
3570 	/* Save the base gadget ID for composite/string gadgets */
3571 
3572 	compgadid = gadid;
3573 	compgads = LayoutCompOpts( w->Width - w->BorderLeft - w->BorderRight - 3,
3574 			w->Height - w->BorderTop - w->BorderBottom - 6, w->RPort,
3575 			&cury, &gadid );
3576 
3577 	if( compgads )
3578 	{
3579 	    for( gp = compgads; gp; gp = gp->next )
3580 		AddGList( w, &gp->gad, 0, 1, NULL );
3581 	}
3582 	SetUpMenus( &Options_MenuList3, scrn );
3583 	SetMenuStrip( w, &Options_MenuList3 );
3584 	WindowLimits( w, -1, cury + 2 + 20, -1, -1 );
3585 
3586 	/*
3587 	 * This will force us through the code in the NEWSIZE case below, but
3588 	 * since boolgads != NULL, we won't layout the gadgets again.
3589 	 */
3590 	SizeWindow( w, 0, ( cury + 5 + 20 ) - w->Height );
3591     }
3592 
3593     while( !done && w )
3594     {
3595 	WaitPort( w->UserPort );
3596 	while( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) )
3597 	{
3598 	    class = imsg->Class;
3599 	    code = imsg->Code;
3600 	    gd = (struct Gadget *)imsg->IAddress;
3601 	    if( class != SIZEVERIFY )
3602 		ReplyMsg( (struct Message *)imsg );
3603 	    if( class == MENUPICK )
3604 	    {
3605 		if( ITEMNUM( code ) == 0 )
3606 		    save = 1;
3607 		done = 1;
3608 	    }
3609 	    else if( class == MOUSEBUTTONS )
3610 	    {
3611 	    	if( code == SELECTUP && lastgad )
3612 	    	{
3613 		    gd = lastgad;
3614 		    if( ( gd->Flags & SELECTED ) == 0 )
3615 		    {
3616 			SetAPen( rp, 0 );
3617 			SetBPen( rp, 0 );
3618 			SetDrMd( rp, JAM2 );
3619 			RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3620 					gd->LeftEdge + gd->Width - 1,
3621 					gd->TopEdge + gd->Height - 1 );
3622 			PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3623 		    }
3624 		    else
3625 		    {
3626 			SetAPen( rp, 3 );
3627 			SetBPen( rp, 3 );
3628 			SetDrMd( rp, JAM2 );
3629 			RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3630 					gd->LeftEdge + gd->Width - 1,
3631 					gd->TopEdge + gd->Height - 1 );
3632 			PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3633 		    }
3634 		    lastgad = 0;
3635 	    	}
3636 	    }
3637 	    else if( class == GADGETUP )
3638 	    {
3639 	    	if( gd->GadgetID == GADOPTOKAY )
3640 	    	{
3641 		    save = 1;
3642 		    done = 1;
3643 	    	}
3644 	    	else if( gd->GadgetID == GADOPTCANCEL )
3645 	    	{
3646 		    done = 1;
3647 	    	}
3648 		else if( ( gd->Flags & SELECTED ) == 0 && gd->GadgetID < compgadid )
3649 		{
3650 		    SetAPen( rp, 0 );
3651 		    SetBPen( rp, 0 );
3652 		    SetDrMd( rp, JAM2 );
3653 		    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3654 				    gd->LeftEdge + gd->Width - 1,
3655 				    gd->TopEdge + gd->Height - 1 );
3656 		    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3657 		    lastgad = 0;
3658 		}
3659 	    }
3660 	    else if( class == GADGETDOWN )
3661 	    {
3662 		if( ( gd->Flags & SELECTED ) != 0 && gd->GadgetID < compgadid )
3663 		{
3664 		    SetAPen( rp, 3 );
3665 		    SetBPen( rp, 3 );
3666 		    SetDrMd( rp, JAM2 );
3667 		    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3668 				    gd->LeftEdge + gd->Width - 1,
3669 				    gd->TopEdge + gd->Height - 1 );
3670 		    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3671 		    lastgad = gd;
3672 		}
3673 	    }
3674 	    else if( class == CLOSEWINDOW )
3675 	    {
3676 		done = 1;
3677 	    }
3678 	    else if( class == SIZEVERIFY )
3679 	    {
3680 	    	/*
3681 	    	 * When the window is to be resized, we need to remove all of the gadgets
3682 	    	 * that are attached to get the gadget imagery from overwriting the
3683 	    	 * window borders.  In 2.04 and later we have RefreshWindowFrame(),
3684 	    	 * but still, this looks cleaner on the screen.
3685 	    	 */
3686 		for( gp = boolgads; gp; gp = gp->next )
3687 		{
3688 		    gd = &gp->gad;
3689 		    if( ( gd->Flags & SELECTED ) != 0 )
3690 			*boolopt[ gd->GadgetID - 1 ].addr = TRUE;
3691 		    else
3692 			*boolopt[ gd->GadgetID - 1 ].addr = FALSE;
3693 		    RemoveGList( w, gd, 1 );
3694 		}
3695 		FreeBoolOpts( boolgads );
3696 		/*
3697 		 * This tells the code in NEWSIZE below to layout the gadgets
3698 		 * again and reattach them to the window.
3699 		 */
3700 		boolgads = 0;
3701 		for( gp = compgads; gp; gp = gp->next )
3702 		    RemoveGList( w, &gp->gad, 1 );
3703 		FreeCompOpts( compgads );
3704 		ReplyMsg( (struct Message *)imsg );
3705 	    }
3706 	    else if( class == NEWSIZE )
3707 	    {
3708 		/* Save the last position information */
3709 		lastoptx = w->LeftEdge;
3710 		lastopty = w->TopEdge;
3711 		lastoptw = w->Width;
3712 		lastopth = w->Height;
3713 
3714 		/* If the gadgets are not currently bound, put them back. */
3715 		if( boolgads == NULL )
3716 		{
3717 		    cury = -1;
3718 		    gadid = 1;
3719 		    SetAPen( w->RPort, 0 );
3720 		    SetBPen( w->RPort, 0 );
3721 		    SetDrMd( w->RPort, JAM2 );
3722 		    RectFill( w->RPort, w->BorderLeft, w->BorderTop,
3723 					w->Width - w->BorderRight - 1,
3724 					w->Height - w->BorderBottom - 1 );
3725 		    SetAPen( w->RPort, 1 );
3726 		    SetBPen( w->RPort, 0 );
3727 		    boolgads = LayoutBoolOpts( w->Width - w->BorderLeft - w->BorderRight - 3,
3728 			w->Height - w->BorderTop - w->BorderBottom - 6, w->RPort,
3729 			    &cury, &gadid );
3730 		    for( gp = boolgads; gp; gp = gp->next )
3731 		    {
3732 			gd = &gp->gad;
3733 			AddGList( w, gd, 0, 1, NULL );
3734 			RefreshGList( gd, w, NULL, 1 );
3735 			if( ( gd->Flags & SELECTED ) == 0 )
3736 			{
3737 			    SetAPen( rp, 0 );
3738 			    SetBPen( rp, 0 );
3739 			    SetDrMd( rp, JAM2 );
3740 			    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3741 					    gd->LeftEdge + gd->Width - 1,
3742 					    gd->TopEdge + gd->Height - 1 );
3743 			    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3744 			}
3745 			else
3746 			{
3747 			    SetAPen( rp, 3 );
3748 			    SetBPen( rp, 3 );
3749 			    SetDrMd( rp, JAM2 );
3750 			    RectFill( rp, gd->LeftEdge + 1, gd->TopEdge + 1,
3751 					    gd->LeftEdge + gd->Width - 1,
3752 					    gd->TopEdge + gd->Height - 1 );
3753 			    PrintIText( rp, gd->GadgetText, gd->LeftEdge, gd->TopEdge );
3754 			}
3755 		    }
3756 		    compgadid = gadid;
3757 		    compgads = LayoutCompOpts( w->Width - w->BorderLeft - w->BorderRight - 3,
3758 			w->Height - w->BorderTop - w->BorderBottom - 6, w->RPort,
3759 			    &cury, &gadid );
3760 		    for( gp = compgads; gp; gp = gp->next )
3761 			AddGList( w, &gp->gad, 0, 1, NULL );
3762 		}
3763 		RefreshGList( w->FirstGadget, w, NULL, -1 );
3764 		WindowLimits( w, -1, cury + 2 + 20, -1, -1 );
3765 	    }
3766 	}
3767     }
3768 
3769     if( w )
3770     {
3771 	/* Make sure we get the latest position too */
3772 	lastoptx = w->LeftEdge;
3773 	lastopty = w->TopEdge;
3774 	lastoptw = w->Width;
3775 	lastopth = w->Height;
3776 
3777 	/* Close the window */
3778 	SafeCloseWindow( w );
3779     }
3780 
3781     /* Copy boolean gads settings into data table.
3782      * The compgads data is stored in the global compvals[]
3783      * string array, so we just leave the strings there
3784      * since options don't get added while we are running.
3785      */
3786     for( gp = boolgads; gp; gp = gp->next )
3787     {
3788 	gd = &gp->gad;
3789 	if( gd->Flags & SELECTED )
3790 	    *boolopt[ gd->GadgetID - 1 ].addr = TRUE;
3791 	else
3792 	    *boolopt[ gd->GadgetID - 1 ].addr = FALSE;
3793     }
3794 
3795     /* Free the gadgets */
3796     if( boolgads ) FreeBoolOpts( boolgads );
3797     if( compgads ) FreeCompOpts( compgads );
3798 
3799     return( save );
3800 }
3801 
3802 /*
3803  * Put options in boolopt[] and compvals[] into separate OPTIONS= tooltypes entries
3804  * in the GAME structure passed.
3805  */
3806 
3807 void PutOptions( gptr )
3808     register GPTR gptr;
3809 {
3810     char buf[ 200 ];
3811     extern char **compvals;
3812     int i;
3813 
3814     DelToolLines( gptr, "OPTIONS" );
3815     for( i = 0; boolopt[i].name; ++i )
3816     {
3817 	if( boolopt[i].addr == 0 )
3818 	    continue;
3819 	if( *boolopt[ i ].addr != boolopt[ i ].initvalue )
3820 	{
3821 	    sprintf( buf, "%s%s", *boolopt[i].addr ? "" : "!",
3822 				    boolopt[i].name );
3823 	    AddToolLine( gptr, "OPTIONS", buf );
3824 	}
3825     }
3826 
3827     for( i = 0; compvals && compvals[i]; ++i )
3828     {
3829 	/* If a value was provided, put the value into a tooltypes entry */
3830 	if( *compvals[ i ] )
3831 	{
3832 	    sprintf( buf, "%s:%s", compopt[i].name, compvals[i] );
3833 	    AddToolLine( gptr, "OPTIONS", buf );
3834 	}
3835     }
3836 }
3837 
3838 char *basename( str )
3839     char *str;
3840 {
3841     char *t;
3842 
3843     t = strrchr( str, '/' );
3844     if( !t )
3845 	t = strrchr( str, ':' );
3846     if( !t )
3847 	t = str;
3848     else
3849 	++t;
3850     return( t );
3851 }
3852 
3853 /* This OPTIONS=!xxx or OPTIONS=catname:toby string value is parsed, the correct
3854  * buffer area, boolopt[] or compvals[] is then updated to reflect the value
3855  * that was in the options string.
3856  */
3857 void ParseOptionStr( str )
3858     char *str;
3859 {
3860     char *s, *t, buf[ 100 ];
3861     int i, sidx, state = 0;
3862     int done = 0;
3863 
3864     s = buf;
3865     *buf = 0;
3866     sidx = -1;
3867 
3868     /* Start past the 'options=' part */
3869     for( t = str; *str && !done; ++t )
3870     {
3871 	if( state == 0 && isspace( *t ) )
3872 	    continue;
3873 
3874 	/* If at end remember so... */
3875 	if( !*t )
3876 	    done = 1;
3877 
3878 	/* If looking for an option value */
3879 	if( state == 0 )
3880 	{
3881 	    /* If found string value... */
3882 	    if( *t == ':' )
3883 	    {
3884 		*s = 0;
3885 		state = 1;
3886 		sidx = -1;
3887 
3888 		/* Look for the particular named option */
3889 		for( i = 0; compopt[i].name; ++i )
3890 		{
3891 		    if( stricmp( (char *)compopt[i].name, buf ) == 0 )
3892 		    {
3893 			sidx = i;
3894 			break;
3895 		    }
3896 		}
3897 
3898 		/* Set buffer pointer */
3899 		*(s = buf) = 0;
3900 
3901 		if( sidx == -1 )
3902 		{
3903 		    errmsg( FLASH, "Invalid string valued option name %s", buf );
3904 		    return;
3905 		}
3906 		continue;
3907 	    }
3908 	}
3909 
3910 	/* If at end of string or comma and we have some text... */
3911 	if( ( !*t || *t == ',' ) && *buf )
3912 	{
3913 	    /* Mark end */
3914 	    *s = 0;
3915 
3916 	    /* If have collected string option value... */
3917 	    if( sidx != -1 )
3918 	    {
3919 	    	if( compvals && compvals[ sidx ] != NULL )
3920 		    strcpy( compvals[ sidx ], buf );
3921 		sidx = -1;
3922 	    }
3923 	    else
3924 	    {
3925 		/* Look for boolean option */
3926 		s = buf;
3927 		if( *s == '!' )
3928 		    ++s;
3929 		for( i = 0; boolopt[ i ].name; ++i )
3930 		{
3931 		    if( stricmp( (char *)boolopt[ i ].name, s ) == 0 )
3932 			break;
3933 		}
3934 
3935 		if( boolopt[i].name && boolopt[i].addr )
3936 		{
3937 		    *boolopt[i].addr = *buf != '!';
3938 		}
3939 		else
3940 		{
3941 		    errmsg( FLASH, "Unrecognized option `%s'", buf );
3942 		    return;
3943 		}
3944 	    }
3945 	    *(s = buf) = 0;
3946 	    state = 0;
3947 	}
3948 	else
3949 	{
3950 	    if( *t == ',' )
3951 		*(s = buf) = 0;
3952 	    else
3953 		*s++ = *t;
3954 	}
3955     }
3956 }
3957