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 
OpenShWindow(nw)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 *));
CloseShWindow(win)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 
BufferGetchar()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 
ConvertKey(message)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 
ProcessMessage(message)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)
kbhit()539 int kbhit(){
540 	return 0;
541 }
542 #else
543 int
kbhit()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
amikbhit()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 
WindowGetchar()589 int WindowGetchar( )
590 {
591     while ((lastevent.type = WEUNK), amikbhit() <= 0) {
592 	WaitPort(HackPort);
593     }
594     return BufferGetchar();
595 }
596 
WindowGetevent()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 
amii_cleanup()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
Abort(rc)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
CleanUp()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 *
GetFMsg(port)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 *
DupNewWindow(win)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
FreeNewWindow(win)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
bell()905 bell()
906 {
907     if (flags.silent) return;
908     DisplayBeep(NULL);
909 }
910 
911 void
amii_delay_output()912 amii_delay_output()
913 {
914     /* delay 50 ms */
915     Delay(2L);
916 }
917 
918 void
amii_number_pad(state)919 amii_number_pad(state)
920 int state;
921 {
922 }
923 #endif  /* AMII_GRAPHICS */
924 
925 #ifndef	SHAREDLIB
926 void
amiv_loadlib(void)927 amiv_loadlib( void )
928 {
929 }
930 
931 void
amii_loadlib(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
950