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