text: /* NetHack 3.6	winchar.c	$NHDT-Date: 1432512795 2015/05/25 00:13:15 $  $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */
  /*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992	  */
  /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993	  */
  /*    Copyright (c) Gregg Wonderly, Naperville Illinois, 1994.		*/
  /*    NetHack may be freely redistributed.  See license for details.	*/
  
  #include <exec/types.h>
  #include <libraries/iffparse.h>
  #include <graphics/scale.h>
  #ifndef _DCC
  #include <proto/iffparse.h>
  #endif
  
  #ifdef TESTING
  #include "hack.h"
  #else
  #include "NH:src/tile.c"
  #endif
  
  #include "NH:win/share/tile.h"
  
  #include "NH:sys/amiga/windefs.h"
  #include "NH:sys/amiga/winext.h"
  #include "NH:sys/amiga/winproto.h"
  
  #ifdef OPT_DISPMAP
  #define DISPMAP /* use display_map() from dispmap.s */
  #endif
  
  /* NH:sys/amiga/winvchar.c */
  int main(int, char **);
  struct BitMap *MyAllocBitMap(int, int, int, long);
  void MyFreeBitMap(struct BitMap *);
  void FreeImageFiles(char **, struct BitMap **);
  void amiv_flush_glyph_buffer(struct Window *);
  void amiv_lprint_glyph(winid, int, int);
  void amii_lprint_glyph(winid, int, int);
  void amiv_start_glyphout(winid);
  void amii_end_glyphout(winid);
  void SetMazeType(MazeType);
  int GlyphToIcon(int);
  void amii_start_glyphout(winid);
  void amii_end_glyphout(winid);
  void amii_flush_glyph_buffer(struct Window *);
  
  int amii_extraplanes = 0;
  extern int reclip;
  
  struct BitMap *MyAllocBitMap(int xsize, int ysize, int depth, long mflags);
  void MyFreeBitMap(struct BitMap *bmp);
  
  #ifdef DISPMAP
  extern void display_map(struct Window *);
  #endif
  
  /*
   *  These values will be available from tile.c source
   *
   * #define MAXMONTILE 335
   * #define MAXOBJTILE 722
   * #define MAXOTHTILE 841
   */
  
  #define IMGROWS 12
  #define IMGCOLUMNS 20
  #define IMGPAGESIZE (IMGROWS * IMGCOLUMNS)
  
  #define ID_BMAP MAKE_ID('B', 'M', 'A', 'P') /* The type of form we use */
  #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* The ILBM bitmap header */
  #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* The ILBM camg (ignored) */
  #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* Standard ILBM color map */
  #define ID_PLNE MAKE_ID('P', 'L', 'N', 'E') /* The plane data */
  #define ID_PDAT MAKE_ID('P', 'D', 'A', 'T') /* The PDAT structure below */
  
  struct PDAT pictdata;
  
  #define NUMTILEIMAGES 3
  char *tileimages[] = {
  #define TBLMONTILE 0
      "NetHack:tiles/monsters.iff",
  #define TBLOBJTILE 1
      "NetHack:tiles/objects.iff",
  #define TBLOTHTILE 2
      "NetHack:tiles/other.iff", 0,
  };
  
  struct BitMap *ifftimg[NUMTILEIMAGES], *tile;
  
  #ifdef TESTING
  short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 };
  main(int argc, char **argv)
  {
      BitMapHeader bmhd;
      struct IntuiMessage *imsg;
      long code, class;
      char buf[100];
      int i, x, y, tbl, done = 0, num;
      struct Window *w;
      struct Screen *scr;
  
      bmhd = ReadTileImageFiles();
  
      scr = OpenScreenTags(
          NULL, SA_Depth, pictdata.nplanes + amii_extraplanes, SA_DisplayID,
          DBLNTSC_MONITOR_ID | HIRESLACE_KEY, SA_Overscan, OSCAN_TEXT, SA_Top,
          0, SA_Left, 0, SA_Width, STDSCREENWIDTH, SA_Height, STDSCREENHEIGHT,
          SA_Type, CUSTOMSCREEN, SA_DetailPen, 0, SA_BlockPen, 1, SA_Title,
          "NetHack Chars", SA_Pens, pens, TAG_DONE);
      if (scr == NULL) {
          printf("no screen\n");
  #undef exit
          exit(1);
      }
  
      w = OpenWindowTags(
          0, WA_CustomScreen, scr, WA_Flags,
          WFLG_DRAGBAR | WFLG_SIZEGADGET | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET,
          WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS,
          WA_Left, 0, WA_Top, scr->WBorTop + 1 + 13, WA_MinWidth, 100,
          WA_MinHeight, 100, WA_MaxWidth, 700, WA_MaxHeight, 1000, WA_Width,
          640, WA_Height, 340, WA_SmartRefresh, TRUE, TAG_DONE);
      if (w) {
          while (!done) {
              for (i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i) {
                  int dx, dy;
                  tbl = i / IMGPAGESIZE;
                  x = i % IMGPAGESIZE;
                  y = x / IMGCOLUMNS;
                  x = x % IMGCOLUMNS;
                  dx = i % (IMGCOLUMNS * 2);
                  dy = i / (IMGCOLUMNS * 2);
                  BltBitMapRastPort(ifftimg[tbl], x * pictdata.xsize,
                                    y * pictdata.ysize, w->RPort,
                                    w->BorderLeft + 1 + dx * pictdata.xsize,
                                    w->BorderTop + 1 + dy * pictdata.ysize,
                                    pictdata.xsize, pictdata.ysize, 0xc0);
              }
              WaitPort(w->UserPort);
              while (imsg = (struct IntuiMessage *) GetMsg(w->UserPort)) {
                  class = imsg->Class;
                  code = imsg->Code;
                  ReplyMsg((struct Message *) imsg);
                  switch (class) {
                  case IDCMP_MOUSEBUTTONS: {
                      x = imsg->MouseX - w->BorderLeft;
                      y = imsg->MouseY - w->BorderTop;
                      num = ((y / pictdata.ysize) * IMGCOLUMNS * 2)
                            + (x / pictdata.xsize);
                      sprintf(buf, "Char #%d", num);
                      SetWindowTitles(w, buf, buf);
                  } break;
                  case IDCMP_CLOSEWINDOW:
                      done = 1;
                      break;
                  }
              }
          }
          CloseWindow(w);
          CloseScreen(scr);
      }
  
      FreeImageFiles(tileimages, ifftimg);
  
      return (0);
  }
  #endif
  
  BitMapHeader
  ReadTileImageFiles()
  {
      char *errstr = NULL;
      BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr);
      if (errstr) {
          panic(errstr);
      }
      return ret;
  }
  
  BitMapHeader
  ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp)
  {
      BitMapHeader *bmhd = NULL, bmhds;
      unsigned char *cmap;
      extern int errno;
      register int i, j;
      struct IFFHandle *iff;
      struct StoredProperty *prop;
  
      IFFParseBase = OpenLibrary("iffparse.library", 0L);
      if (!IFFParseBase) {
          *errstrp = "No iffparse.library";
          return bmhds;
      }
  
      /*
          for( i = 0; filenames[i]; ++i )
              memset( iffimg[i], 0, sizeof( struct BitMap ) );
      */
      for (i = 0; filenames[i]; ++i) {
          iff = AllocIFF();
          if (!iff) {
              FreeImageFiles(filenames, iffimg);
              *errstrp = "can't start IFF processing";
              return bmhds;
          }
          iff->iff_Stream = Open(filenames[i], MODE_OLDFILE);
          if (iff->iff_Stream == 0) {
              char *buf = malloc(100 + strlen(filenames[i]));
              FreeImageFiles(filenames, iffimg);
              sprintf(buf, "Can't open %s: %s", filenames[i], strerror(errno));
              *errstrp = buf;
              return bmhds;
          }
          InitIFFasDOS(iff);
          OpenIFF(iff, IFFF_READ);
          PropChunk(iff, ID_BMAP, ID_BMHD);
          PropChunk(iff, ID_BMAP, ID_CMAP);
          PropChunk(iff, ID_BMAP, ID_CAMG);
          PropChunk(iff, ID_BMAP, ID_PDAT);
          StopChunk(iff, ID_BMAP, ID_PLNE);
          if ((j = ParseIFF(iff, IFFPARSE_SCAN)) != 0) {
              char *buf = malloc(100);
              FreeImageFiles(filenames, iffimg);
              sprintf(buf, "ParseIFF failed for image %d, failure code: %d", i,
                      j);
              *errstrp = buf;
              return bmhds;
          }
  
          if (prop = FindProp(iff, ID_BMAP, ID_BMHD)) {
              bmhd = (BitMapHeader *) prop->sp_Data;
          } else {
              FreeImageFiles(filenames, iffimg);
              CloseIFF(iff);
              Close(iff->iff_Stream);
              FreeIFF(iff);
              *errstrp = "No BMHD CHUNK in file";
              return bmhds;
          }
  
          if (prop = FindProp(iff, ID_BMAP, ID_CMAP)) {
              cmap = prop->sp_Data;
              for (j = 0; j < (1L << bmhd->nPlanes) * 3; j += 3) {
  #if 0
  		/* Some day we will want to use the larger palette
  		 * resolution available under v39 and later.  i.e.
  		 * 32 instead of 12 bits of color.  Ususally this
  		 * just means shifting the color left by 16-20 bits
  		 * depending on what intensity looks best.  Experience
  		 * says that the higher values are better intensities.
  		 *
  		 * For now though we won't do this. The color table
  		 * structure is incompatible with earlier versions of
  		 * intuition.  We would have to do some funny things
  		 * to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS
  		 * UWORD's at run time...  A union would help, but...
  		 */
  		if( IntuitionBase->LibNode.lib_Version >= 39 )
  		{
  		    /* 8 bits of color, so shift to left end. */
  		    amiv_init_map[ j+0 ] = cmap[j+0]<<24;
  		    amiv_init_map[ j+1 ] = cmap[j+1]<<24;
  		    amiv_init_map[ j+2 ] = cmap[j+2]<<24;
  		}
  		else
  #endif
                  {
  /* We can only use 4 bits of the 8 that are stored in the
   * cmap, so mask them and then shift them into position
   * for the UWORD value to store.
   */
  #ifndef TESTING
                      amii_initmap[j / 3] = amiv_init_map[j / 3] =
                          ((cmap[j + 0] >> 4) << 8) | ((cmap[j + 1] >> 4) << 4)
                          | (cmap[j + 2] >> 4);
  #endif
                  }
              }
          } else {
              FreeImageFiles(filenames, iffimg);
              CloseIFF(iff);
              Close(iff->iff_Stream);
              FreeIFF(iff);
              *errstrp = "No CMAP CHUNK in file";
              return bmhds;
          }
  
          if (prop = FindProp(iff, ID_BMAP, ID_PDAT)) {
              struct PDAT *pp;
  
              pp = (struct PDAT *) prop->sp_Data;
              pictdata = *pp;
          } else {
              FreeImageFiles(filenames, iffimg);
              CloseIFF(iff);
              Close(iff->iff_Stream);
              FreeIFF(iff);
              *errstrp = "No PDAT CHUNK in file";
              return bmhds;
          }
  
          iffimg[i] = MyAllocBitMap(bmhd->w, bmhd->h,
                                    pictdata.nplanes + amii_extraplanes,
                                    MEMF_CHIP | MEMF_CLEAR);
          if (iffimg[i] == NULL) {
              char *buf = malloc(80);
              FreeImageFiles(filenames, iffimg);
              sprintf(buf, "Can't allocate bitmap for image %d\n", i);
              *errstrp = buf;
              return bmhds;
          }
          for (j = 0; j < pictdata.nplanes + amii_extraplanes; ++j) {
              ReadChunkBytes(iff, iffimg[i]->Planes[j],
                             RASSIZE(bmhd->w, bmhd->h));
          }
          bmhds = *bmhd;
          CloseIFF(iff);
          Close(iff->iff_Stream);
          FreeIFF(iff);
      }
      CloseLibrary(IFFParseBase);
  
      tile = MyAllocBitMap(pictdata.xsize, pictdata.ysize,
                           pictdata.nplanes + amii_extraplanes,
                           MEMF_CHIP | MEMF_CLEAR);
      if (tile == NULL) {
          FreeImageFiles(filenames, iffimg);
          *errstrp = "Can't allocate tile bitmap for scaling";
      }
      return (bmhds);
  }
  
  struct MyBitMap {
      struct BitMap bm;
      long mflags;
      USHORT xsize, ysize;
  };
  
  struct BitMap *
  MyAllocBitMap(int xsize, int ysize, int depth, long mflags)
  {
      int j;
      struct MyBitMap *bm;
  
      bm = (struct MyBitMap *) alloc(sizeof(*bm));
      if (!bm)
          return (NULL);
  
      bm->xsize = xsize;
      bm->ysize = ysize;
      InitBitMap(&bm->bm, depth, xsize, ysize);
      for (j = 0; j < depth; ++j) {
          if (mflags & MEMF_CHIP)
              bm->bm.Planes[j] = AllocRaster(xsize, ysize);
          else
              bm->bm.Planes[j] = AllocMem(RASSIZE(xsize, ysize), mflags);
  
          if (bm->bm.Planes[j] == 0) {
              MyFreeBitMap(&bm->bm);
              return (NULL);
          }
          if (mflags & MEMF_CLEAR)
              memset(bm->bm.Planes[j], 0, RASSIZE(xsize, ysize));
      }
      return (&bm->bm);
  }
  
  void
  MyFreeBitMap(struct BitMap *bmp)
  {
      int j;
      struct MyBitMap *bm = (struct MyBitMap *) bmp;
  
      for (j = 0; j < bm->bm.Depth; ++j) {
          if (bm->bm.Planes[j]) {
              if (bm->mflags & MEMF_CHIP)
                  FreeRaster(bm->bm.Planes[j], bm->xsize, bm->ysize);
              else
                  FreeMem(bm->bm.Planes[j], RASSIZE(bm->xsize, bm->ysize));
          }
      }
      free(bm);
  }
  
  #ifdef TESTING
  void
  panic(s, a1, a2, a3, a4)
  char *s;
  {
      printf(s, a1, a2, a3, a4);
      putchar('\n');
  }
  long *
  alloc(unsigned int x)
  {
      long *p = (long *) malloc(x);
      if (!p) {
          panic("malloc failed");
          exit(1);
      }
      return p;
  }
  #endif
  
  void
  FreeTileImageFiles()
  {
      FreeImageFiles(tileimages, ifftimg);
  }
  
  void
  FreeImageFiles(char **filenames, struct BitMap **img)
  {
      register int i;
  
      for (i = 0; filenames[i]; ++i) {
          if (img[i])
              MyFreeBitMap(img[i]);
      }
  
      /* REALLY ugly hack alert! */
      if (tile && img == ifftimg)
          MyFreeBitMap(tile);
  }
  
  #ifndef TESTING
  /*
   * Define some stuff for our special glyph drawing routines
   */
  unsigned short glyph_node_index, glyph_buffer_index;
  #define NUMBER_GLYPH_NODES 80
  #define GLYPH_BUFFER_SIZE 512
  struct amiv_glyph_node {
      short odstx, odsty;
      short srcx, srcy, dstx, dsty;
      struct BitMap *bitmap;
  };
  struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES];
  static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE];
  
  void
  flush_glyph_buffer(vw)
  struct Window *vw;
  {
      if (WINVERS_AMIV)
          amiv_flush_glyph_buffer(vw);
      else
          amii_flush_glyph_buffer(vw);
  }
  
  /*
   * Routine to flush whatever is buffered
   */
  void
  amiv_flush_glyph_buffer(vw)
  struct Window *vw;
  {
  #if !defined(DISPMAP) || defined(OPT_DISPMAP)
      int xsize, ysize, x, y;
      struct BitScaleArgs bsa;
      struct BitScaleArgs bsm;
      struct RastPort rast;
      struct Window *w = NULL;
      struct BitMap *imgbm = 0, *bm = 0;
      int i, k;
      int scaling_needed;
      register struct RastPort *rp = vw->RPort;
  #endif
  
      /* If nothing is buffered, return before we do anything */
      if (glyph_node_index == 0)
          return;
  
      cursor_off(WIN_MAP);
      amiv_start_glyphout(WIN_MAP);
  
  #ifdef OPT_DISPMAP
      if (sysflags.fast_map) {
  #endif
  #ifdef DISPMAP
          display_map(vw);
  #endif
  #ifdef OPT_DISPMAP
      } else {
  #endif
  #if !defined(DISPMAP) || defined(OPT_DISPMAP)
          /* XXX fix indent */
          /* This is a dynamic value based on this relationship. */
          scaling_needed =
              (pictdata.xsize != mxsize || pictdata.ysize != mysize);
  
          /* If overview window is up, set up to render the correct scale there
           */
          if (WIN_OVER != WIN_ERR && (w = amii_wins[WIN_OVER]->win) != NULL) {
              InitRastPort(&rast);
  
              /* Calculate the x and y size of each tile for a ROWNO by COLNO
               * map */
              xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO;
              ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO;
  
              /* Get a chip memory bitmap to blit out of */
              bm = MyAllocBitMap(pictdata.xsize, pictdata.ysize,
                                 pictdata.nplanes + amii_extraplanes,
                                 MEMF_CLEAR | MEMF_CHIP);
              if (bm == NULL) {
                  amii_putstr(
                      WIN_MESSAGE, 0,
                      "Can't allocate bitmap for scaling overview window");
              }
  
              rast.BitMap = bm;
  
              memset(&bsa, 0, sizeof(bsa));
              bsa.bsa_SrcX = bsa.bsa_SrcY = 0;
              bsa.bsa_SrcBitMap = tile;
              bsa.bsa_SrcWidth = pictdata.xsize;
              bsa.bsa_SrcHeight = pictdata.ysize;
              bsa.bsa_XSrcFactor = pictdata.xsize;
              bsa.bsa_YSrcFactor = pictdata.ysize;
              bsa.bsa_DestX = 0;
              bsa.bsa_DestY = 0;
              bsa.bsa_DestWidth = xsize;
              bsa.bsa_DestHeight = ysize;
              bsa.bsa_XDestFactor = xsize;
              bsa.bsa_YDestFactor = ysize;
              bsa.bsa_DestBitMap = bm;
          }
  
          if (scaling_needed) {
              /* Fill in scaling data for map rendering */
              memset(&bsm, 0, sizeof(bsm));
              bsm.bsa_SrcX = bsm.bsa_SrcY = 0;
              bsm.bsa_SrcBitMap = tile;
  
              bsm.bsa_SrcWidth = pictdata.xsize;
              bsm.bsa_SrcHeight = pictdata.ysize;
  
              bsm.bsa_XSrcFactor = pictdata.xsize;
              bsm.bsa_YSrcFactor = pictdata.ysize;
  
              bsm.bsa_DestWidth = mxsize;
              bsm.bsa_DestHeight = mysize;
  
              bsm.bsa_XDestFactor = mxsize;
              bsm.bsa_YDestFactor = mysize;
              bsm.bsa_DestBitMap = rp->BitMap;
              bsm.bsa_DestY = bsm.bsa_DestX = 0;
  
              imgbm = MyAllocBitMap(mxsize, mysize,
                                    pictdata.nplanes + amii_extraplanes,
                                    MEMF_CLEAR | MEMF_CHIP);
              if (imgbm == NULL) {
                  amii_putstr(WIN_MESSAGE, 0,
                              "Can't allocate scaling bitmap for map window");
              } else
                  bsm.bsa_DestBitMap = imgbm;
          }
  
          /* Go ahead and start dumping the stuff */
          for (i = 0; i < glyph_node_index; ++i) {
              /* Do it */
              register int offx, offy, j;
              struct BitMap *nodebm = amiv_g_nodes[i].bitmap;
  
              /* Get the unclipped coordinates */
              x = amiv_g_nodes[i].odstx;
              y = amiv_g_nodes[i].odsty;
  
              /* If image is not in CHIP. copy each plane into tile line by line
               */
  
              offx = amiv_g_nodes[i].srcx / 8; /* 8 is bits per byte */
              offy = amiv_g_nodes[i].srcy * nodebm->BytesPerRow;
              for (j = 0; j < pictdata.nplanes + amii_extraplanes; ++j) {
                  for (k = 0; k < pictdata.ysize; ++k) {
                      /* For a 16x16 tile, this could just be short assignments,
                       * but
                       * this code is generalized to handle any size tile
                       * image...
                       */
                      memcpy(tile->Planes[j] + ((k * pictdata.ysize) / 8),
                             nodebm->Planes[j] + offx + offy
                                 + (nodebm->BytesPerRow * k),
                             pictdata.ysize / 8);
                  }
              }
  
              if (!clipping || (x >= clipx && y >= clipy && x < clipxmax
                                && y < clipymax)) {
                  /* scaling is needed, do it */
                  if (scaling_needed) {
                      BitMapScale(&bsm);
                      BltBitMapRastPort(imgbm, 0, 0, rp, amiv_g_nodes[i].dstx,
                                        amiv_g_nodes[i].dsty, mxsize, mysize,
                                        0xc0);
                  } else {
                      BltBitMapRastPort(tile, 0, 0, rp, amiv_g_nodes[i].dstx,
                                        amiv_g_nodes[i].dsty, pictdata.xsize,
                                        pictdata.ysize, 0xc0);
                  }
              }
              /* Draw the overview window unless we are scrolling the map raster
               * around */
              if (bm && w && reclip != 2) {
                  BitMapScale(&bsa);
                  BltBitMapRastPort(
                      rast.BitMap, 0, 0, w->RPort,
                      w->BorderLeft + amiv_g_nodes[i].odstx * xsize,
                      w->BorderTop + amiv_g_nodes[i].odsty * ysize, xsize,
                      ysize, 0xc0);
              }
          }
  
          if (imgbm)
              MyFreeBitMap(imgbm);
          if (bm)
              MyFreeBitMap(bm);
  #endif /* DISPMAP */
  #ifdef OPT_DISPMAP
      }
  #endif
  
      amii_end_glyphout(WIN_MAP);
  
      /* Clean up */
      glyph_node_index = glyph_buffer_index = 0;
  }
  
  /*
   * Glyph buffering routine.  Called instead of WindowPuts().
   */
  void
  amiv_lprint_glyph(window, color_index, glyph)
  winid window;
  int color_index, glyph;
  {
      int base;
      struct amii_WinDesc *cw;
      struct Window *w;
      int curx;
      int cury;
      int tbl, icon;
      register int xoff, yoff;
  
      /* Get the real icon index */
      if (glyph != NO_GLYPH)
          icon = GlyphToIcon(glyph);
  
      if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL)
          panic("bad winid in amiv_lprint_glyph: %d", window);
  
      w = cw->win;
  
      if (glyph != NO_GLYPH && glyph < 10000) {
          /* decide on which image has the needed picture */
          if (icon <= MAXMONTILE) {
              tbl = TBLMONTILE;
              base = 0;
          } else if (icon <= MAXOBJTILE) {
              tbl = TBLOBJTILE;
              base = MAXMONTILE + 1;
          } else if (icon <= MAXOTHTILE) {
              tbl = TBLOTHTILE;
              base = MAXOBJTILE + 1;
          } else
              panic("Bad icon #%d, glyph #%d, only %d icons known\n", icon,
                    glyph, MAXOTHTILE);
  
          /* Get the relative offset in the page */
  
          /* How many pixels to account for y distance down */
          yoff = ((icon - base) / pictdata.across) * pictdata.ysize;
  
          /* How many pixels to account for x distance across */
          xoff = ((icon - base) % pictdata.across) * pictdata.xsize;
      }
  
      if (glyph >= 10000) {
          /* Run a single ASCII character out to the rastport right now */
          char c = glyph - 10000;
          int xxx, xxy;
          struct RastPort *rp = w->RPort;
  
          Move(rp, xxx = (((cw->curx - clipx) * rp->TxWidth) + w->BorderLeft),
               xxy = (w->BorderTop + (((cw->cury - clipy) + 1) * rp->TxHeight)
                      + 1));
          Text(rp, &c, 1);
          /* XXX this shouldn't be necessary: */
          if (cw->cursx == xxx && cw->cursy == xxy) {
              cw->wflags &= ~FLMAP_CURSUP;
          }
          cw->curx += rp->TxWidth; /* keep things in sync */
          return;
      }
  
      if (cw->type == NHW_MAP) {
          curx = cw->curx - clipx;
          cury = cw->cury - clipy;
  
          /* See if we're out of glyph nodes */
          if (glyph_node_index >= NUMBER_GLYPH_NODES)
              amiv_flush_glyph_buffer(w);
  
          /* Fill in the node. */
          amiv_g_nodes[glyph_node_index].dsty =
              min(w->BorderTop + (cury * mysize), w->Height - 1);
  
  #ifdef OPT_DISPMAP
          if (sysflags.fast_map) {
  #endif /* keni */
  #ifdef DISPMAP
              /* display_map() needs byte-aligned destinations, and we don't
               * want to
               * overwrite the window border.
               */
              amiv_g_nodes[glyph_node_index].dstx =
                  (w->BorderLeft + 8 + (curx * mxsize)) & -8;
  #endif
  #ifdef OPT_DISPMAP
          } else {
  #endif
  #if !defined(DISPMAP) || defined(OPT_DISPMAP)
              amiv_g_nodes[glyph_node_index].dstx =
                  min(w->BorderLeft + (curx * mxsize), w->Width - 1);
  #endif
  #ifdef OPT_DISPMAP
          }
  #endif
          amiv_g_nodes[glyph_node_index].odsty = cw->cury;
          amiv_g_nodes[glyph_node_index].odstx = cw->curx;
          amiv_g_nodes[glyph_node_index].srcx = xoff;
          amiv_g_nodes[glyph_node_index].srcy = yoff;
          amiv_g_nodes[glyph_node_index].bitmap = ifftimg[tbl];
          ++glyph_node_index;
      } else {
          /* Do it */
          register int j, k, x, y, apen;
          struct RastPort *rp = w->RPort;
          x = rp->cp_x - pictdata.xsize - 3;
  #ifdef OPT_DISPMAP
          if (sysflags.fast_map) {
  #endif
  #ifdef DISPMAP
              x &= -8;
              if (x == 0)
                  x = 8;
  #endif
  #ifdef OPT_DISPMAP
          }
  #endif
  
          y = rp->cp_y - pictdata.ysize + 1;
  
          if (glyph != NO_GLYPH) {
              struct BitMap *bm = ifftimg[tbl];
  
              /* 8 bits per byte */
              xoff /= 8;
              yoff *= bm->BytesPerRow;
              for (j = 0; j < pictdata.nplanes; ++j) {
                  for (k = 0; k < pictdata.ysize; ++k) {
                      memcpy(tile->Planes[j] + ((k * pictdata.ysize) / 8),
                             bm->Planes[j] + xoff + yoff
                                 + (bm->BytesPerRow * k),
                             pictdata.ysize / 8);
                  }
              }
  
              BltBitMapRastPort(tile, 0, 0, rp, x, y, pictdata.xsize,
                                pictdata.ysize, 0xc0);
  
              apen = rp->FgPen;
              SetAPen(rp, sysflags.amii_dripens[SHINEPEN]);
              Move(rp, x - 1, y + pictdata.ysize);
              Draw(rp, x - 1, y - 1);
              Draw(rp, x + pictdata.xsize, y - 1);
              SetAPen(rp, sysflags.amii_dripens[SHADOWPEN]);
              Move(rp, x + pictdata.xsize, y);
              Draw(rp, x + pictdata.xsize, y + pictdata.ysize);
              Draw(rp, x, y + pictdata.ysize);
              SetAPen(rp, apen);
          } else if (x > w->BorderLeft) {
              int apen, bpen;
              apen = rp->FgPen;
              bpen = rp->BgPen;
              SetAPen(rp, amii_menuBPen);
              SetBPen(rp, amii_menuBPen);
              RectFill(rp, x - 1, y - 1, x + pictdata.xsize,
                       y + pictdata.ysize);
              SetAPen(rp, apen);
              SetBPen(rp, bpen);
          }
      }
  }
  
  /*
   * Define some variables which will be used to save context when toggling
   * back and forth between low level text and console I/O.
   */
  static long xsave, ysave, modesave, apensave, bpensave;
  static int usecolor;
  
  /*
   * The function is called before any glyphs are driven to the screen.  It
   * removes the cursor, saves internal state of the window, then returns.
   */
  
  void
  amiv_start_glyphout(window)
  winid window;
  {
      struct amii_WinDesc *cw;
      struct Window *w;
  
      if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL)
          panic("bad winid %d in start_glyphout()", window);
  
      if (cw->wflags & FLMAP_INGLYPH)
          return;
  
      if (!(w = cw->win))
          panic("bad winid %d, no window ptr set", window);
  
      /*
       * Save the context of the window
       */
      xsave = w->RPort->cp_x;
      ysave = w->RPort->cp_y;
      modesave = w->RPort->DrawMode;
      apensave = w->RPort->FgPen;
      bpensave = w->RPort->BgPen;
  
      /*
       * Set the mode, and be done with it
       */
      usecolor = iflags.use_color;
      iflags.use_color = FALSE;
      cw->wflags |= FLMAP_INGLYPH;
  }
  
  /*
   * General cleanup routine -- flushes and restores cursor
   */
  void
  amii_end_glyphout(window)
  winid window;
  {
      struct amii_WinDesc *cw;
      struct Window *w;
  
      if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL)
          panic("bad window id %d in amii_end_glyphout()", window);
  
      if ((cw->wflags & FLMAP_INGLYPH) == 0)
          return;
      cw->wflags &= ~(FLMAP_INGLYPH);
  
      if (!(w = cw->win))
          panic("bad winid %d, no window ptr set", window);
  
      /*
       * Clean up whatever is left in the buffer
       */
      iflags.use_color = usecolor;
  
      /*
       * Reset internal data structs
       */
      SetAPen(w->RPort, apensave);
      SetBPen(w->RPort, bpensave);
      SetDrMd(w->RPort, modesave);
  
      Move(w->RPort, xsave, ysave);
  }
  
  static maze_type = COL_MAZE_BRICK;
  
  void
  SetMazeType(MazeType t)
  {
      maze_type = t;
  }
  
  int
  GlyphToIcon(int glyph)
  {
      if (glyph > 10000)
          return glyph;
      return (glyph2tile[glyph]);
  }
  #endif
  
  #ifdef AMII_GRAPHICS
  #ifdef TESTING
  /*
   * Define some stuff for our special glyph drawing routines
   */
  static unsigned short glyph_node_index, glyph_buffer_index;
  #define NUMBER_GLYPH_NODES 80
  #define GLYPH_BUFFER_SIZE 512
  #endif /* TESTING */
  
  struct amii_glyph_node {
      short x;
      short y;
      short len;
      unsigned char bg_color;
      unsigned char fg_color;
      char *buffer;
  };
  static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES];
  static char amii_glyph_buffer[GLYPH_BUFFER_SIZE];
  
  #ifdef TEXTCOLOR
  /*
   * Map our amiga-specific colormap into the colormap specified in color.h.
   * See winami.c for the amiga specific colormap.
   */
  
  int foreg[AMII_MAXCOLORS] = {
      0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0
  };
  int backg[AMII_MAXCOLORS] = {
      1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1
  };
  #if 0
  #define CLR_BLACK 0
  #define CLR_RED 1
  #define CLR_GREEN 2
  #define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */
  #define CLR_BLUE 4
  #define CLR_MAGENTA 5
  #define CLR_CYAN 6
  #define CLR_GRAY 7 /* low-intensity white */
  #define NO_COLOR 8
  #define CLR_ORANGE 9
  #define CLR_BRIGHT_GREEN 10
  #define CLR_YELLOW 11
  #define CLR_BRIGHT_BLUE 12
  #define CLR_BRIGHT_MAGENTA 13
  #define CLR_BRIGHT_CYAN 14
  #define CLR_WHITE 15
  #define CLR_MAX 16
  #endif
  #endif
  
  #ifndef TESTING
  /*
   * Begin Revamped Text display routines
   *
   * Up until version 3.1, the only method for displaying text on the playing
   * field was by using the console.device.  This was nice for a number of
   * reasons, the most signifigant of which was a lot of the nuts and bolts was
   * done for you via escape sequences interpreted by said device.  This did
   * not come without a price however.  And that price was speed. It has now
   * come to a point where the speed has now been deemed unacceptable.
   *
   * The following series of routines are designed to drop into the current
   * nethack display code, using hooks provided for such a measure. It works
   * on similar principals as the WindowPuts(), buffering I/O internally
   * until either an explicit flush or internal buffering is exceeded, thereby
   * forcing the flush.  The output (or glyphs) does not go to the
   * console.device, however.  It is driven directly to the rasterport of the
   * nethack window via the low-level Text() calls, increasing the speed by
   * a very signifigant factor.
   */
  /*
   * Routine to simply flush whatever is buffered
   */
  void
  amii_flush_glyph_buffer(w)
  struct Window *w;
  {
      short i, x, y;
      register struct RastPort *rp = w->RPort;
  
      /* If nothing is buffered, return before we do anything */
      if (glyph_node_index == 0)
          return;
  
      cursor_off(WIN_MAP);
      amii_start_glyphout(WIN_MAP);
  
      /* Set up the drawing mode */
      SetDrMd(rp, JAM2);
  
      /* Go ahead and start dumping the stuff */
      for (i = 0; i < glyph_node_index; ++i) {
          /* These coordinate calculations must be synced with the
           * code in amii_curs() in winfuncs.c.  curs_on_u() calls amii_curs()
           * to draw the cursor on top of the player
           */
          y = w->BorderTop + (amii_g_nodes[i].y - 2) * rp->TxHeight
              + rp->TxBaseline + 1;
          x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft;
  
          /* Move pens to correct location */
          Move(rp, (long) x, (long) y);
  
          /* Setup the colors */
          SetAPen(rp, (long) amii_g_nodes[i].fg_color);
          SetBPen(rp, (long) amii_g_nodes[i].bg_color);
  
          /* Do it */
          Text(rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len);
      }
  
      amii_end_glyphout(WIN_MAP);
      /* Clean up */
      glyph_node_index = glyph_buffer_index = 0;
  }
  void
  amiga_print_glyph(window, color_index, glyph)
  winid window;
  int color_index, glyph;
  {
      if (WINVERS_AMIV)
          amiv_lprint_glyph(window, color_index, glyph);
      else
          amii_lprint_glyph(window, color_index, glyph);
  }
  
  /*
   * Glyph buffering routine.  Called instead of WindowPuts().
   */
  void
  amii_lprint_glyph(window, color_index, glyph)
  winid window;
  int color_index, glyph;
  {
      int fg_color, bg_color;
      struct amii_WinDesc *cw;
      struct Window *w;
      int curx;
      int cury;
  
      if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL)
          panic("bad winid in amii_lprint_glyph: %d", window);
  
      w = cw->win;
      curx = cw->curx;
      cury = cw->cury;
  
  #ifdef TEXTCOLOR
      fg_color = foreg[color_index];
      bg_color = backg[color_index];
  #else
      fg_color = 1;
      bg_color = 0;
  #endif /* TEXTCOLOR */
  
      /* See if we have enough character buffer space... */
      if (glyph_buffer_index >= GLYPH_BUFFER_SIZE)
          amii_flush_glyph_buffer(w);
  
      /*
       * See if we can append it to the current active node of glyph buffer. It
       * must satisfy the following conditions:
       *
       *    * background colors are the same, AND
       *    * foreground colors are the same, AND
       *    * they are precisely side by side
       */
      if ((glyph_buffer_index != 0)
          && (fg_color == amii_g_nodes[glyph_node_index - 1].fg_color)
          && (bg_color == amii_g_nodes[glyph_node_index - 1].bg_color)
          && (amii_g_nodes[glyph_node_index - 1].x
                  + amii_g_nodes[glyph_node_index - 1].len
              == curx) && (amii_g_nodes[glyph_node_index - 1].y == cury)) {
          /*
           * Add it to the end of the buffer
           */
          amii_glyph_buffer[glyph_buffer_index++] = glyph;
          amii_g_nodes[glyph_node_index - 1].len++;
      } else {
          /* See if we're out of glyph nodes */
          if (glyph_node_index >= NUMBER_GLYPH_NODES)
              amii_flush_glyph_buffer(w);
          amii_g_nodes[glyph_node_index].len = 1;
          amii_g_nodes[glyph_node_index].x = curx;
          amii_g_nodes[glyph_node_index].y = cury;
          amii_g_nodes[glyph_node_index].fg_color = fg_color;
          amii_g_nodes[glyph_node_index].bg_color = bg_color;
          amii_g_nodes[glyph_node_index].buffer =
              &amii_glyph_buffer[glyph_buffer_index];
          amii_glyph_buffer[glyph_buffer_index] = glyph;
          ++glyph_buffer_index;
          ++glyph_node_index;
      }
  }
  #endif /* !TESTING */
  
  #ifdef TESTING
  /*
   * Define some variables which will be used to save context when toggling
   * back and forth between low level text and console I/O.
   */
  static long xsave, ysave, modesave, apensave, bpensave;
  static int usecolor;
  #endif /* TESTING */
  
  #ifndef TESTING
  /*
   * The function is called before any glyphs are driven to the screen.  It
   * removes the cursor, saves internal state of the window, then returns.
   */
  
  void
  amii_start_glyphout(window)
  winid window;
  {
      struct amii_WinDesc *cw;
      struct Window *w;
  
      if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL)
          panic("bad winid %d in start_glyphout()", window);
  
      if (cw->wflags & FLMAP_INGLYPH)
          return;
  
      if (!(w = cw->win))
          panic("bad winid %d, no window ptr set", window);
  
      /*
       * Save the context of the window
       */
      xsave = w->RPort->cp_x;
      ysave = w->RPort->cp_y;
      modesave = w->RPort->DrawMode;
      apensave = w->RPort->FgPen;
      bpensave = w->RPort->BgPen;
  
      /*
       * Set the mode, and be done with it
       */
      usecolor = iflags.use_color;
      iflags.use_color = FALSE;
      cw->wflags |= FLMAP_INGLYPH;
  }
  #endif /* !TESTING */
  
  #if 0
  /*
   * General cleanup routine -- flushes and restores cursor
   */
  void
  amii_end_glyphout(window)
      winid window;
  {
      struct amii_WinDesc *cw;
      struct Window *w;
  
      if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
  	panic("bad window id %d in amii_end_glyphout()", window );
  
      if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
  	return;
      cw->wflags &= ~(FLMAP_INGLYPH);
  
      if( !(w = cw->win ) )
  	panic( "bad winid %d, no window ptr set", window );
  
      /*
       * Clean up whatever is left in the buffer
       */
      iflags.use_color = usecolor;
  
      /*
       * Reset internal data structs
       */
      SetAPen(w->RPort, apensave);
      SetBPen(w->RPort, bpensave);
      SetDrMd(w->RPort, modesave);
  
      Move(w->RPort, xsave, ysave);
  }
  #endif
  #endif
  
  #ifndef TESTING
  #ifdef OPT_DISPMAP
  /* don't use dispmap unless x & y are 8,16,24,32,48 and equal */
  void
  dispmap_sanity()
  {
      if (mxsize != mysize || dispmap_sanity1(mxsize)
          || dispmap_sanity1(mysize)) {
          sysflags.fast_map = 0;
      }
  }
  int
  dispmap_sanity1(x)
  int x;
  {
      static unsigned char valid[] = { 8, 16, 24, 32, 48, 0 };
      return !!strchr(valid, x);
  }
  #endif /* OPT_DISPMAP */
  #endif /* TESTING */
  