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