OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / sys / amiga / amiwind.c
1 /*    SCCS Id: @(#)amiwind.c     3.2    2000/01/12
2 /*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992          */
3 /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996  */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 #include "NH:sys/amiga/windefs.h"
7 #include "NH:sys/amiga/winext.h"
8 #include "NH:sys/amiga/winproto.h"
9
10 /* Have to undef CLOSE as display.h and intuition.h both use it */
11 #undef CLOSE
12
13 #ifdef AMII_GRAPHICS    /* too early in the file? too late? */
14
15 #ifdef AMIFLUSH
16 static struct Message *FDECL(GetFMsg,(struct MsgPort *));
17 #endif
18
19 static int BufferGetchar(void);
20 static void ProcessMessage( register struct IntuiMessage *message );
21
22 #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
23
24 struct Library *ConsoleDevice;
25
26 #include "NH:sys/amiga/amimenu.c"
27
28 /* Now our own variables */
29
30 struct IntuitionBase *IntuitionBase;
31 struct Screen *HackScreen;
32 struct Window *pr_WindowPtr;
33 struct MsgPort *HackPort;
34 struct IOStdReq ConsoleIO;
35 struct Menu *MenuStrip;
36 APTR *VisualInfo;
37 char Initialized = 0;
38 WEVENT lastevent;
39
40 #ifdef HACKFONT
41 struct GfxBase *GfxBase;
42 struct Library *DiskfontBase;
43 #endif
44
45 #define KBDBUFFER   10
46 static unsigned char KbdBuffer[KBDBUFFER];
47 unsigned char KbdBuffered;
48
49 #ifdef HACKFONT
50
51 struct TextFont *TextsFont = NULL;
52 struct TextFont *HackFont = NULL;
53 struct TextFont *RogueFont = NULL;
54
55 UBYTE FontName[] = "NetHack:hack.font";
56     /* # chars in "NetHack:": */
57 #define         SIZEOF_DISKNAME 8
58
59 #endif
60
61 struct TextAttr Hack80 = {
62 #ifdef HACKFONT
63     &FontName[SIZEOF_DISKNAME],
64 #else
65     (UBYTE *) "topaz.font",
66 #endif
67     8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
68         | FPF_ROMFONT
69 };
70
71 struct TextAttr TextsFont13 = {
72     (UBYTE *) "courier.font",
73     13, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
74 #ifndef HACKFONT
75         | FPF_ROMFONT
76 #endif
77 };
78
79 /* Avoid doing a ReplyMsg through a window that no longer exists. */
80 static enum {NoAction, CloseOver} delayed_key_action = NoAction;
81
82 /*
83  * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
84  * to close.
85  */
86
87 struct Window *OpenShWindow(nw)
88 struct NewWindow *nw;
89 {
90     register struct Window *win;
91     register ULONG idcmpflags;
92
93     if (!HackPort)  /* Sanity check */
94         return (struct Window *) 0;
95
96     idcmpflags = nw->IDCMPFlags;
97     nw->IDCMPFlags = 0;
98     if (!(win = OpenWindow((void *)nw)))
99     {
100         nw->IDCMPFlags = idcmpflags;
101         return (struct Window *) 0;
102     }
103
104     nw->IDCMPFlags = idcmpflags;
105     win->UserPort = HackPort;
106     ModifyIDCMP(win, idcmpflags);
107     return win;
108 }
109
110
111 /*
112  * Close a window that shared the HackPort IDCMP port.
113  */
114
115 void FDECL(CloseShWindow, (struct Window *));
116 void CloseShWindow(win)
117 struct Window *win;
118 {
119     register struct IntuiMessage *msg;
120
121     if( !HackPort )
122         panic("HackPort NULL in CloseShWindow" );
123     if (!win)
124         return;
125
126     Forbid();
127     /* Flush all messages for all windows to avoid typeahead and other
128      * similar problems...
129      */
130     while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
131         ReplyMsg( (struct Message *) msg );
132     KbdBuffered = 0;
133     win->UserPort = (struct MsgPort *) 0;
134     ModifyIDCMP(win, 0L);
135     Permit();
136     CloseWindow(win);
137 }
138
139 static int BufferGetchar()
140 {
141     register int c;
142
143     if (KbdBuffered > 0) {
144         c = KbdBuffer[0];
145         KbdBuffered--;
146         /* Move the remaining characters */
147         if( KbdBuffered < sizeof( KbdBuffer ) )
148             memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
149         return c;
150     }
151
152     return NO_CHAR;
153 }
154
155 /*
156  *  This should remind you remotely of DeadKeyConvert, but we are cheating
157  *  a bit. We want complete control over the numeric keypad, and no dead
158  *  keys... (they are assumed to be on Alted keys).
159  *
160  *  Also assumed is that the IntuiMessage is of type RAWKEY.  For some
161  *  reason, IECODE_UP_PREFIX events seem to be lost when they  occur while
162  *  our console window is inactive. This is particulary  troublesome with
163  *  qualifier keys... Is this because I never RawKeyConvert those events???
164  */
165
166 int ConvertKey(message)
167 register struct IntuiMessage *message;
168 {
169     static struct InputEvent theEvent;
170     static char       numpad[] = "bjnh.lyku";
171     static char  ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
172     static char shift_numpad[] = "BJNH.LYKU";
173
174     unsigned char buffer[10];
175     struct Window *w = message->IDCMPWindow;
176     register int length;
177     register ULONG qualifier;
178     char numeric_pad, shift, control, alt;
179
180     if( amii_wins[ WIN_MAP ] )
181         w = amii_wins[ WIN_MAP ]->win;
182     qualifier = message->Qualifier;
183
184     control = (qualifier &  IEQUALIFIER_CONTROL) != 0;
185     shift   = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
186     alt     = (qualifier & (IEQUALIFIER_LALT   | IEQUALIFIER_RALT  )) != 0;
187
188     /* Allow ALT to function as a META key ... */
189     /* But make it switchable - alt is needed for some non-US keymaps */
190     if(flags.altmeta)
191         qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
192     numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
193
194     /*
195      *  Shortcut for HELP and arrow keys. I suppose this is allowed.
196      *  The defines are in intuition/intuition.h, and the keys don't
197      *  serve 'text' input, normally. Also, parsing their escape
198      *  sequences is such a mess...
199      */
200
201     switch (message->Code) {
202         case RAWHELP:
203             if( alt )
204             {
205                 EditColor();
206                 return( -1 );
207             }
208 #ifdef  CLIPPING
209             else if( WINVERS_AMIV && control )
210             {
211                 EditClipping();
212
213                 CO = ( w->Width - w->BorderLeft - w->BorderRight  ) / mxsize;
214                 LI = ( w->Height - w->BorderTop - w->BorderBottom ) / mysize;
215                 clipxmax = CO + clipx;
216                 clipymax = LI + clipy;
217                 if( CO < COLNO || LI < ROWNO )
218                 {
219                     clipping = TRUE;
220                     amii_cliparound( u.ux, u.uy );
221                 }
222                 else
223                 {
224                     clipping = FALSE;
225                     clipx = clipy = 0;
226                 }
227                 BufferQueueChar( 'R'-64 );
228                 return(-1);
229             }
230 #endif
231             else if( WINVERS_AMIV && shift )
232             {
233                 if( WIN_OVER == WIN_ERR )
234                 {
235                     WIN_OVER = amii_create_nhwindow( NHW_OVER );
236                     BufferQueueChar( 'R'-64 );
237                 }
238                 else
239                 {
240                     delayed_key_action = CloseOver;
241                 }
242                 return( -1 );
243             }
244             return( '?' );
245             break;
246         case CURSORLEFT:
247             length = '4';
248             numeric_pad = 1;
249             goto arrow;
250         case CURSORDOWN:
251             length = '2';
252             numeric_pad = 1;
253             goto arrow;
254         case CURSORUP:
255             length = '8';
256             numeric_pad = 1;
257             goto arrow;
258         case CURSORRIGHT:
259             length = '6';
260             numeric_pad = 1;
261             goto arrow;
262     }
263
264     theEvent.ie_Class = IECLASS_RAWKEY;
265     theEvent.ie_Code = message->Code;
266     theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
267     theEvent.ie_EventAddress = (APTR) (message->IAddress);
268
269     length = RawKeyConvert(&theEvent, (char *)buffer, 
270       (long) sizeof(buffer), NULL);
271
272     if (length == 1) {   /* Plain ASCII character */
273         length = buffer[0];
274         /*
275          *  If iflags.num_pad is set, movement is by 4286.
276          *  If not set, translate 4286 into hjkl.
277          *  This way, the numeric pad can /always/ be used
278          *  for moving, though best results are when it is off.
279          */
280 arrow:
281         if (!iflags.num_pad && numeric_pad && length >= '1' && length <= '9') {
282             length -= '1';
283             if (control) {
284                 length = ctrl_numpad[length];
285             } else if (shift) {
286                 length = shift_numpad[length];
287             } else {
288                 length = numpad[length];
289             }
290         }
291
292         /* Kludge to allow altmeta on eg. scandinavian keymap (# == shift+alt+3)
293            and prevent it from interfering with # command (M-#) */
294         if (length == ('#'|0x80))
295             return '#';
296         if (alt && flags.altmeta)
297             length |= 0x80;
298         return(length);
299     } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
300     else if( length > 1 )
301     {
302         int i;
303
304         if( length == 3 && buffer[ 0 ] == 155 && buffer[ 2 ] == 126 )
305         {
306             int got = 1;
307             switch( buffer[ 1 ] )
308             {
309                 case 53: mxsize = mysize = 8; break;
310                 case 54: mxsize = mysize = 16; break;
311                 case 55: mxsize = mysize = 24; break;
312                 case 56: mxsize = mysize = 32; break;
313                 case 57: mxsize = mysize = 48; break;
314                 default: got = 0; break;
315             }
316 #ifdef OPT_DISPMAP
317             dispmap_sanity();
318 #endif
319
320             if( got )
321             {
322                 CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
323                 LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
324                 clipxmax = CO + clipx;
325                 clipymax = LI + clipy;
326                 if( CO < COLNO || LI < ROWNO )
327                 {
328                     amii_cliparound( u.ux, u.uy );
329                 }
330                 else
331                 {
332                         CO = COLNO;
333                         LI = ROWNO;
334                 }
335                 reclip = 1;
336                 doredraw();
337                 flush_screen( 1 );
338                 reclip = 0;
339                 /*BufferQueueChar( 'R'-64 );*/
340                 return( -1 );
341             }
342         }
343         printf( "Unrecognized key: %d ", (int)buffer[0]);
344         for( i = 1; i < length; ++i )
345             printf( "%d ", (int)buffer[i]);
346         printf( "\n" );
347     }
348     return( -1 );
349 }
350
351 /*
352  *  Process an incoming IntuiMessage.
353  *  It would certainly look nicer if this could be done using a
354  *  PA_SOFTINT message port, but we cannot call RawKeyConvert()
355  *  during a software interrupt.
356  *  Anyway, amikbhit()/kbhit() is called often enough, and usually gets
357  *  ahead of input demands, when the user types ahead.
358  */
359
360 static void ProcessMessage(message)
361 register struct IntuiMessage *message;
362 {
363     int c;
364     int cnt;
365     menu_item *mip;
366     static int skip_mouse=0;    /* need to ignore next mouse event on
367                                  * a window activation */
368     struct Window *w = message->IDCMPWindow;
369
370     switch(message->Class) {
371     case ACTIVEWINDOW:
372         if( alwaysinvent && WIN_INVEN != WIN_ERR &&
373                             w == amii_wins[ WIN_INVEN ]->win )
374         {
375             cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip );
376         }
377         else if( scrollmsg && WIN_MESSAGE != WIN_ERR &&
378                             w == amii_wins[ WIN_MESSAGE ]->win )
379         {
380             cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
381         }
382         else
383         {
384             skip_mouse=1;
385         }
386         break;
387
388     case MOUSEBUTTONS:
389         {
390             if( skip_mouse )
391             {
392                 skip_mouse=0;
393                 break;
394             }
395
396             if( !amii_wins[ WIN_MAP ] || w != amii_wins[ WIN_MAP ]->win )
397                 break;
398
399             if( message->Code == SELECTDOWN )
400             {
401                 lastevent.type = WEMOUSE;
402                 lastevent.un.mouse.x = message->MouseX;
403                 lastevent.un.mouse.y = message->MouseY;
404                     /* With shift equals RUN */
405                 lastevent.un.mouse.qual = (message->Qualifier &
406                   (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
407             }
408         }
409         break;
410
411     case MENUPICK:
412         {
413             USHORT thismenu;
414             struct MenuItem *item;
415
416             thismenu = message->Code;
417             while (thismenu != MENUNULL)
418             {
419                 item = ItemAddress(MenuStrip, (ULONG) thismenu);
420                 if (KbdBuffered < KBDBUFFER)
421                     BufferQueueChar((char)(GTMENUITEM_USERDATA(item)));
422                 thismenu = item->NextSelect;
423             }
424         }
425         break;
426
427     case REFRESHWINDOW:
428         {
429             if( scrollmsg
430                 && amii_wins[ WIN_MESSAGE ]
431                 && w == amii_wins[ WIN_MESSAGE ]->win
432             ){
433                 cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
434             }
435         }
436         break;
437
438     case CLOSEWINDOW:
439         if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
440         {
441             dismiss_nhwindow( WIN_INVEN );
442         }
443         if( WINVERS_AMIV
444             && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win )
445         ){
446             destroy_nhwindow( WIN_OVER );
447             WIN_OVER = WIN_ERR;
448         }
449         break;
450
451     case RAWKEY:
452         if (!(message->Code & IECODE_UP_PREFIX)){
453             /* May queue multiple characters
454              * but doesn't do that yet...
455              */
456             if( ( c = ConvertKey(message) ) > 0 )
457                 BufferQueueChar( c );
458         }
459         break;
460
461     case GADGETDOWN:
462         if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win )
463         {
464             cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip );
465         }
466         else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
467         {
468             cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip );
469         }
470         break;
471
472     case NEWSIZE:
473         if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win )
474         {
475             if( WINVERS_AMIV )
476             {
477                 /* Make sure that new size is honored for good. */
478                 SetAPen( w->RPort, amii_msgBPen );
479                 SetBPen( w->RPort, amii_msgBPen );
480                 SetDrMd( w->RPort, JAM2 );
481                 RectFill( w->RPort, w->BorderLeft, w->BorderTop,
482                   w->Width - w->BorderRight-1,
483                   w->Height - w->BorderBottom-1 );
484             }
485             ReDisplayData( WIN_MESSAGE );
486         }
487         else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win )
488         {
489             ReDisplayData( WIN_INVEN );
490         }
491         else if( WINVERS_AMIV
492                  && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win )
493         ){
494             BufferQueueChar( 'R'-64 );
495         }
496         else if( WIN_MAP != WIN_ERR && w == amii_wins[ WIN_MAP ]->win )
497         {
498 #ifdef  CLIPPING
499             CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize;
500             LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize;
501             clipxmax = CO + clipx;
502             clipymax = LI + clipy;
503             if( CO < COLNO || LI < ROWNO )
504             {
505                 amii_cliparound( u.ux, u.uy );
506             }
507             else
508             {
509                 clipping = FALSE;
510                 clipx = clipy = 0;
511             }
512             BufferQueueChar( 'R'-64 );
513 #endif
514         }
515         break;
516     }
517     ReplyMsg((struct Message *) message);
518
519     switch(delayed_key_action){
520     case CloseOver:
521         amii_destroy_nhwindow( WIN_OVER );
522         WIN_OVER = WIN_ERR;
523         delayed_key_action = NoAction;
524     case NoAction:
525         ;       /* null */
526     }
527 }
528
529 #endif /* AMII_GRAPHICS */
530 /*
531  *  Get all incoming messages and fill up the keyboard buffer,
532  *  thus allowing Intuition to (maybe) free up the IntuiMessages.
533  *  Return when no more messages left, or keyboard buffer half full.
534  *  We need to do this since there is no one-to-one correspondence
535  *  between characters and incoming messages.
536  */
537
538 #if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS)
539 int kbhit(){
540         return 0;
541 }
542 #else
543 int
544 kbhit()
545 {
546     int c;
547 # ifdef TTY_GRAPHICS
548                 /* a kludge to defuse the mess in allmain.c */
549                 /* I hope this is the right approach */
550     if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)return 0;
551 # endif
552     c = amikbhit();
553     if( c <= 0 )
554         return( 0 );
555     return( c );
556 }
557 #endif
558
559 #ifdef AMII_GRAPHICS
560
561 int
562 amikbhit()
563 {
564     register struct IntuiMessage *message;
565     while( KbdBuffered < KBDBUFFER / 2 )
566     {
567 #ifdef AMIFLUSH
568         message = (struct IntuiMessage *) GetFMsg(HackPort);
569 #else
570         message = (struct IntuiMessage *) GetMsg(HackPort);
571 #endif
572         if(message)
573         {
574             ProcessMessage(message);
575             if( lastevent.type != WEUNK && lastevent.type != WEKEY )
576                 break;
577         }
578         else
579             break;
580     }
581     return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
582 }
583
584 /*
585  *  Get a character from the keyboard buffer, waiting if not available.
586  *  Ignore other kinds of events that happen in the mean time.
587  */
588
589 int WindowGetchar( )
590 {
591     while ((lastevent.type = WEUNK), amikbhit() <= 0) {
592         WaitPort(HackPort);
593     }
594     return BufferGetchar();
595 }
596
597 WETYPE WindowGetevent()
598 {
599     lastevent.type = WEUNK;
600     while (amikbhit() == 0)
601     {
602         WaitPort(HackPort);
603     }
604
605     if( KbdBuffered )
606     {
607         lastevent.type = WEKEY;
608         lastevent.un.key = BufferGetchar();
609     }
610     return( lastevent.type );
611 }
612
613 /*
614  *  Clean up everything. But before we do, ask the user to hit return
615  *  when there is something that s/he should read.
616  */
617
618 void amii_cleanup()
619 {
620     register struct IntuiMessage *msg;
621
622     /* Close things up */
623     if( HackPort )
624     {
625         amii_raw_print("");
626         amii_getret();
627     }
628
629     if (ConsoleIO.io_Device)
630         CloseDevice( (struct IORequest *)&ConsoleIO );
631     ConsoleIO.io_Device = 0;
632
633     if( ConsoleIO.io_Message.mn_ReplyPort )
634         DeleteMsgPort( ConsoleIO.io_Message.mn_ReplyPort );
635     ConsoleIO.io_Message.mn_ReplyPort = 0;
636
637     /* Strip messages before deleting the port */
638     if( HackPort )
639     {
640         Forbid();
641         while (msg = (struct IntuiMessage *) GetMsg(HackPort))
642             ReplyMsg((struct Message *) msg);
643         kill_nhwindows( 1 );
644         DeleteMsgPort( HackPort );
645         HackPort = NULL;
646         Permit();
647     }
648
649     /* Close the screen, under v37 or greater it is a pub screen and there may
650      * be visitors, so check close status and wait till everyone is gone.
651      */
652     if( HackScreen )
653     {
654 #ifdef  INTUI_NEW_LOOK
655         if( IntuitionBase->LibNode.lib_Version >= 37 )
656         {
657             if (MenuStrip) FreeMenus(MenuStrip);
658             if (VisualInfo) FreeVisualInfo(VisualInfo);
659             while( CloseScreen( HackScreen ) == FALSE )
660             {
661                 struct EasyStruct easy =
662                 {
663                     sizeof( struct EasyStruct ),
664                     0,
665                     "Nethack Problem",
666                     "Can't Close Screen, Close Visiting Windows",
667                     "Okay"
668                 };
669                 EasyRequest( NULL, &easy, NULL, NULL );
670             }
671         }
672         else
673 #endif
674         {
675             CloseScreen(HackScreen);
676         }
677         HackScreen = NULL;
678     }
679
680 #ifdef HACKFONT
681     if (HackFont)
682     {
683         CloseFont(HackFont);
684         HackFont = NULL;
685     }
686
687     if( TextsFont )
688     {
689         CloseFont( TextsFont );
690         TextsFont = NULL;
691     }
692
693     if( RogueFont )
694     {
695         CloseFont( RogueFont );
696         RogueFont = NULL;
697     }
698
699     if( DiskfontBase )
700     {
701         CloseLibrary(DiskfontBase);
702         DiskfontBase = NULL;
703     }
704 #endif
705
706     if (GadToolsBase) {
707         CloseLibrary((struct Library *)GadToolsBase);
708         GadToolsBase=NULL;
709     }
710
711     if (LayersBase) {
712         CloseLibrary((struct Library *)LayersBase);
713         LayersBase = NULL;
714     }
715
716     if (GfxBase) {
717         CloseLibrary((struct Library *)GfxBase);
718         GfxBase = NULL;
719     }
720
721     if (IntuitionBase) {
722         CloseLibrary((struct Library *)IntuitionBase);
723         IntuitionBase = NULL;
724     }
725
726 #ifdef  SHAREDLIB
727     if (DOSBase) {
728         CloseLibrary((struct Library *)DOSBase);
729         DOSBase = NULL;
730     }
731 #endif
732
733     ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
734
735     Initialized = 0;
736 }
737
738 #endif  /* AMII_GRAPHICS */
739
740 #ifndef SHAREDLIB
741 void Abort(rc)
742 long rc;
743 {
744     int fault = 1;
745 #ifdef CHDIR
746     extern char orgdir[];
747     chdir(orgdir);
748 #endif
749 #ifdef AMII_GRAPHICS
750     if (Initialized
751       && ConsoleDevice
752       && windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) {
753       printf("\n\nAbort with alert code %08lx...\n", rc);
754       amii_getret();
755     } else
756 #endif
757       printf("\n\nAbort with alert code %08lx...\n",rc);
758       /* Alert(rc);              this is too severe */
759 #ifdef __SASC
760 # ifdef INTUI_NEW_LOOK
761     if( IntuitionBase->LibNode.lib_Version >= 37 )
762     {
763         struct EasyStruct es =
764         {
765                 sizeof( struct EasyStruct ),
766                 0,
767                 "NetHack Panic Request",
768                 "NetHack is Aborting with code == 0x%08lx",
769                 "Continue Abort|Return to Program|Clean up and exit",
770         };
771         fault = EasyRequest( NULL, &es, NULL, (long)rc );
772         if( fault == 2 )
773             return;
774     }
775 # endif
776     if( fault == 1 )
777     {
778 /*  __emit(0x4afc); */    /* illegal instruction */
779     __emit(0x40fc);     /* divide by */
780     __emit(0x0000);     /*  #0  */
781       /* NOTE: don't move amii_cleanup() above here - */
782       /* it is too likely to kill the system     */
783       /* before it can get the SnapShot out, if  */
784       /* there is something really wrong.    */
785     }
786 #endif
787 #ifdef AMII_GRAPHICS
788     if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)
789       amii_cleanup();
790 #endif
791 #undef exit
792 #ifdef AZTEC_C
793     _abort();
794 #endif
795     exit((int) rc);
796 }
797
798 void
799 CleanUp()
800 {
801         amii_cleanup();
802 }
803 #endif
804
805 #ifdef AMII_GRAPHICS
806
807 #ifdef AMIFLUSH
808 /* This routine adapted from AmigaMail IV-37 by Michael Sinz */
809 static struct Message *
810 GetFMsg(port)
811     struct MsgPort *port;
812     {
813     struct IntuiMessage *msg,*succ,*succ1;
814
815     if(msg=(struct IntuiMessage *)GetMsg(port)){
816         if(!flags.amiflush)return((struct Message *)msg);
817         if(msg->Class==RAWKEY){
818             Forbid();
819             succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
820             while(succ1=(struct IntuiMessage *)
821               (succ->ExecMessage.mn_Node.ln_Succ)){
822                 if(succ->Class==RAWKEY){
823                     Remove((struct Node *)succ);
824                     ReplyMsg((struct Message *)succ);
825                 }
826                 succ=succ1;
827             }
828             Permit();
829         }
830     }
831     return((struct Message *)msg);
832 }
833 #endif
834
835 struct NewWindow *
836 DupNewWindow( win )
837     struct NewWindow *win;
838 {
839     struct NewWindow *nwin;
840     struct Gadget *ngd, *gd, *pgd = NULL;
841     struct PropInfo *pip;
842     struct StringInfo *sip;
843
844     /* Copy the (Ext)NewWindow structure */
845
846     nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
847     *nwin = *win;
848
849     /* Now do the gadget list */
850
851     nwin->FirstGadget = NULL;
852     for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
853     {
854         ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
855         *ngd = *gd;
856         if( gd->GadgetType == STRGADGET )
857         {
858             sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
859             *sip = *((struct StringInfo *)gd->SpecialInfo);
860             sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
861             *sip->Buffer = 0;
862             ngd->SpecialInfo = (APTR)sip;
863         }
864         else if( gd->GadgetType == PROPGADGET )
865         {
866             pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
867             *pip = *((struct PropInfo *)gd->SpecialInfo);
868             ngd->SpecialInfo = (APTR)pip;
869         }
870         if( pgd )
871             pgd->NextGadget = ngd;
872         else
873             nwin->FirstGadget = ngd;
874         pgd = ngd;
875         ngd->NextGadget = NULL;
876         ngd->UserData = (APTR) 0x45f35c3d;  // magic cookie for FreeNewWindow()
877     }
878     return( nwin );
879 }
880
881 void
882 FreeNewWindow( win )
883     struct NewWindow *win;
884 {
885     register struct Gadget *gd, *pgd;
886     register struct StringInfo *sip;
887
888     for( gd = win->FirstGadget; gd; gd = pgd ) {
889         pgd = gd->NextGadget;
890         if ((ULONG)gd->UserData == 0x45f35c3d) {
891             if( gd->GadgetType == STRGADGET ) {
892                 sip = (struct StringInfo *)gd->SpecialInfo;
893                 free( sip->Buffer );
894                 free( sip );
895             } else if( gd->GadgetType == PROPGADGET ) {
896                 free( (struct PropInfo *)gd->SpecialInfo );
897             }
898             free( gd );
899         }
900     }
901     free( win );
902 }
903
904 void
905 bell()
906 {
907     if (flags.silent) return;
908     DisplayBeep(NULL);
909 }
910
911 void
912 amii_delay_output()
913 {
914     /* delay 50 ms */
915     Delay(2L);
916 }
917
918 void
919 amii_number_pad(state)
920 int state;
921 {
922 }
923 #endif  /* AMII_GRAPHICS */
924
925 #ifndef SHAREDLIB
926 void
927 amiv_loadlib( void )
928 {
929 }
930
931 void
932 amii_loadlib( void )
933 {
934 }
935
936 /* fatal error */
937 /*VARARGS1*/
938 void error VA_DECL(const char *, s)
939     VA_START(s);
940     VA_INIT(s, char *);
941
942     putchar('\n');
943     vprintf(s, VA_ARGS);
944     putchar('\n');
945
946     VA_END();
947     Abort(0L);
948 }
949 #endif