/* NetHack 3.6 winfuncs.c $NHDT-Date: 1553895320 2019/03/29 21:35:20 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #else #include "windefs.h" #include "winext.h" #include "winproto.h" #endif #include "patchlevel.h" extern struct TagItem scrntags[]; #ifndef CROSS_TO_AMIGA extern struct Library *ConsoleDevice; #else extern struct Device * # ifdef __CONSTLIBBASEDECL__ __CONSTLIBBASEDECL__ # endif /* __CONSTLIBBASEDECL__ */ ConsoleDevice; #endif static BitMapHeader amii_bmhd; static void cursor_common(struct RastPort *, int, int); #ifdef CLIPPING int CO, LI; /* Changing clipping region, skip clear of screen in overview window. */ int reclip; /* Must be set to at least two or you will get stuck! */ int xclipbord = 4, yclipbord = 2; #endif int mxsize, mysize; /* Track the last level we centered the clipping viewport on, so that both amii_clear_nhwindow (pre-docrt centering) and amii_cliparound (scroll/pan during play) can detect level changes. */ static d_level clip_saved_level = { 127, 127 }; /* XXX */ struct Rectangle amii_oldover; struct Rectangle amii_oldmsg; extern struct TextFont *RogueFont; int amii_msgAPen; int amii_msgBPen; int amii_statAPen; int amii_statBPen; int amii_menuAPen; int amii_menuBPen; int amii_textAPen; int amii_textBPen; int amii_otherAPen; int amii_otherBPen; long amii_libvers = LIBRARY_FONT_VERSION; void ami_wininit_data(int dir) { extern unsigned short amii_init_map[AMII_MAXCOLORS]; extern unsigned short amiv_init_map[AMII_MAXCOLORS]; if (dir != WININIT) return; if (!WINVERS_AMIV) { amii_numcolors = 8; amii_defpens[0] = C_BLACK; /* DETAILPEN */ amii_defpens[1] = C_BLUE; /* BLOCKPEN */ amii_defpens[2] = C_BROWN; /* TEXTPEN */ amii_defpens[3] = C_WHITE; /* SHINEPEN */ amii_defpens[4] = C_BLUE; /* SHADOWPEN */ amii_defpens[5] = C_CYAN; /* FILLPEN */ amii_defpens[6] = C_WHITE; /* FILLTEXTPEN */ amii_defpens[7] = C_CYAN; /* BACKGROUNDPEN */ amii_defpens[8] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[9] = C_WHITE; /* BARDETAILPEN */ amii_defpens[10] = C_CYAN; /* BARBLOCKPEN */ amii_defpens[11] = C_BLUE; /* BARTRIMPEN */ amii_defpens[12] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_BLACK; amii_statAPen = C_WHITE; amii_statBPen = C_BLACK; amii_menuAPen = C_WHITE; amii_menuBPen = C_BLACK; amii_textAPen = C_WHITE; amii_textBPen = C_BLACK; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; mxsize = 8; mysize = 8; amii_libvers = LIBRARY_FONT_VERSION; memcpy(amii_initmap, amii_init_map, sizeof(amii_initmap)); } else { mxsize = 16; mysize = 16; amii_numcolors = 16; amii_defpens[0] = C_BLACK; /* DETAILPEN */ amii_defpens[1] = C_WHITE; /* BLOCKPEN */ amii_defpens[2] = C_BLACK; /* TEXTPEN */ amii_defpens[3] = C_CYAN; /* SHINEPEN */ amii_defpens[4] = C_BLUE; /* SHADOWPEN */ amii_defpens[5] = C_GREYBLUE; /* FILLPEN */ amii_defpens[6] = C_LTGREY; /* FILLTEXTPEN */ amii_defpens[7] = C_GREYBLUE; /* BACKGROUNDPEN */ amii_defpens[8] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[9] = C_WHITE; /* BARDETAILPEN */ amii_defpens[10] = C_GREYBLUE; /* BARBLOCKPEN */ amii_defpens[11] = C_BLUE; /* BARTRIMPEN */ amii_defpens[12] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_GREYBLUE; amii_statAPen = C_WHITE; amii_statBPen = C_GREYBLUE; amii_menuAPen = C_BLACK; amii_menuBPen = C_LTGREY; amii_textAPen = C_BLACK; amii_textBPen = C_LTGREY; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; amii_libvers = LIBRARY_TILE_VERSION; memcpy(amii_initmap, amiv_init_map, sizeof(amii_initmap)); } #ifdef OPT_DISPMAP dispmap_sanity(); #endif memcpy(sysflags.amii_dripens, amii_defpens, sizeof(sysflags.amii_dripens)); } #ifdef INTUI_NEW_LOOK struct Hook SM_FilterHook; struct Hook fillhook; struct TagItem wintags[] = { { WA_BackFill, (ULONG) &fillhook }, { WA_PubScreenName, (ULONG) "NetHack" }, { TAG_END, 0 }, }; #endif void amii_destroy_nhwindow(winid win) /* just hide */ { int i; int type; struct amii_WinDesc *cw; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) { panic(winpanicstr, win, "destroy_nhwindow"); } if (WINVERS_AMIV) { if (cw->type == NHW_MAP) { /* If inventory is up, close it now, it will be freed later */ if (alwaysinvent && WIN_INVEN != WIN_ERR && amii_wins[WIN_INVEN] && amii_wins[WIN_INVEN]->win) { dismiss_nhwindow(WIN_INVEN); } /* Tear down overview window if it is up */ if (WIN_OVER != WIN_ERR) { amii_destroy_nhwindow(WIN_OVER); WIN_OVER = WIN_ERR; } } else if (cw->type == NHW_OVER) { struct Window *w = amii_wins[WIN_OVER]->win; amii_oldover.MinX = w->LeftEdge; amii_oldover.MinY = w->TopEdge; amii_oldover.MaxX = w->Width; amii_oldover.MaxY = w->Height; if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE]) { w = amii_wins[WIN_MESSAGE]->win; amii_oldmsg.MinX = w->LeftEdge; amii_oldmsg.MinY = w->TopEdge; amii_oldmsg.MaxX = w->Width; amii_oldmsg.MaxY = w->Height; SizeWindow(amii_wins[WIN_MESSAGE]->win, (amiIDisplay->xpix - amii_wins[WIN_MESSAGE]->win->LeftEdge) - amii_wins[WIN_MESSAGE]->win->Width, 0); } } } /* Tear down the Intuition stuff */ dismiss_nhwindow(win); type = cw->type; if (cw->resp) { free(cw->resp); cw->resp = NULL; } if (cw->canresp) { free(cw->canresp); cw->canresp = NULL; } if (cw->morestr) { free(cw->morestr); cw->morestr = NULL; } if (cw->hook) { free(cw->hook); cw->hook = NULL; } if (cw->data && (cw->type == NHW_MESSAGE || cw->type == NHW_MENU || cw->type == NHW_TEXT)) { for (i = 0; i < cw->maxrow; ++i) { if (cw->data[i]) free(cw->data[i]); } free(cw->data); } free(cw); amii_wins[win] = NULL; /* Set globals to WIN_ERR for known one-of-a-kind windows. */ if (win == WIN_MAP) WIN_MAP = WIN_ERR; else if (win == WIN_STATUS) WIN_STATUS = WIN_ERR; else if (win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; else if (win == WIN_INVEN) WIN_INVEN = WIN_ERR; } #ifdef INTUI_NEW_LOOK struct FillParams { struct Layer *layer; struct Rectangle bounds; WORD offsetx; WORD offsety; }; #ifdef __GNUC__ #ifdef __PPC__ void PPC_LayerFillHook(void); struct EmulLibEntry LayerFillHook = { TRAP_LIB, 0, (void (*)(void)) PPC_LayerFillHook }; void PPC_LayerFillHook(void) { struct Hook *hk = (struct Hook *) REG_A0; struct RastPort *rp = (struct RastPort *) REG_A2; struct FillParams *fp = (struct FillParams *) REG_A1; #else /* Assembly trampoline: Intuition calls LayerFillHook with arguments in registers a0 (hook), a1 (fillparams), a2 (rastport). Push them onto the stack and call the C implementation. */ __asm( " .globl _LayerFillHook\n" "_LayerFillHook:\n" " move.l a1,-(sp)\n" " move.l a2,-(sp)\n" " move.l a0,-(sp)\n" " jsr _LayerFillHook_impl\n" " lea 12(sp),sp\n" " rts\n" ); void LayerFillHook_impl(struct Hook *hk, struct RastPort *rp, struct FillParams *fp) { #endif #else void #ifndef _DCC __interrupt #endif __saveds __asm LayerFillHook(__a0 struct Hook *hk, __a2 struct RastPort *rp, __a1 struct FillParams *fp) { #endif long x, y, xmax, ymax; int apen; struct RastPort rptmp; memcpy(&rptmp, rp, sizeof(struct RastPort)); rptmp.Layer = NULL; switch ((int) hk->h_Data) { case NHW_STATUS: apen = amii_statBPen; break; case NHW_MESSAGE: apen = amii_msgBPen; break; case NHW_TEXT: apen = amii_textBPen; break; case NHW_MENU: apen = amii_menuBPen; break; case -2: apen = amii_otherBPen; break; case NHW_BASE: case NHW_MAP: case NHW_OVER: default: apen = C_BLACK; break; } x = fp->bounds.MinX; y = fp->bounds.MinY; xmax = fp->bounds.MaxX; ymax = fp->bounds.MaxY; SetAPen(&rptmp, apen); SetBPen(&rptmp, apen); SetDrMd(&rptmp, JAM2); RectFill(&rptmp, x, y, xmax, ymax); } #endif winid amii_create_nhwindow(int type) { struct Window *w = NULL; struct NewWindow *nw = NULL; struct amii_WinDesc *wd = NULL; struct Window *mapwin = NULL, *stwin = NULL, *msgwin = NULL; int newid; int maph, stath, scrfontysize; scrfontysize = HackScreen->Font->ta_YSize; /* * Initial mapwindow height, this might change later in tilemode * and low screen */ maph = (21 * mxsize) + 2 + (bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + scrfontysize + 1 : 0); /* Status window height, avoids having to calculate many times */ stath = txheight * 2 + 2 + (WINVERS_AMIV || bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + (bigscreen ? scrfontysize + 1 : 0) : 0); if (WIN_STATUS != WIN_ERR && amii_wins[WIN_STATUS]) stwin = amii_wins[WIN_STATUS]->win; if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE]) msgwin = amii_wins[WIN_MESSAGE]->win; if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) mapwin = amii_wins[WIN_MAP]->win; /* Create Port anytime that we need it */ if (HackPort == NULL) { HackPort = CreateMsgPort(); if (!HackPort) panic("no memory for msg port"); } nw = &new_wins[type].newwin; nw->Width = amiIDisplay->xpix; nw->Screen = HackScreen; if (WINVERS_AMIV) { nw->DetailPen = C_WHITE; nw->BlockPen = C_GREYBLUE; } else { nw->DetailPen = C_WHITE; nw->BlockPen = C_BLACK; } if (type == NHW_BASE) { nw->LeftEdge = 0; nw->TopEdge = HackScreen->BarHeight + 1; nw->Width = HackScreen->Width; nw->Height = HackScreen->Height - nw->TopEdge; } else if (!WINVERS_AMIV && type == NHW_MAP) { nw->LeftEdge = 0; nw->Height = maph; if (msgwin && stwin) { nw->TopEdge = stwin->TopEdge - maph; } else { panic("msgwin and stwin must open before map"); } if (nw->TopEdge < 0) panic("Too small screen to fit map"); } else if (type == NHW_MAP && WINVERS_AMIV) { struct Window *w; w = amii_wins[WIN_MESSAGE]->win; nw->LeftEdge = 0; nw->TopEdge = w->TopEdge + w->Height; nw->Width = amiIDisplay->xpix - nw->LeftEdge; w = amii_wins[WIN_STATUS]->win; nw->Height = w->TopEdge - nw->TopEdge; nw->MaxHeight = 0xffff; nw->MaxWidth = 0xffff; if (nw->TopEdge + nw->Height > amiIDisplay->ypix - 1) nw->Height = amiIDisplay->ypix - nw->TopEdge - 1; } else if (type == NHW_STATUS) { if (!WINVERS_AMIV && (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP])) w = amii_wins[WIN_MAP]->win; else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) w = amii_wins[WIN_BASE]->win; else panic("No window to base STATUS location from"); nw->Height = stath; nw->TopEdge = amiIDisplay->ypix - nw->Height; nw->LeftEdge = w->LeftEdge; if (nw->LeftEdge + nw->Width >= amiIDisplay->xpix) nw->LeftEdge = 0; if (nw->Width >= amiIDisplay->xpix - nw->LeftEdge) nw->Width = amiIDisplay->xpix - nw->LeftEdge; } else if (WINVERS_AMIV && type == NHW_OVER) { nw->Flags |= WINDOWSIZING | WINDOWDRAG | WINDOWCLOSE; nw->IDCMPFlags |= CLOSEWINDOW; /* Bring up window as half the width of the message window, and make * the message window change to one half the width... */ if (amii_oldover.MaxX != 0) { nw->LeftEdge = amii_oldover.MinX; nw->TopEdge = amii_oldover.MinY; nw->Width = amii_oldover.MaxX; nw->Height = amii_oldover.MaxY; ChangeWindowBox(amii_wins[WIN_MESSAGE]->win, amii_oldmsg.MinX, amii_oldmsg.MinY, amii_oldmsg.MaxX, amii_oldmsg.MaxY); } else { nw->LeftEdge = (amii_wins[WIN_MESSAGE]->win->Width * 4) / 9; nw->TopEdge = amii_wins[WIN_MESSAGE]->win->TopEdge; nw->Width = amiIDisplay->xpix - nw->LeftEdge; nw->Height = amii_wins[WIN_MESSAGE]->win->Height; SizeWindow(amii_wins[WIN_MESSAGE]->win, nw->LeftEdge - amii_wins[WIN_MESSAGE]->win->Width, 0); } } else if (type == NHW_MESSAGE) { if (!WINVERS_AMIV && (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP])) w = amii_wins[WIN_MAP]->win; else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) w = amii_wins[WIN_BASE]->win; else panic("No window to base STATUS location from"); nw->TopEdge = bigscreen ? HackScreen->BarHeight + 1 : 0; /* Assume highest possible message window */ nw->Height = HackScreen->Height - nw->TopEdge - maph - stath; /* In tilemode we can cope with this */ if (WINVERS_AMIV && nw->Height < 0) nw->Height = 0; /* If in fontmode messagewindow is too small, open it with 3 lines and overlap it with map */ if (nw->Height < txheight + 2) { nw->Height = txheight * 4 + 3 + HackScreen->WBorTop + HackScreen->WBorBottom; } if ((nw->Height - 2) / txheight < 3) { scrollmsg = 0; nw->Title = 0; } else { nw->FirstGadget = &MsgScroll; nw->Flags |= WINDOWSIZING | WINDOWDRAG; nw->Flags &= ~BORDERLESS; if (WINVERS_AMIV || nw->Height == 0) { if (WINVERS_AMIV) { nw->Height = TextsFont->tf_YSize + HackScreen->WBorTop + 3 + HackScreen->WBorBottom; if (bigscreen) nw->Height += (txheight * 6); else nw->Height += (txheight * 3); } else { nw->Height = HackScreen->Height - nw->TopEdge - stath - maph; } } } /* Do we have room for larger message window ? * This is possible if we can show full height map in tile * mode with default scaling. */ if (nw->Height + stath + maph < HackScreen->Height - nw->TopEdge) nw->Height = HackScreen->Height - nw->TopEdge - 1 - maph - stath; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { MsgPropScroll.Flags |= PROPNEWLOOK; PropScroll.Flags |= PROPNEWLOOK; } #endif } nw->IDCMPFlags |= MENUPICK; /* Check if there is "Room" for all this stuff... */ if ((WINVERS_AMIV || bigscreen) && type != NHW_BASE) { nw->Flags &= ~(BORDERLESS | BACKDROP); if (WINVERS_AMIV) { if (type == NHW_STATUS) { nw->Flags &= ~(WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING); nw->IDCMPFlags &= ~NEWSIZE; } else { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING); nw->IDCMPFlags |= NEWSIZE; } } else { if (HackScreen->Width < 657) { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH); } else { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT); } } } if (WINVERS_AMII && type == NHW_MAP) nw->Flags &= ~WINDOWSIZING; if (type == NHW_MESSAGE && scrollmsg) { nw->Flags |= WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING; nw->Flags &= ~BORDERLESS; } /* No titles on a hires only screen except for messagewindow */ if (!(WINVERS_AMIV && type == NHW_MAP) && !bigscreen && type != NHW_MESSAGE) nw->Title = 0; wd = (struct amii_WinDesc *) alloc(sizeof(struct amii_WinDesc)); memset(wd, 0, sizeof(struct amii_WinDesc)); /* Both, since user may have changed the pen settings so respect those */ if (WINVERS_AMII || WINVERS_AMIV) { /* Special backfill for these types of layers */ switch (type) { case NHW_MESSAGE: case NHW_STATUS: case NHW_TEXT: case NHW_MENU: case NHW_BASE: case NHW_OVER: case NHW_MAP: if (wd) { fillhook.h_Entry = (void *) &LayerFillHook; fillhook.h_Data = (void *) type; fillhook.h_SubEntry = 0; wd->hook = alloc(sizeof(fillhook)); memcpy(wd->hook, &fillhook, sizeof(fillhook)); memcpy(wd->wintags, wintags, sizeof(wd->wintags)); wd->wintags[0].ti_Data = (long) wd->hook; nw->Extension = (void *) wd->wintags; } break; } } /* Don't open MENU or TEXT windows yet */ if (type == NHW_MENU || type == NHW_TEXT) w = NULL; else w = OpenShWindow((void *) nw); if (w == NULL && type != NHW_MENU && type != NHW_TEXT) { char buf[100]; sprintf(buf, "nw type (%d) dims l: %d, t: %d, w: %d, h: %d", type, nw->LeftEdge, nw->TopEdge, nw->Width, nw->Height); raw_print(buf); panic("bad openwin %d", type); } /* Check for an empty slot */ for (newid = 0; newid < MAXWIN + 1; newid++) { if (amii_wins[newid] == 0) break; } if (newid == MAXWIN + 1) panic("time to write re-alloc code\n"); /* Set wincnt accordingly */ if (newid > wincnt) wincnt = newid; /* Do common initialization */ amii_wins[newid] = wd; wd->newwin = NULL; wd->win = w; wd->type = type; wd->wflags = 0; wd->active = FALSE; wd->curx = wd->cury = 0; wd->resp = wd->canresp = wd->morestr = 0; /* CHECK THESE */ wd->maxrow = new_wins[type].maxrow; wd->maxcol = new_wins[type].maxcol; if (type != NHW_TEXT && type != NHW_MENU) { if (TextsFont && (type == NHW_MESSAGE || type == NHW_STATUS)) { SetFont(w->RPort, TextsFont); txheight = w->RPort->TxHeight; txwidth = w->RPort->TxWidth; txbaseline = w->RPort->TxBaseline; if (type == NHW_MESSAGE) { if (scrollmsg) { if (WINVERS_AMIV) { WindowLimits(w, 100, w->BorderTop + w->BorderBottom + ((txheight + 1) * 2) + 1, 0, 0); } else { WindowLimits(w, w->Width, w->BorderTop + w->BorderBottom + ((txheight + 1) * 2) + 1, 0, 0); } } else { WindowLimits(w, w->Width, w->BorderTop + w->BorderBottom + txheight + 2, 0, 0); } } } if (type != NHW_MAP) { SetFont(w->RPort, TextsFont); } #ifdef HACKFONT else if (HackFont) SetFont(w->RPort, HackFont); #endif } /* Text and menu windows are not opened yet */ if (w) { wd->rows = (w->Height - w->BorderTop - w->BorderBottom - 2) / w->RPort->TxHeight; wd->cols = (w->Width - w->BorderLeft - w->BorderRight - 2) / w->RPort->TxWidth; /* Map window uses y+2 offset in amii_print_glyph, so cury values go up to ROWNO+2. Ensure rows accommodates this. */ if (type == NHW_MAP && wd->rows < ROWNO + 3) wd->rows = ROWNO + 3; } /* Okay, now do the individual type initialization */ switch (type) { /* History lines for MESSAGE windows are stored in cw->data[?]. * maxcol and maxrow are used as cursors. maxrow is the count * of the number of history lines stored. maxcol is the cursor * to the last line that was displayed by ^P. */ case NHW_MESSAGE: SetMenuStrip(w, MenuStrip); MsgScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; iflags.msg_history = wd->rows * 10; if (iflags.msg_history < 40) iflags.msg_history = 40; if (iflags.msg_history > 400) iflags.msg_history = 400; iflags.window_inited = TRUE; wd->data = (char **) alloc(iflags.msg_history * sizeof(char *)); memset(wd->data, 0, iflags.msg_history * sizeof(char *)); wd->maxrow = wd->maxcol = 0; /* Indicate that we have not positioned the cursor yet */ wd->curx = -1; break; /* A MENU contains a list of lines in wd->data[?]. These * lines are created in amii_putstr() by reallocating the size * of wd->data to hold enough (char *)'s. wd->rows is the * number of (char *)'s allocated. wd->maxrow is the number * used. wd->maxcol is used to track how wide the menu needs * to be. wd->resp[x] contains the characters that correspond * to selecting wd->data[x]. wd->resp[x] corresponds to * wd->data[x] for any x. Elements of wd->data[?] that are not * valid selections have the corresponding element of * wd->resp[] set to a value of '\01'; i.e. a ^A which is * not currently a valid keystroke for responding to any * MENU or TEXT window. */ case NHW_MENU: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->resp = (char *) alloc(256); wd->resp[0] = 0; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = 0; wd->data = NULL; break; /* See the explanation of MENU above. Except, wd->resp[] is not * used for TEXT windows since there is no selection of a * a line performed/allowed. The window is always full * screen width. */ case NHW_TEXT: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = amiIDisplay->cols; wd->data = NULL; wd->morestr = NULL; break; /* The status window has only two lines. These are stored in * wd->data[], and here we allocate the space for them. */ case NHW_STATUS: SetMenuStrip(w, MenuStrip); /* wd->cols is the number of characters which fit across the * screen. */ wd->data = (char **) alloc(3 * sizeof(char *)); wd->data[0] = (char *) alloc(wd->cols + 10); wd->data[0][0] = '\0'; wd->data[1] = (char *) alloc(wd->cols + 10); wd->data[1][0] = '\0'; wd->data[2] = NULL; break; /* NHW_OVER does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_OVER: SetMenuStrip(w, MenuStrip); break; /* NHW_MAP does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_MAP: SetMenuStrip(w, MenuStrip); if (WINVERS_AMIV) { CO = (w->Width - w->BorderLeft - w->BorderRight) / mxsize; LI = (w->Height - w->BorderTop - w->BorderBottom) / mysize; amii_setclipped(); SetFont(w->RPort, RogueFont); SetAPen(w->RPort, C_WHITE); /* XXX not sufficient */ SetBPen(w->RPort, C_BLACK); SetDrMd(w->RPort, JAM2); } else { if (HackFont) SetFont(w->RPort, HackFont); } break; /* The base window must exist until CleanUp() deletes it. */ case NHW_BASE: SetMenuStrip(w, MenuStrip); /* Make our requesters come to our screen */ { struct Process *myProcess = (struct Process *) FindTask(NULL); pr_WindowPtr = (struct Window *) (myProcess->pr_WindowPtr); myProcess->pr_WindowPtr = (APTR) w; } /* Need this for RawKeyConvert() */ ConsoleIO.io_Data = (APTR) w; ConsoleIO.io_Length = sizeof(struct Window); ConsoleIO.io_Message.mn_ReplyPort = CreateMsgPort(); if (OpenDevice("console.device", -1L, (struct IORequest *) &ConsoleIO, 0L) != 0) { Abort(AG_OpenDev | AO_ConsoleDev); } ConsoleDevice = (struct Device *) ConsoleIO.io_Device; KbdBuffered = 0; #ifdef HACKFONT if (TextsFont) SetFont(w->RPort, TextsFont); else if (HackFont) SetFont(w->RPort, HackFont); #endif txwidth = w->RPort->TxWidth; txheight = w->RPort->TxHeight; txbaseline = w->RPort->TxBaseline; break; default: panic("bad create_nhwindow( %d )\n", type); return WIN_ERR; } return (newid); } #ifdef __GNUC__ #ifdef __PPC__ int PPC_SM_Filter(void); struct EmulLibEntry SM_Filter = { TRAP_LIB, 0, (int (*)(void)) PPC_SM_Filter }; int PPC_SM_Filter(void) { struct Hook *hk = (struct Hook *) REG_A0; ULONG modeID = (ULONG) REG_A1; struct ScreenModeRequester *smr = (struct ScreenModeRequester *) REG_A2; #else /* Assembly trampoline for SM_Filter hook callback. SM_Filter is the asm entry point; SM_Filter_impl is the C body. */ extern void SM_Filter(void); __asm( " .globl _SM_Filter\n" "_SM_Filter:\n" " move.l a2,-(sp)\n" " move.l a1,-(sp)\n" " move.l a0,-(sp)\n" " jsr _SM_Filter_impl\n" " lea 12(sp),sp\n" " rts\n" ); int SM_Filter_impl(struct Hook *hk, ULONG modeID, struct ScreenModeRequester *smr) { #endif #else int #ifndef _DCC __interrupt #endif __saveds __asm SM_Filter( __a0 struct Hook *hk, __a1 ULONG modeID, __a2 struct ScreenModeRequester *smr) { #endif struct DimensionInfo dims; struct DisplayInfo disp; DisplayInfoHandle handle; handle = FindDisplayInfo(modeID); if (handle) { GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeID); GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeID); if (!disp.NotAvailable && dims.MaxDepth <= 8 && dims.StdOScan.MaxX >= WIDTH - 1 && dims.StdOScan.MaxY >= SCREENHEIGHT - 1) { return 1; } } return 0; } /* Initialize the windowing environment */ void amii_init_nhwindows(int *argcp, char **argv) { int i; struct Screen *wbscr; int forcenobig = 0; if (HackScreen) panic("init_nhwindows() called twice", 0); /* run args & set bigscreen from -L(1)/-l(-1) */ { int lclargc = *argcp; int t; char **argv_in = argv; char **argv_out = argv; for (t = 1; t <= lclargc; t++) { if (!strcmp("-L", *argv_in) || !strcmp("-l", *argv_in)) { bigscreen = (*argv_in[1] == 'l') ? -1 : 1; /* and eat the flag */ (*argcp)--; } else { *argv_out = *argv_in; /* keep the flag */ argv_out++; } argv_in++; } *argv_out = 0; } WIN_MESSAGE = WIN_ERR; WIN_MAP = WIN_ERR; WIN_STATUS = WIN_ERR; WIN_INVEN = WIN_ERR; WIN_BASE = WIN_ERR; WIN_OVER = WIN_ERR; if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_Intuition); } if ((GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_GraphicsLib); } if ((LayersBase = (struct Library *) OpenLibrary("layers.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_LayersLib); } if ((GadToolsBase = OpenLibrary("gadtools.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_GadTools); } if ((AslBase = OpenLibrary("asl.library", amii_libvers)) == NULL) { Abort(AG_OpenLib); } amiIDisplay = (struct amii_DisplayDesc *) alloc(sizeof(struct amii_DisplayDesc)); memset(amiIDisplay, 0, sizeof(struct amii_DisplayDesc)); /* Use Intuition sizes for overscan screens... */ amiIDisplay->xpix = 0; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { if (wbscr = LockPubScreen("Workbench")) { amiIDisplay->xpix = wbscr->Width; amiIDisplay->ypix = wbscr->Height; UnlockPubScreen(NULL, wbscr); } } #endif if (amiIDisplay->xpix == 0) { amiIDisplay->ypix = GfxBase->NormalDisplayRows; amiIDisplay->xpix = GfxBase->NormalDisplayColumns; } amiIDisplay->cols = amiIDisplay->xpix / FONTWIDTH; amiIDisplay->toplin = 0; amiIDisplay->rawprint = 0; amiIDisplay->lastwin = 0; if (bigscreen == 0) { if ((GfxBase->ActiView->ViewPort->Modes & LACE) == LACE) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; bigscreen = 1; } else if (GfxBase->NormalDisplayRows >= 300 || amiIDisplay->ypix >= 300) { bigscreen = 1; } } else if (bigscreen == -1) { bigscreen = 0; forcenobig = 1; } else if (bigscreen) { /* If bigscreen requested and we don't have enough rows in * noninterlaced mode, switch to interlaced... */ if (GfxBase->NormalDisplayRows < 300) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; } } if (!bigscreen) { alwaysinvent = 0; } amiIDisplay->rows = amiIDisplay->ypix / FONTHEIGHT; #ifdef HACKFONT /* * Load the fonts that we need. */ if (DiskfontBase = OpenLibrary("diskfont.library", amii_libvers)) { Hack80.ta_Name -= SIZEOF_DISKNAME; HackFont = OpenDiskFont(&Hack80); Hack80.ta_Name += SIZEOF_DISKNAME; /* Textsfont13 is filled in with "FONT=" settings. The default is * courier/13. */ TextsFont = NULL; if (bigscreen) TextsFont = OpenDiskFont(&TextsFont13); /* Try hack/8 for texts if no user specified font */ if (TextsFont == NULL) { Hack80.ta_Name -= SIZEOF_DISKNAME; TextsFont = OpenDiskFont(&Hack80); Hack80.ta_Name += SIZEOF_DISKNAME; } /* If no fonts, make everything topaz 8 for non-view windows. */ Hack80.ta_Name = "topaz.font"; RogueFont = OpenFont(&Hack80); if (!RogueFont) panic("Can't get topaz:8"); if (!HackFont || !TextsFont) { if (!HackFont) { HackFont = OpenFont(&Hack80); if (!HackFont) panic("Can't get a map font, topaz:8"); } if (!TextsFont) { TextsFont = OpenFont(&Hack80); if (!TextsFont) panic("Can't open text font"); } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } #endif /* Adjust getlin window size to font */ if (TextsFont) { extern SHORT BorderVectors1[]; extern SHORT BorderVectors2[]; extern struct Gadget Gadget2; extern struct Gadget String; extern struct NewWindow StrWindow; BorderVectors1[2] += (TextsFont->tf_XSize - 8) * 6; /* strlen("Cancel") == 6 */ BorderVectors1[4] += (TextsFont->tf_XSize - 8) * 6; BorderVectors1[5] += TextsFont->tf_YSize - 8; BorderVectors1[7] += TextsFont->tf_YSize - 8; BorderVectors2[2] += (TextsFont->tf_XSize - 8) * 6; BorderVectors2[4] += (TextsFont->tf_XSize - 8) * 6; BorderVectors2[5] += TextsFont->tf_YSize - 8; BorderVectors2[7] += TextsFont->tf_YSize - 8; Gadget2.TopEdge += TextsFont->tf_YSize - 8; Gadget2.Width += (TextsFont->tf_XSize - 8) * 6; Gadget2.Height += TextsFont->tf_YSize - 8; String.LeftEdge += (TextsFont->tf_XSize - 8) * 6; String.TopEdge += TextsFont->tf_YSize - 8; String.Width += TextsFont->tf_XSize - 8; String.Height += TextsFont->tf_YSize - 8; StrWindow.Width += (TextsFont->tf_XSize - 8) * 7; StrWindow.Height += (TextsFont->tf_YSize - 8) * 2; /* Titlebar + 1 row of gadgets */ } /* This is the size screen we want to open, within reason... */ NewHackScreen.Width = max(WIDTH, amiIDisplay->xpix); NewHackScreen.Height = max(SCREENHEIGHT, amiIDisplay->ypix); { static char fname[18]; sprintf(fname, "NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); NewHackScreen.DefaultTitle = fname; } #if 0 NewHackScreen.BlockPen = C_BLACK; NewHackScreen.DetailPen = C_WHITE; #endif #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { int i; struct DimensionInfo dims; DisplayInfoHandle handle; struct DisplayInfo disp; ULONG modeid = DEFAULT_MONITOR_ID | HIRES_KEY; NewHackScreen.Width = STDSCREENWIDTH; NewHackScreen.Height = STDSCREENHEIGHT; #ifdef HACKFONT if (TextsFont) { NewHackScreen.Font = &TextsFont13; } #endif if (amii_scrnmode == 0xffffffff) { struct ScreenModeRequester *SMR; #ifdef __GNUC__ SM_FilterHook.h_Entry = (void *) &SM_Filter; #else SM_FilterHook.h_Entry = (ULONG (*) ()) SM_Filter; #endif SM_FilterHook.h_Data = 0; SM_FilterHook.h_SubEntry = 0; SMR = AllocAslRequest(ASL_ScreenModeRequest, NULL); if (AslRequestTags(SMR, ASLSM_FilterFunc, (ULONG) &SM_FilterHook, TAG_END)) amii_scrnmode = SMR->sm_DisplayID; else amii_scrnmode = 0; FreeAslRequest(SMR); } if (forcenobig == 0) { if ((wbscr = LockPubScreen("Workbench")) != NULL || (wbscr = LockPubScreen(NULL)) != NULL) { /* Get the default pub screen's size */ modeid = GetVPModeID(&wbscr->ViewPort); if (modeid == INVALID_ID || ModeNotAvailable(modeid) || (handle = FindDisplayInfo(modeid)) == NULL || GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeid) <= 0 || GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeid) <= 0) { modeid = DEFAULT_MONITOR_ID | HIRES_KEY; /* If the display database seems to not work, use the * screen * dimensions */ NewHackScreen.Height = wbscr->Height; NewHackScreen.Width = wbscr->Width; /* * Request LACE if it looks laced. For 2.1/3.0, we will * get * promoted to the users choice of modes (if promotion is * allowed) * If the user is using a dragable screen, things will get * hosed * but that is life... */ if (wbscr->ViewPort.Modes & LACE) NewHackScreen.ViewModes |= LACE; modeid = -1; } else { /* Use the display database to get the correct information */ if (disp.PropertyFlags & DIPF_IS_LACE) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY + 1; NewHackScreen.Width = dims.StdOScan.MaxX + 1; } NewHackScreen.TopEdge = 0; NewHackScreen.LeftEdge = 0; UnlockPubScreen(NULL, wbscr); } } for (i = 0; scrntags[i].ti_Tag != TAG_DONE; ++i) { switch (scrntags[i].ti_Tag) { case SA_DisplayID: if (!amii_scrnmode || ModeNotAvailable(amii_scrnmode)) { if (ModeNotAvailable(modeid)) { scrntags[i].ti_Tag = TAG_IGNORE; break; } else scrntags[i].ti_Data = (long) modeid; } else modeid = scrntags[i].ti_Data = (long) amii_scrnmode; if ((handle = FindDisplayInfo(modeid)) != NULL && GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeid) > 0 && GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeid) > 0) { if (disp.PropertyFlags & DIPF_IS_LACE) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY + 1; NewHackScreen.Width = dims.StdOScan.MaxX + 1; } break; case SA_Pens: scrntags[i].ti_Data = (long) sysflags.amii_dripens; break; } } } #endif if (WINVERS_AMIV) { extern char *tilefile; if (amii_numcolors >= 32) { tilefile = "NetHack:tiles/tiles32.iff"; amii_numcolors = 32; } else { tilefile = "NetHack:tiles/tiles16.iff"; } amii_bmhd = ReadTileImageFiles(); } else memcpy(amii_initmap, amii_init_map, sizeof(amii_initmap)); memcpy(sysflags.amii_curmap, amii_initmap, sizeof(sysflags.amii_curmap)); /* Find out how deep the screen needs to be, 32 planes is enough! */ for (i = 0; i < 32; ++i) { if ((1L << i) >= amii_numcolors) break; } NewHackScreen.Depth = i; /* If for some reason Height/Width became smaller than the required, have the required one */ if (NewHackScreen.Height < SCREENHEIGHT) NewHackScreen.Height = SCREENHEIGHT; if (NewHackScreen.Width < WIDTH) NewHackScreen.Width = WIDTH; #ifdef HACKFONT i = max(TextsFont->tf_XSize, HackFont->tf_XSize); if (NewHackScreen.Width < 80 * i + 4) NewHackScreen.Width = 80 * i + 4; #endif /* While openscreen fails try fewer colors to see if that is the problem. */ while ((HackScreen = OpenScreen((void *) &NewHackScreen)) == NULL) { if (--NewHackScreen.Depth < 3) Abort(AN_OpenScreen & ~AT_DeadEnd); } amii_numcolors = 1L << NewHackScreen.Depth; if (HackScreen->Height > 300 && forcenobig == 0) bigscreen = 1; else bigscreen = 0; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) PubScreenStatus(HackScreen, 0); #endif amiIDisplay->ypix = HackScreen->Height; amiIDisplay->xpix = HackScreen->Width; LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); VisualInfo = GetVisualInfo(HackScreen, TAG_END); MenuStrip = CreateMenus(GTHackMenu, TAG_END); LayoutMenus(MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END); /* Display the copyright etc... */ if (WIN_BASE == WIN_ERR) WIN_BASE = amii_create_nhwindow(NHW_BASE); amii_clear_nhwindow(WIN_BASE); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_A); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_B); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_C); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_D); amii_putstr(WIN_BASE, 0, ""); Initialized = 1; } void amii_sethipens(struct Window *w, int type, int attr) { switch (type) { default: SetAPen(w->RPort, attr ? C_RED : amii_otherAPen); SetBPen(w->RPort, C_BLACK); break; case NHW_STATUS: SetAPen(w->RPort, attr ? C_WHITE : amii_statAPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MESSAGE: SetAPen(w->RPort, attr ? C_WHITE : amii_msgAPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_MENU: SetAPen(w->RPort, attr ? C_BLACK : amii_menuAPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, attr ? C_BLACK : amii_textAPen); SetBPen(w->RPort, amii_textBPen); case -2: SetBPen(w->RPort, amii_otherBPen); SetAPen(w->RPort, attr ? C_RED : amii_otherAPen); break; } } void amii_setfillpens(struct Window *w, int type) { switch (type) { case NHW_MESSAGE: SetAPen(w->RPort, amii_msgBPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_STATUS: SetAPen(w->RPort, amii_statBPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MENU: SetAPen(w->RPort, amii_menuBPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, amii_textBPen); SetBPen(w->RPort, amii_textBPen); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: default: SetAPen(w->RPort, C_BLACK); SetBPen(w->RPort, C_BLACK); break; case -2: SetAPen(w->RPort, amii_otherBPen); SetBPen(w->RPort, amii_otherBPen); break; } } void amii_setdrawpens(struct Window *w, int type) { switch (type) { case NHW_MESSAGE: SetAPen(w->RPort, amii_msgAPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_STATUS: SetAPen(w->RPort, amii_statAPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MENU: SetAPen(w->RPort, amii_menuAPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, amii_textAPen); SetBPen(w->RPort, amii_textBPen); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: SetAPen(w->RPort, C_WHITE); SetBPen(w->RPort, C_BLACK); break; default: SetAPen(w->RPort, amii_otherAPen); SetBPen(w->RPort, amii_otherBPen); break; } } /* Clear the indicated window */ void amii_clear_nhwindow(winid win) { struct amii_WinDesc *cw; struct Window *w; if (reclip == 2) return; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) panic(winpanicstr, win, "clear_nhwindow"); /* Clear the overview window too if it is displayed */ if (WINVERS_AMIV && (cw->type == WIN_MAP && WIN_OVER != WIN_ERR && reclip == 0)) { amii_clear_nhwindow(WIN_OVER); } if (w = cw->win) SetDrMd(w->RPort, JAM2); else return; if ((cw->wflags & FLMAP_CURSUP)) { if (cw->type != NHW_MAP) cursor_off(win); else cw->wflags &= ~FLMAP_CURSUP; } amii_setfillpens(w, cw->type); SetDrMd(w->RPort, JAM2); #ifdef CLIPPING /* When clearing the map for a full redraw (docrt/cls), center the clipping viewport on the player BEFORE the map is redrawn. Without this, the first docrt() after a level change or new game draws with stale clip coordinates (typically 0,0), leaving the player off-screen until their first move triggers amii_cliparound. */ if (cw->type == NHW_MAP && clipping && u.ux && !on_level(&u.uz, &clip_saved_level)) { int COx, LIx; struct RastPort *rp = w->RPort; if (Is_rogue_level(&u.uz)) { COx = (w->Width - w->BorderLeft - w->BorderRight) / rp->TxWidth; LIx = (w->Height - w->BorderTop - w->BorderBottom) / rp->TxHeight; } else { COx = CO; LIx = LI; } clipx = max(0, (int) u.ux - COx / 2); clipxmax = clipx + COx; if (clipxmax > COLNO) { clipxmax = COLNO; clipx = clipxmax - COx; } clipy = max(0, (int) u.uy - LIx / 2); clipymax = clipy + LIx; if (clipymax > ROWNO) { clipymax = ROWNO; clipy = clipymax - LIx; } clip_saved_level = u.uz; } #endif if (cw->type == NHW_MENU || cw->type == NHW_TEXT) { RectFill(w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } else { if (cw->type == NHW_MESSAGE) { amii_curs(win, 1, 0); if (!scrollmsg) TextSpaces(w->RPort, cw->cols); } else { RectFill(w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } } cw->cury = 0; cw->curx = 0; amii_curs(win, 1, 0); } /* Dismiss the window from the screen */ void dismiss_nhwindow(winid win) { struct Window *w; struct amii_WinDesc *cw; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) { panic(winpanicstr, win, "dismiss_nhwindow"); } w = cw->win; if (w) { /* All windows have this stuff attached to them. */ if (cw->type == NHW_MAP || cw->type == NHW_OVER || cw->type == NHW_BASE || cw->type == NHW_MESSAGE || cw->type == NHW_STATUS) { ClearMenuStrip(w); } /* Save where user like inventory to appear */ if (win == WIN_INVEN) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } /* Close the window */ CloseShWindow(w); cw->win = NULL; /* Free copy of NewWindow structure for TEXT/MENU windows. */ if (cw->newwin) FreeNewWindow((void *) cw->newwin); cw->newwin = NULL; } } void amii_exit_nhwindows(const char *str) { /* Seems strange to have to do this... but we need the BASE window * left behind... */ kill_nhwindows(0); if (WINVERS_AMIV) FreeTileImageFiles(); if (str) { raw_print(""); /* be sure we're not under the top margin */ raw_print(str); } } void amii_display_nhwindow(winid win, boolean blocking) { menu_item *mip; int cnt; static int lastwin = -1; struct amii_WinDesc *cw; if (!Initialized) return; lastwin = win; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) panic(winpanicstr, win, "display_nhwindow"); if (cw->type == NHW_MESSAGE) cw->wflags &= ~FLMAP_SKIP; if (cw->type == NHW_MESSAGE || cw->type == NHW_STATUS) return; if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) { flush_glyph_buffer(amii_wins[WIN_MAP]->win); } if (cw->type == NHW_MENU || cw->type == NHW_TEXT) { cnt = DoMenuScroll(win, blocking, PICK_ONE, &mip); } else if (cw->type == NHW_MAP) { amii_end_glyphout(win); /* Do more if it is time... */ if (blocking == TRUE && amii_wins[WIN_MESSAGE]->curx) { outmore(amii_wins[WIN_MESSAGE]); } } } void amii_curs(winid window, int x, int y) { struct amii_WinDesc *cw; struct Window *w; struct RastPort *rp; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) panic(winpanicstr, window, "curs"); if ((w = cw->win) == NULL) { if (cw->type == NHW_MENU || cw->type == NHW_TEXT) return; else panic("No window open yet in curs() for winid %d\n", window); } amiIDisplay->lastwin = window; /* Make sure x is within bounds */ if (x > 0) --x; /* column 0 is never used */ else x = 0; cw->curx = x; cw->cury = y; /* Silently skip rendering for out-of-bounds coordinates */ if (cw->rows > 0 && y >= cw->rows) return; if (cw->cols > 0 && x >= cw->cols) return; #ifdef DEBUG if (0 && (x < 0 || y < 0 || y >= cw->rows || x >= cw->cols)) { char *s = "[unknown type]"; switch (cw->type) { case NHW_MESSAGE: s = "[topl window]"; break; case NHW_STATUS: s = "[status window]"; break; case NHW_MAP: s = "[map window]"; break; case NHW_MENU: s = "[menu window]"; break; case NHW_TEXT: s = "[text window]"; break; case NHW_BASE: s = "[base window]"; break; case NHW_OVER: s = "[overview window]"; break; } impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y); return; } #endif #ifdef CLIPPING if (clipping && cw->type == NHW_MAP) { x -= clipx; y -= clipy; } #endif /* Output all saved output before doing cursor movements for MAP */ if (cw->type == NHW_MAP) { flush_glyph_buffer(w); } /* Actually do it */ rp = w->RPort; if (cw->type == NHW_MENU) { if (WINVERS_AMIV) { if (window == WIN_INVEN) { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1 + pictdata.xsize + 4, (y * max(rp->TxHeight, pictdata.ysize + 3)) + rp->TxBaseline + pictdata.ysize - rp->TxHeight + w->BorderTop + 4); } else { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } } else { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } } else if (cw->type == NHW_TEXT) { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } else if (cw->type == NHW_MAP || cw->type == NHW_BASE) { /* These coordinate calculations must be synced with those * in flush_glyph_buffer() in winchar.c. curs_on_u() will * use this code, all other drawing occurs through the glyph * code. In order for the cursor to appear on top of the hero, * the code must compute X,Y in the same manner relative to * the RastPort coordinates. * * y = w->BorderTop + (g_nodes[i].y-2) * rp->TxHeight + * rp->TxBaseline + 1; * x = g_nodes[i].x * rp->TxWidth + w->BorderLeft; */ if (WINVERS_AMIV) { if (cw->type == NHW_MAP) { if (Is_rogue_level(&u.uz)) { #if 0 int qqx= (x * w->RPort->TxWidth) + w->BorderLeft; int qqy= w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1; printf("pos: (%d,%d)->(%d,%d)\n",x,y,qqx,qqy); #endif SetAPen(w->RPort, C_WHITE); /* XXX should be elsewhere (was 4)*/ Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ((y + 1) * w->RPort->TxHeight) + 1); } else { Move(rp, (x * mxsize) + w->BorderLeft, w->BorderTop + ((y + 1) * mysize) + 1); } } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ((y + 1) * w->RPort->TxHeight) + w->RPort->TxBaseline + 1); } } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + (y * w->RPort->TxHeight) + w->RPort->TxBaseline + 1); } } else if (WINVERS_AMIV && cw->type == NHW_OVER) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3); } else if (cw->type == NHW_MESSAGE && !scrollmsg) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3); } else if (cw->type == NHW_STATUS) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y * (w->RPort->TxHeight + 1)) + w->BorderTop + w->RPort->TxBaseline + 1); } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y * w->RPort->TxHeight) + w->BorderTop + w->RPort->TxBaseline + 1); } } void amii_set_text_font(char *name, int size) { int i; struct amii_WinDesc *cw; int osize = TextsFont13.ta_YSize; static char nname[100]; strncpy(nname, name, sizeof(nname) - 1); nname[sizeof(nname) - 1] = 0; TextsFont13.ta_Name = nname; TextsFont13.ta_YSize = size; /* No alternate text font allowed for 640x269 or smaller */ if (!HackScreen || !bigscreen) return; /* Look for windows to set, and change them */ if (DiskfontBase = OpenLibrary("diskfont.library", amii_libvers)) { TextsFont = OpenDiskFont(&TextsFont13); for (i = 0; TextsFont && i < MAXWIN; ++i) { if ((cw = amii_wins[i]) && cw->win != NULL) { switch (cw->type) { case NHW_STATUS: MoveWindow(cw->win, 0, -(size - osize) * 2); SizeWindow(cw->win, 0, (size - osize) * 2); SetFont(cw->win->RPort, TextsFont); break; case NHW_MESSAGE: case NHW_MAP: case NHW_BASE: case NHW_OVER: SetFont(cw->win->RPort, TextsFont); break; } } } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } void kill_nhwindows(int all) { int i; struct amii_WinDesc *cw; /* Foreach open window in all of amii_wins[], CloseShWindow, free memory */ for (i = 0; i < MAXWIN; ++i) { if ((cw = amii_wins[i]) && (cw->type != NHW_BASE || all)) { amii_destroy_nhwindow(i); } } } void amii_cl_end(struct amii_WinDesc *cw, int curs_pos) { struct Window *w = cw->win; int oy, ox; if (!w) panic("NULL window pointer in amii_cl_end()"); oy = w->RPort->cp_y; ox = w->RPort->cp_x; TextSpaces(w->RPort, cw->cols - curs_pos); Move(w->RPort, ox, oy); } void cursor_off(winid window) { struct amii_WinDesc *cw; struct Window *w; struct RastPort *rp; int curx, cury; int x, y; long dmode; short apen, bpen; unsigned char ch; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) { iflags.window_inited = 0; panic(winpanicstr, window, "cursor_off"); } if (!(cw->wflags & FLMAP_CURSUP)) return; w = cw->win; if (!w) return; cw->wflags &= ~FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ curx = rp->cp_x; cury = rp->cp_y; x = cw->cursx; y = cw->cursy; dmode = rp->DrawMode; apen = rp->FgPen; bpen = rp->BgPen; SetAPen(rp, cw->curs_apen); SetBPen(rp, cw->curs_bpen); SetDrMd(rp, COMPLEMENT); /*printf("CURSOR OFF: %d %d\n",x,y);*/ if (WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); if (Is_rogue_level(&u.uz)) Move(rp, curx, cury); } else { ch = CURSOR_CHAR; Move(rp, x, y); Text(rp, &ch, 1); /* Put back the other stuff */ Move(rp, curx, cury); } SetDrMd(rp, dmode); SetAPen(rp, apen); SetBPen(rp, bpen); } void cursor_on(winid window) { int x, y; struct amii_WinDesc *cw; struct Window *w; struct RastPort *rp; unsigned char ch; long dmode; short apen, bpen; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) { /* tty does this differently - is this OK? */ iflags.window_inited = 0; panic(winpanicstr, window, "cursor_on"); } /*printf("CURSOR ON: %d %d\n",cw->win->RPort->cp_x, * cw->win->RPort->cp_y);*/ if ((cw->wflags & FLMAP_CURSUP)) cursor_off(window); w = cw->win; if (!w) return; cw->wflags |= FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ #ifdef DISPMAP if (WINVERS_AMIV && cw->type == NHW_MAP && !Is_rogue_level(&u.uz)) x = cw->cursx = (rp->cp_x & -8) + 8; else #endif x = cw->cursx = rp->cp_x; y = cw->cursy = rp->cp_y; apen = rp->FgPen; bpen = rp->BgPen; dmode = rp->DrawMode; /* Draw in complement mode. The cursor body will be C_WHITE */ cw->curs_apen = 0xff; /* Last color/all planes, regardless of depth */ cw->curs_bpen = 0xff; SetAPen(rp, cw->curs_apen); SetBPen(rp, cw->curs_bpen); SetDrMd(rp, COMPLEMENT); if (WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); } else { if (w && x >= 0 && y >= 0 && x < w->Width && y < w->Height) { Move(rp, x, y); ch = CURSOR_CHAR; Text(rp, &ch, 1); Move(rp, x, y); } } SetDrMd(rp, dmode); SetAPen(rp, apen); SetBPen(rp, bpen); } static void cursor_common(struct RastPort *rp, int x, int y) { int x1, x2, y1, y2; if (Is_rogue_level(&u.uz)) { x1 = x - 2; y1 = y - rp->TxHeight; x2 = x + rp->TxWidth + 1; y2 = y + 3; /*printf("COMM: (%d %d) (%d %d) (%d %d) (%d * %d)\n",x1,y1,x2,y2,x1+2,y1+2,x2-2,y2-2);*/ } else { x1 = x; y1 = y - mysize - 1; x2 = x + mxsize - 1; y2 = y - 2; RectFill(rp, x1, y1, x2, y2); } RectFill(rp, x1 + 2, y1 + 2, x2 - 2, y2 - 2); } void amii_suspend_nhwindows(const char *str) { if (HackScreen) ScreenToBack(HackScreen); } void amii_resume_nhwindows(void) { if (HackScreen) ScreenToFront(HackScreen); } void amii_bell(void) { DisplayBeep(NULL); } void removetopl(int cnt) { struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE]; /* NB - this is sufficient for * yn_function, but that's it */ if (cw->curx < cnt) cw->curx = 0; else cw->curx -= cnt; amii_curs(WIN_MESSAGE, cw->curx + 1, cw->cury); amii_cl_end(cw, cw->curx); } /*#endif /* AMIGA_INTUITION */ #ifdef PORT_HELP void port_help(void) { display_file(PORT_HELP, 1); } #endif /* * print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void amii_print_glyph(winid win, coordxy x, coordxy y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo UNUSED) { struct amii_WinDesc *cw; uchar ch; int glyph; int color, och; extern const int zapcolors[]; unsigned special; glyph = glyphinfo->glyph; /* In order for the overview window to work, we can not clip here */ if (!WINVERS_AMIV) { #ifdef CLIPPING /* If point not in visible part of window just skip it */ if (clipping) { if (x <= clipx || y < clipy || x >= clipxmax || y >= clipymax) return; } #endif } if (win == WIN_ERR || (cw = amii_wins[win]) == NULL || cw->type != NHW_MAP) { panic(winpanicstr, win, "amii_print_glyph"); } #if 0 { static int x=-1; if(u.uz.dlevel != x){ fprintf(stderr,"lvlchg: %d (%d)\n",u.uz.dlevel,Is_rogue_level(&u.uz)); x = u.uz.dlevel; } } #endif if (WINVERS_AMIV && !Is_rogue_level(&u.uz)) { amii_curs(win, x, y); amiga_print_glyph(win, 0, glyph); } else /* AMII, or Rogue level in either version */ { /* map glyph to character and color */ ch = glyphinfo->ttychar; color = glyphinfo->gm.sym.color; if (WINVERS_AMIV) { /* implies Rogue level here */ amii_curs(win, x, y); amiga_print_glyph(win, NO_COLOR, ch + 10000); } else { /* Move the cursor. */ amii_curs(win, x, y + 2); /* Turn off color if rogue level. */ if (Is_rogue_level(&u.uz)) color = NO_COLOR; amiga_print_glyph(win, color, ch); cw->curx++; /* one character over */ } } } /* Make sure the user sees a text string when no windowing is available */ void amii_raw_print(const char *s) { int argc = 0; if (!s) return; if (amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if (Initialized == 0 && WIN_BASE == WIN_ERR) init_nhwindows(&argc, (char **) 0); if (amii_rawprwin != WIN_ERR) amii_putstr(amii_rawprwin, 0, s); else if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) amii_putstr(WIN_MAP, 0, s); else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) amii_putstr(WIN_BASE, 0, s); else { puts(s); fflush(stdout); } } /* Make sure the user sees a bold text string when no windowing * is available */ void amii_raw_print_bold(const char *s) { int argc = 0; if (!s) return; if (amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if (Initialized == 0 && WIN_BASE == WIN_ERR) init_nhwindows(&argc, (char **) 0); if (amii_rawprwin != WIN_ERR) amii_putstr(amii_rawprwin, 1, s); else if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) amii_putstr(WIN_MAP, 1, s); else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) amii_putstr(WIN_BASE, 1, s); else { printf("\33[1m%s\33[0m\n", s); fflush(stdout); } } /* Rebuild/update the inventory if the window is up. */ void amii_update_inventory(int arg UNUSED) { struct amii_WinDesc *cw; if (WIN_INVEN != WIN_ERR && (cw = amii_wins[WIN_INVEN]) && cw->type == NHW_MENU && cw->win) { repopulate_perminvent(); } } /* Stub for ctrl_nhwindow - no special handling needed for Amiga */ win_request_info * amii_ctrl_nhwindow(winid window UNUSED, int request UNUSED, win_request_info *wri UNUSED) { return (win_request_info *) 0; } /* Humm, doesn't really do anything useful */ void amii_mark_synch(void) { if (!amiIDisplay) fflush(stderr); /* anything else? do we need this much? */ } /* Wait for everything to sync. Nothing is asynchronous, so we just * ask for a key to be pressed. */ void amii_wait_synch(void) { if (!amiIDisplay || amiIDisplay->rawprint) { if (amiIDisplay) amiIDisplay->rawprint = 0; } else { if (WIN_MAP != WIN_ERR) { display_nhwindow(WIN_MAP, TRUE); flush_glyph_buffer(amii_wins[WIN_MAP]->win); } } } void amii_setclipped(void) { #ifdef CLIPPING clipping = TRUE; clipx = clipy = 0; clipxmax = CO; clipymax = LI; /* some of this is now redundant with top of amii_cliparound XXX */ #endif } /* Redraw a rectangular region of the map via newsym(). Used after ScrollRaster() shifts existing pixels — only the exposed strip needs redrawing. Does NOT flush; the caller flushes after all regions. */ static void redraw_map_region(int x1, int y1, int x2, int y2) { int x, y; if (!u.ux) return; if (x1 < 1) x1 = 1; if (y1 < 0) y1 = 0; if (x2 >= COLNO) x2 = COLNO - 1; if (y2 >= ROWNO) y2 = ROWNO - 1; for (y = y1; y <= y2; y++) for (x = x1; x <= x2; x++) { /* Invalidate the glyph buffer so newsym() redraws even if * the glyph hasn't changed — the pixels were shifted by * ScrollRaster and no longer match the buffer. */ gg.gbuf[y][x].glyphinfo.glyph = NO_GLYPH; newsym(x, y); } } /* XXX still to do: suppress scrolling if we violate the boundary but the * edge of the map is already displayed */ void amii_cliparound(int x, int y) { #ifdef CLIPPING int oldx = clipx, oldy = clipy; int oldxmax = clipxmax, oldymax = clipymax; int COx, LIx; #define SCROLLCNT 1 /* Get there in 3 moves... */ int scrollcnt = SCROLLCNT; /* ...or 1 if we changed level */ if (!clipping) { /* And 1 in anycase, cleaner, simpler, quicker */ return; } if (Is_rogue_level(&u.uz)) { struct Window *w = amii_wins[WIN_MAP]->win; struct RastPort *rp = w->RPort; COx = (w->Width - w->BorderLeft - w->BorderRight) / rp->TxWidth; LIx = (w->Height - w->BorderTop - w->BorderBottom) / rp->TxHeight; } else { COx = CO; LIx = LI; } /* * On a level change, move the clipping region so that for a * reasonablely large window extra motion is avoided; for * the rogue level hopefully this means no motion at all. */ if (!on_level(&u.uz, &clip_saved_level)) { scrollcnt = 1; /* jump with blanking */ /* Center viewport on the player for the new level. */ clipx = max(0, x - COx / 2); clipxmax = clipx + COx; if (clipxmax > COLNO) { clipxmax = COLNO; clipx = clipxmax - COx; } clipy = max(0, y - LIx / 2); clipymax = clipy + LIx; if (clipymax > ROWNO) { clipymax = ROWNO; clipy = clipymax - LIx; } clip_saved_level = u.uz; /* save as new current level */ } if (x <= clipx + xclipbord) { clipx = max(0, x - (clipxmax - clipx) / 2); clipxmax = clipx + COx; } else if (x > clipxmax - xclipbord) { clipxmax = min(COLNO, x + (clipxmax - clipx) / 2); clipx = clipxmax - COx; } if (y <= clipy + yclipbord) { clipy = max(0, y - (clipymax - clipy) / 2); clipymax = clipy + LIx; } else if (y > clipymax - yclipbord) { clipymax = min(ROWNO, y + (clipymax - clipy) / 2); clipy = clipymax - LIx; } reclip = 1; if (clipx != oldx || clipy != oldy || clipxmax != oldxmax || clipymax != oldymax) { struct Window *w = amii_wins[WIN_MAP]->win; struct RastPort *rp = w->RPort; int dx = clipx - oldx; int dy = clipy - oldy; int scrx, scry; /* tile pixel dimensions */ int halfW, halfH; /* half viewport in tiles */ if (Is_rogue_level(&u.uz)) { scrx = rp->TxWidth; scry = rp->TxHeight; } else { scrx = mxsize; scry = mysize; } halfW = COx / 2; halfH = LIx / 2; /* Erase the map cursor before shifting pixels, otherwise the old cursor position leaves a COMPLEMENT artifact on screen. */ if (WIN_MAP != WIN_ERR) cursor_off(WIN_MAP); /* Large jumps (teleport, level change): just redraw everything. */ if (abs(dx) > halfW || abs(dy) > halfH || scrollcnt != SCROLLCNT) { { int savedAPen = rp->FgPen; int savedDrMd = rp->DrawMode; SetAPen(rp, amii_otherBPen); SetDrMd(rp, JAM1); RectFill(rp, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); SetAPen(rp, savedAPen); SetDrMd(rp, savedDrMd); } redraw_map(FALSE); } else { /* Flush pending glyphs — they reference old clip coords */ flush_glyph_buffer(w); /* Hardware-blit the viewport by the scroll delta */ ScrollRaster(rp, dx * scrx, dy * scry, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); /* Redraw only the exposed strip(s) */ if (dx > 0) redraw_map_region(clipxmax - dx, clipy, clipxmax, clipymax - 1); else if (dx < 0) redraw_map_region(clipx, clipy, clipx - dx, clipymax - 1); if (dy > 0) redraw_map_region(clipx, clipymax - dy, clipxmax, clipymax - 1); else if (dy < 0) redraw_map_region(clipx, clipy, clipxmax, clipy - dy - 1); flush_glyph_buffer(w); } } reclip = 0; #endif } void flushIDCMP(struct MsgPort *port) { struct Message *msg; while (msg = GetMsg(port)) ReplyMsg(msg); }