This is amiwind.c in view mode; [Download] [Up]
/* * amiwind.c (C) Copyright 1989 by Olaf Seibert (KosmoSoft) */ /* NetHack may be freely redistributed. See license for details. */ /* * Here is some very Amiga specific stuff, dealing with * screens, windows, menus, and input via IntuiMessages. */ #include "hack.h" #undef TRUE #undef FALSE #undef COUNT #undef NULL #include <exec/types.h> #include <exec/alerts.h> #include <exec/io.h> #include <exec/devices.h> #include <devices/console.h> #include <devices/conunit.h> #include <intuition/intuition.h> #include <libraries/dosextens.h> #ifdef LATTICE #include <dos.h> #include <proto/exec.h> #include <proto/graphics.h> #include <proto/intuition.h> #include <proto/diskfont.h> #include <proto/console.h> #endif #include "Amiga:amimenu.c" /* * Versions we need of various libraries. We can't use LIBRARY_VERSION * as defined in <exec/types.h> because some of the libraries we need * don't have that version number in the 1.2 ROM. */ #define INTUITION_VERSION 33L #define GRAPHICS_VERSION 33L #define DISKFONT_VERSION 34L #define ICON_VERSION 34L /* First, external declarations... */ extern struct Library *IconBase; struct Library *ConsoleDevice; #ifdef AZTEC_C void FDECL(Alert, (long, char *)); void NDECL(Forbid); void NDECL(Permit); struct Process *FDECL(FindTask, (char *)); struct Library *FDECL(OpenLibrary, (char *, long)); void FDECL(CloseLibrary, (struct Library *)); struct Message *FDECL(GetMsg, (struct MsgPort *)); void FDECL(ReplyMsg, (struct Message *)); long FDECL(OpenDevice, (char *, long, struct IORequest *, long)); void FDECL(CloseDevice, (struct IORequest *)); long FDECL(DoIO, (struct IORequest *)); struct TextFont *FDECL(OpenDiskFont, (struct TextAttr *)); struct TextFont *FDECL(OpenFont, (struct TextAttr *)); void FDECL(CloseFont, (struct TextFont *)); void FDECL(LoadRGB4, (struct ViewPort *, unsigned short *, long)); long FDECL(SetFont, (struct RastPort *, struct TextFont*)); struct MsgPort *FDECL(CreatePort, (char *, long)); void FDECL(DeletePort, (struct MsgPort *)); struct Screen *FDECL(OpenScreen, (struct NewScreen *)); struct Window *FDECL(OpenWindow, (struct NewWindow *)); void FDECL(CloseWindow, (struct Window *)); void FDECL(SetMenuStrip, (struct Window *, struct Menu *)); void FDECL(ClearMenuStrip, (struct Window *)); struct MenuItem *FDECL(ItemAddress, (struct Menu *, long)); long FDECL(RawKeyConvert, (struct InputEvent *, char *, long, struct KeyMap *)); #endif static int NDECL(BufferGetchar); static void FDECL(ConvertKey, (register struct IntuiMessage *)); static void FDECL(ProcessMessage, (register struct IntuiMessage *)); void NDECL(Initialize); /* Now our own variables */ struct Library *IntuitionBase; struct Screen *HackScreen; struct Window *HackWindow; struct Window *pr_WindowPtr; struct IOStdReq ConsoleIO; char Initialized = 0; #ifdef HACKFONT struct Library *GfxBase; struct Library *DiskfontBase; #endif extern struct Library *ConsoleDevice; #define CSI '\x9b' #define NO_CHAR -1 #define RAWHELP 0x5F /* Rawkey code of the HELP key */ /* * It is assumed that all multiple-character outputs are * at most CONBUFFER characters each. */ #define CONBUFFER 512 static char ConsoleBuffer[CONBUFFER]; static unsigned short Buffered; #define KBDBUFFER 10 static unsigned char KbdBuffer[KBDBUFFER]; static unsigned char KbdBuffered; #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = ch) /* * It seems Intuition won't OpenDiskFont our diskFont, so we get the * closest match, which is of course topaz/8. (and if not, it is still * an 8-pixel font, so everything still looks ok) */ #ifdef HACKFONT struct TextFont *HackFont; UBYTE FontName[] = "NetHack:hack.font"; #define SIZEOF_DISKNAME 8 #endif struct TextAttr Hack80 = { #ifdef HACKFONT &FontName[SIZEOF_DISKNAME], #else (UBYTE *) "topaz.font", #endif TOPAZ_EIGHTY, FS_NORMAL, FPF_DISKFONT | FPF_ROMFONT }; #define BARHEIGHT 11 #define WINDOWHEIGHT 192 #define WIDTH 640 #ifdef TEXTCOLOR #define DEPTH 3 static unsigned short palette[] = { 0x0000, /* Black */ 0x0DDD, /* White */ 0x0C75, /* Brown */ 0x0B08, /* Cyan */ 0x00B0, /* Green */ 0x0F08, /* Magenta */ 0x055F, /* Blue */ 0x0F00, /* Red */ }; #else #define DEPTH 2 #endif struct NewScreen NewHackScreen = { 0, 0, WIDTH, BARHEIGHT + WINDOWHEIGHT, DEPTH, 0, 1, /* DetailPen, BlockPen */ HIRES, CUSTOMSCREEN, &Hack80, /* Font */ (UBYTE *) " NetHack 3.0 - Ported by Olaf Seibert (KosmoSoft)", NULL, /* Gadgets */ NULL, /* CustomBitmap */ }; struct NewWindow NewHackWindow = { /* left, top, width, height, detailpen, blockpen */ 0, BARHEIGHT, WIDTH, WINDOWHEIGHT, -1, -1, RAWKEY | MENUPICK #ifdef MAIL | DISKINSERTED #endif , BORDERLESS | BACKDROP | ACTIVATE, NULL, NULL, NULL, NULL, NULL, -1,-1,-1,-1, CUSTOMSCREEN }; static int BufferGetchar() { register unsigned char *from, *to; register int c; register short i; if (KbdBuffered) { c = KbdBuffer[0]; KbdBuffered--; to = KbdBuffer; from = to + 1; /* Move the remaining characters */ for (i = KbdBuffered; i > 0; i--) { *to++ = *from++; } return c; } return NO_CHAR; } /* * This should remind you remotely of DeadKeyConvert, * but we are cheating a bit. * We want complete control over the numeric keypad, and no * dead keys... (they are assumed to be on Alted keys) * Also assumed is that the IntuiMessage is of type RAWKEY. * For some reason, IECODE_UP_PREFIX events seem to be lost when they * occur while our console window is inactive. This is particulary * troublesome with qualifier keys... Is this because I never * RawKeyConvert those events??? */ static void ConvertKey(message) register struct IntuiMessage *message; { static struct InputEvent theEvent; static char numpad[] = "bjnh.lyku"; static char ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15"; static char shift_numpad[] = "BJNH.LYKU"; unsigned char buffer[1]; register char length; register ULONG qualifier = message->Qualifier; char numeric_pad, shift, control, alt; control = (qualifier & IEQUALIFIER_CONTROL) != 0; shift = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0; alt = (qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT )) != 0; /* Allow ALT to function as a META key ... */ qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT); numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0; /* * Shortcut for HELP and arrow keys. I suppose this is allowed. * The defines are in intuition/intuition.h, and the keys don't * serve 'text' input, normally. Also, parsing their escape * sequences is such a mess... */ switch (message->Code) { case RAWHELP: length = '?'; goto no_arrow; case CURSORLEFT: length = 'h'; goto arrow; case CURSORDOWN: length = 'j'; goto arrow; case CURSORUP: length = 'k'; goto arrow; case CURSORRIGHT: length = 'l'; arrow: if (!flags.num_pad) /* Give digits if set, letters otherwise */ goto wasarrow; no_arrow: BufferQueueChar(length); return; } #ifdef BETA if (!ConsoleDevice) { /* Should never happen */ Abort(AG_IOError | AO_ConsoleDev); return; } #endif theEvent.ie_Class = IECLASS_RAWKEY; theEvent.ie_Code = message->Code; theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier; theEvent.ie_EventAddress = (APTR) *(message->IAddress); length = RawKeyConvert(&theEvent, buffer, (long) sizeof(buffer), NULL); if (length == 1) { /* Plain ASCII character */ length = buffer[0]; if (!flags.num_pad && numeric_pad && length >= '1' && length <= '9') { wasarrow: length -= '1'; if (control) { length = ctrl_numpad[length]; } else if (shift) { length = shift_numpad[length]; } else { length = numpad[length]; } } if (alt) length |= 0x80; BufferQueueChar(length); } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */ } /* * Process an incoming IntuiMessage. * It would certainly look nicer if this could be done using a * PA_SOFTINT message port, but we cannot call RawKeyConvert() * during a software interrupt. * Anyway, kbhit() is called often enough, and usually gets * ahead of input demands, when the user types ahead. */ static void ProcessMessage(message) register struct IntuiMessage *message; { switch(message->Class) { case MENUPICK: { USHORT thismenu; struct MenuItem *item = NULL; thismenu = message->Code; while (thismenu != MENUNULL) { item = ItemAddress(HackMenu, (ULONG) thismenu); if (KbdBuffered < KBDBUFFER) BufferQueueChar(item->Command); /* Unused: No COMMSEQ */ thismenu = item->NextSelect; } } break; case RAWKEY: if (!(message->Code & IECODE_UP_PREFIX)) ConvertKey(message); /* May queue multiple characters */ break; /* but doesn't do that yet */ #ifdef MAIL case DISKINSERTED: { extern int mustgetmail; if (mustgetmail < 0) mustgetmail = rn1(100,50); } #endif } ReplyMsg((struct Message *) message); } /* * Get all incoming messages and fill up the keyboard buffer, * thus allowing Intuition to (maybe) free up the IntuiMessages. * Return when no more messages left, or keyboard buffer half full. * We need to do this since there is no one-to-one correspondence * between characters and incoming messages. */ int kbhit() { register struct IntuiMessage *message; while( (KbdBuffered < KBDBUFFER / 2) && (message = (struct IntuiMessage *) GetMsg(HackWindow->UserPort)) ) ProcessMessage(message); return (int) KbdBuffered; } /* * Get a character from the keyboard buffer, waiting if * not available. */ int WindowGetchar() { while (!kbhit()) { WaitPort(HackWindow->UserPort); } return BufferGetchar(); } /* * Flush the output waiting in the console output buffer. */ void WindowFlush() { #ifdef BETA if (!ConsoleDevice) { /* Should never happen */ Abort(AG_IOError | AO_ConsoleDev); return; } #endif if (Buffered) { ConsoleIO.io_Command = CMD_WRITE; ConsoleIO.io_Data = (APTR)ConsoleBuffer; ConsoleIO.io_Length = Buffered; DoIO((struct IORequest *) &ConsoleIO); Buffered = 0; } } /* * Queue a single character for output to the console screen. */ void WindowPutchar(c) char c; { if (Buffered >= CONBUFFER) WindowFlush(); ConsoleBuffer[Buffered++] = c; } /* * Queue an entire string for output to the console screen, * flushing the existing characters first, if necessary. * Do not append a newline. */ void WindowFPuts(string) char *string; { register int len = strlen(string); if (len + Buffered >= CONBUFFER) WindowFlush(); strcpy(ConsoleBuffer + Buffered, string); Buffered += len; } /* * Queue an entire string for output to the console screen, * flushing the existing characters first, if necessary. * Append a newline. */ void WindowPuts(string) char *string; { WindowFPuts(string); WindowPutchar('\n'); } /* * Queue a formatted string for output to the console screen, * flushing the existing characters first, if necessary. */ /*VARARGS1*/ #if defined(USE_STDARG) || defined(USE_VARARGS) void WindowPrintf VA_DECL(char *, fmt) VA_START(fmt); VA_INIT(fmt, char *); WindowFlush(); /* Don't know if all will fit */ vsprintf(ConsoleBuffer, fmt, VA_ARGS); ConsoleIO.io_Command = CMD_WRITE; ConsoleIO.io_Data = (APTR)ConsoleBuffer; ConsoleIO.io_Length = -1; DoIO((struct IORequest *) &ConsoleIO); VA_END(); } #else void WindowPrintf(fmt, args, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) char *fmt; long args, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9; { # ifdef AZTEC_C /* Efficient but not portable */ format(WindowPutchar, fmt, &args); #else WindowFlush(); /* Don't know if all will fit */ sprintf(ConsoleBuffer, fmt, args, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); ConsoleIO.io_Command = CMD_WRITE; ConsoleIO.io_Data = (APTR)ConsoleBuffer; ConsoleIO.io_Length = -1; DoIO((struct IORequest *) &ConsoleIO); #endif } #endif /* * Clean up everything. But before we do, ask the user to hit return * when there is something that s/he should read. */ void CleanUp() { /* Clean up resources */ if (ConsoleIO.io_Device) { register struct ConUnit *cu; cu = (struct ConUnit *)ConsoleIO.io_Unit; if (cu->cu_XCCP != 1 || cu->cu_YCCP != 1) getret(); CloseDevice((struct IORequest *) &ConsoleIO); ConsoleDevice = NULL; } if (ConsoleIO.io_Message.mn_ReplyPort) DeletePort(ConsoleIO.io_Message.mn_ReplyPort); if (HackWindow) { register struct IntuiMessage *msg; ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr; ClearMenuStrip(HackWindow); Forbid(); while (msg = (struct IntuiMessage *) GetMsg(HackWindow->UserPort)) ReplyMsg((struct Message *) msg); CloseWindow(HackWindow); Permit(); HackWindow = NULL; } if (HackScreen) { CloseScreen(HackScreen); HackScreen = NULL; } if (IconBase) { CloseLibrary(IconBase); IconBase = NULL; } #ifdef HACKFONT if (HackFont) { CloseFont(HackFont); HackFont = NULL; } if (DiskfontBase) { CloseLibrary(DiskfontBase); DiskfontBase = NULL; } if (GfxBase) { CloseLibrary(GfxBase); GfxBase = NULL; } #endif if (IntuitionBase) { CloseLibrary(IntuitionBase); IntuitionBase = NULL; } Initialized = 0; } void Abort(rc) long rc; { #ifdef CHDIR extern char orgdir[]; chdir(orgdir); #endif if (Initialized && ConsoleDevice) { printf("\n\nAbort with alert code %08lx...\n", rc); getret(); } else Alert(rc, 0L); #ifdef LATTICE { /* __emit(0x4afc); /* illegal instruction */ __emit(0x40fc); /* divide by */ __emit(0x0000); /* #0 */ /* NOTE: don't move CleanUp() above here - */ /* it is too likely to kill the system */ /* before it can get the SnapShot out, if */ /* there is something really wrong. */ __builtin_printf("abort botch"); /* (KL)TEMP */ } #endif CleanUp(); #undef exit #ifdef AZTEC_C _abort(); #endif exit((int) rc); } /* * Open everything we need. */ void Initialize() { if (Initialized) return; if ( (IntuitionBase = OpenLibrary("intuition.library", INTUITION_VERSION)) == NULL) Abort(AG_OpenLib | AO_Intuition); #ifdef HACKFONT if ( (GfxBase = OpenLibrary("graphics.library", GRAPHICS_VERSION)) == NULL) Abort(AG_OpenLib | AO_GraphicsLib); /* * Force our own font to be loaded, if possible. * If we can open diskfont.library, but not our font, we can close * the diskfont.library again since it just wastes memory. * Even if we can open the font, we don't need the diskfont.library * anymore, since CloseFont is a graphics.library function. */ if ((HackFont = OpenFont(&Hack80)) == NULL) { if (DiskfontBase = OpenLibrary("diskfont.library", DISKFONT_VERSION)) { Hack80.ta_Name -= SIZEOF_DISKNAME; HackFont = OpenDiskFont(&Hack80); Hack80.ta_Name += SIZEOF_DISKNAME; CloseLibrary(DiskfontBase); DiskfontBase = NULL; } } #endif /* if ( (IconBase = OpenLibrary("icon.library", ICON_VERSION)) == NULL) Abort(AG_OpenLib | AO_IconLib); */ /* * Now Intuition is supposed to use our HackFont for the screen, * since we have a corresponding TextAttr, but it *doesn't*. * So, we need to do a SetFont() a bit later on. */ if ( (HackScreen = OpenScreen(&NewHackScreen)) == NULL) Abort(AN_OpenScreen & ~AT_DeadEnd); #ifdef TEXTCOLOR LoadRGB4(&HackScreen->ViewPort, palette, 8L); #endif NewHackWindow.Screen = HackScreen; if ( (HackWindow = OpenWindow(&NewHackWindow)) == NULL) Abort(AN_OpenWindow & ~AT_DeadEnd); SetMenuStrip(HackWindow, HackMenu); { register struct Process *myProcess = (struct Process *) FindTask(NULL); pr_WindowPtr = (struct Window *)myProcess->pr_WindowPtr; myProcess->pr_WindowPtr = (APTR) HackWindow; } #ifdef HACKFONT if (HackFont) SetFont(HackWindow->RPort, HackFont); #endif ConsoleIO.io_Data = (APTR) HackWindow; ConsoleIO.io_Length = sizeof(*HackWindow); ConsoleIO.io_Message.mn_ReplyPort = CreatePort(NULL, 0L); if (OpenDevice("console.device", 0L, (struct IORequest *) &ConsoleIO, 0L) != 0) Abort(AG_OpenDev | AO_ConsoleDev); ConsoleDevice = (struct Library *) ConsoleIO.io_Device; Buffered = 0; KbdBuffered = 0; /* set CRMOD on */ WindowFPuts("\23320h"); Initialized = 1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.