home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / nethack-3.1 / sys / amiga / amiwind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-22  |  20.7 KB  |  894 lines

  1. /*    SCCS Id: @(#)amiwind.c     3.1    93/01/08
  2. /*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992      */
  3. /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993      */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. /*
  7.  *  Here is some very Amiga specific stuff, dealing with
  8.  *  screens, windows, menus, and input via IntuiMessages.
  9.  */
  10.  
  11. #include "hack.h"
  12. #include "winami.h"
  13.  
  14. /* Have to undef CLOSE as display.h and intuition.h both use it */
  15. #undef CLOSE
  16.  
  17. #include <exec/types.h>
  18. #include <exec/alerts.h>
  19. #include <exec/io.h>
  20. #include <exec/devices.h>
  21. #include <devices/console.h>
  22. #include <devices/conunit.h>
  23. #include <intuition/intuition.h>
  24. #include <intuition/intuitionbase.h>
  25. #include <libraries/dosextens.h>
  26.  
  27. #ifdef __SASC
  28. # undef COUNT
  29.  
  30. # include <dos.h>       /* for __emit */
  31. # include <string.h>
  32. # include <proto/dos.h>
  33. # include <proto/exec.h>
  34.  
  35. /* kludge - see amirip for why */
  36. # undef red
  37. # undef green
  38. # undef blue
  39. # undef index
  40. # include <proto/graphics.h>
  41.  
  42. # include <proto/intuition.h>
  43. # include <proto/diskfont.h>
  44. # include <proto/console.h>
  45. #endif
  46.  
  47. #undef  NULL
  48. #define NULL    0L
  49.  
  50. #include "Amiga:amimenu.c"
  51.  
  52. /*  First, external declarations... */
  53.  
  54. struct Library *ConsoleDevice;
  55.  
  56. #ifdef AZTEC_50
  57. # include <functions.h>
  58. #endif
  59.  
  60. #ifdef  INTUI_NEW_LOOK
  61. #define NewWindow ExtNewWindow
  62. #endif
  63.  
  64. #include "Amiga:winami.p"
  65. #include "Amiga:amiwind.p"
  66. #include "Amiga:amidos.p"
  67.  
  68. static int BufferGetchar(void);
  69. static void ProcessMessage( register struct IntuiMessage *message );
  70.  
  71. #ifdef AMIFLUSH
  72. static struct Message *FDECL(GetFMsg,(struct MsgPort *));
  73. #endif
  74.  
  75. /*  Now our own variables */
  76.  
  77. struct IntuitionBase *IntuitionBase;
  78. struct Screen *HackScreen;
  79. struct Window *pr_WindowPtr;
  80. struct MsgPort *HackPort;
  81. struct IOStdReq ConsoleIO;
  82. char Initialized = 0;
  83. WEVENT lastevent;
  84.  
  85. #ifdef HACKFONT
  86. struct GfxBase *GfxBase;
  87. struct Library *DiskfontBase;
  88. #endif
  89.  
  90. extern struct Library *ConsoleDevice;
  91.  
  92. #define CSI     '\x9b'
  93. #define NO_CHAR     -1
  94. #define RAWHELP     0x5F    /* Rawkey code of the HELP key */
  95.  
  96. #define KBDBUFFER   10
  97. static unsigned char KbdBuffer[KBDBUFFER];
  98. unsigned char KbdBuffered;
  99.  
  100. #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
  101.  
  102. /*
  103.  * Define some stuff for our special glyph drawing routines
  104.  */
  105. static unsigned short glyph_node_index, glyph_buffer_index;
  106. #define NUMBER_GLYPH_NODES  80
  107. #define GLYPH_BUFFER_SIZE   512
  108. struct glyph_node {
  109.     short    x;
  110.     short    y;
  111.     short    len;
  112.     unsigned char   bg_color;
  113.     unsigned char   fg_color;
  114.     char    *buffer;
  115. };
  116. static struct glyph_node g_nodes[NUMBER_GLYPH_NODES];
  117. static char glyph_buffer[GLYPH_BUFFER_SIZE];
  118.  
  119. #ifdef TEXTCOLOR
  120. /*
  121.  * Map our amiga-specific colormap into the colormap specified in color.h.
  122.  * See amiwind.c for the amiga specific colormap.
  123.  */
  124.  
  125. int foreg[16] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
  126. int backg[16] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
  127. #endif
  128.  
  129. #ifdef HACKFONT
  130.  
  131. struct TextFont *HackFont;
  132. UBYTE FontName[] = "NetHack:hack.font";
  133.     /* # chars in "NetHack:": */
  134. #define         SIZEOF_DISKNAME 8
  135.  
  136. #endif
  137.  
  138. struct TextAttr Hack80 = {
  139. #ifdef HACKFONT
  140.     &FontName[SIZEOF_DISKNAME],
  141. #else
  142.     (UBYTE *) "topaz.font",
  143. #endif
  144.     TOPAZ_EIGHTY, FS_NORMAL, FPF_DISKFONT | FPF_ROMFONT
  145. };
  146.  
  147. /*
  148.  * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
  149.  * to close.
  150.  */
  151.  
  152. struct Window *OpenShWindow(nw)
  153. struct NewWindow *nw;
  154. {
  155.     register struct Window *win;
  156.     register ULONG idcmpflags;
  157.  
  158.     if (!HackPort)  /* Sanity check */
  159.     return (struct Window *) 0;
  160.  
  161.     idcmpflags = nw->IDCMPFlags;
  162.     nw->IDCMPFlags = 0;
  163.     if (!(win = OpenWindow((void *)nw)))
  164.     return (struct Window *) 0;
  165.  
  166.     win->UserPort = HackPort;
  167.     ModifyIDCMP(win, idcmpflags);
  168.     return win;
  169. }
  170.  
  171.  
  172. /*
  173.  * Close a window that shared the HackPort IDCMP port.
  174.  */
  175.  
  176. void FDECL(CloseShWindow, (struct Window *));
  177. void CloseShWindow(win)
  178. struct Window *win;
  179. {
  180.     register struct IntuiMessage *msg, *nxt;
  181.  
  182.     if( !HackPort )
  183.     panic("HackPort NULL in CloseShWindow" );
  184.     if (!win)
  185.     return;
  186.  
  187.     Forbid();
  188.     /* Flush all messages for all windows to avoid typeahead and other
  189.      * similar problems...
  190.      */
  191.     while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
  192.     ReplyMsg( (struct Message *) msg );
  193.     KbdBuffered = 0;
  194.     win->UserPort = (struct MsgPort *) 0;
  195.     ModifyIDCMP(win, 0L);
  196.     Permit();
  197.     CloseWindow(win);
  198. }
  199.  
  200. static int BufferGetchar()
  201. {
  202.     register int c;
  203.  
  204.     if (KbdBuffered > 0) {
  205.     c = KbdBuffer[0];
  206.     KbdBuffered--;
  207.     /* Move the remaining characters */
  208.     if( KbdBuffered < sizeof( KbdBuffer ) )
  209.         memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
  210.     return c;
  211.     }
  212.  
  213.     return NO_CHAR;
  214. }
  215.  
  216. /*
  217.  *  This should remind you remotely of DeadKeyConvert, but we are cheating
  218.  *  a bit. We want complete control over the numeric keypad, and no dead
  219.  *  keys... (they are assumed to be on Alted keys).
  220.  *
  221.  *  Also assumed is that the IntuiMessage is of type RAWKEY.  For some
  222.  *  reason, IECODE_UP_PREFIX events seem to be lost when they  occur while
  223.  *  our console window is inactive. This is particulary  troublesome with
  224.  *  qualifier keys... Is this because I never RawKeyConvert those events???
  225.  */
  226.  
  227. int ConvertKey(message)
  228. register struct IntuiMessage *message;
  229. {
  230.     static struct InputEvent theEvent;
  231.     static char       numpad[] = "bjnh.lyku";
  232.     static char  ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
  233.     static char shift_numpad[] = "BJNH.LYKU";
  234.  
  235.     unsigned char buffer[1];
  236.     register int length;
  237.     register ULONG qualifier;
  238.     char numeric_pad, shift, control, alt;
  239.  
  240.     qualifier = message->Qualifier;
  241.  
  242.     control = (qualifier &  IEQUALIFIER_CONTROL) != 0;
  243.     shift   = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
  244.     alt     = (qualifier & (IEQUALIFIER_LALT   | IEQUALIFIER_RALT  )) != 0;
  245.  
  246.     /* Allow ALT to function as a META key ... */
  247.  
  248.     qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
  249.     numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
  250.  
  251.     /*
  252.      *  Shortcut for HELP and arrow keys. I suppose this is allowed.
  253.      *  The defines are in intuition/intuition.h, and the keys don't
  254.      *  serve 'text' input, normally. Also, parsing their escape
  255.      *  sequences is such a mess...
  256.      */
  257.  
  258.     switch (message->Code) {
  259.     case RAWHELP:
  260.         if( alt )
  261.         {
  262.         EditColor();
  263.         return( -1 );
  264.         }
  265.         return( '?' );
  266.         break;
  267.     case CURSORLEFT:
  268.         length = '4';
  269.         numeric_pad = 1;
  270.         goto arrow;
  271.     case CURSORDOWN:
  272.         length = '2';
  273.         numeric_pad = 1;
  274.         goto arrow;
  275.     case CURSORUP:
  276.         length = '8';
  277.         numeric_pad = 1;
  278.         goto arrow;
  279.     case CURSORRIGHT:
  280.         length = '6';
  281.         numeric_pad = 1;
  282.         goto arrow;
  283.     }
  284.  
  285.     theEvent.ie_Class = IECLASS_RAWKEY;
  286.     theEvent.ie_Code = message->Code;
  287.     theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
  288.     theEvent.ie_EventAddress = (APTR) (message->IAddress);
  289.  
  290.     length = RawKeyConvert(&theEvent, (char *)buffer, 
  291.       (long) sizeof(buffer), NULL);
  292.  
  293.     if (length == 1) {   /* Plain ASCII character */
  294.     length = buffer[0];
  295.     /*
  296.      *  If flags.num_pad is set, movement is by 4286.
  297.      *  If not set, translate 4286 into hjkl.
  298.      *  This way, the numeric pad can /always/ be used
  299.      *  for moving, though best results are when it is off.
  300.      */
  301. arrow:
  302.     if (!flags.num_pad && numeric_pad && length >= '1' && length <= '9') {
  303.         length -= '1';
  304.         if (control) {
  305.         length = ctrl_numpad[length];
  306.         } else if (shift) {
  307.         length = shift_numpad[length];
  308.         } else {
  309.         length = numpad[length];
  310.         }
  311.     }
  312.     if (alt)
  313.         length |= 0x80;
  314.     return(length);
  315.     } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
  316.     else
  317.     return( -1 );
  318. }
  319.  
  320. /*
  321.  *  Process an incoming IntuiMessage.
  322.  *  It would certainly look nicer if this could be done using a
  323.  *  PA_SOFTINT message port, but we cannot call RawKeyConvert()
  324.  *  during a software interrupt.
  325.  *  Anyway, kbhit() is called often enough, and usually gets
  326.  *  ahead of input demands, when the user types ahead.
  327.  */
  328.  
  329. static void ProcessMessage(message)
  330. register struct IntuiMessage *message;
  331. {
  332.     int c;
  333.     static int skip_mouse=0;    /* need to ignore next mouse event on
  334.                  * a window activation */
  335.     switch(message->Class) {
  336.     case ACTIVEWINDOW:
  337.     skip_mouse=1;break;
  338.     case MOUSEBUTTONS:
  339.     {
  340.         if(skip_mouse){
  341.         skip_mouse=0;
  342.         break;
  343.         }
  344.         if( message->Code == SELECTDOWN ){
  345.         lastevent.type = WEMOUSE;
  346.         lastevent.u.mouse.x = message->MouseX;
  347.         lastevent.u.mouse.y = message->MouseY;
  348.             /* With shift equals RUN */
  349.         lastevent.u.mouse.qual = (message->Qualifier &
  350.           (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
  351.         }
  352.     }
  353.     break;
  354.  
  355.     case MENUPICK:
  356.     {
  357.         USHORT thismenu;
  358.         struct MenuItem *item;
  359.  
  360.         thismenu = message->Code;
  361.         while (thismenu != MENUNULL) {
  362.         item = ItemAddress(HackMenu, (ULONG) thismenu);
  363.         if (KbdBuffered < KBDBUFFER)
  364.             BufferQueueChar(item->Command); /* Unused: No COMMSEQ */
  365.         thismenu = item->NextSelect;
  366.         }
  367.     }
  368.     break;
  369.  
  370.     case RAWKEY:
  371.     if (!(message->Code & IECODE_UP_PREFIX)){
  372.         /* May queue multiple characters
  373.          * but doesn't do that yet...
  374.          */
  375.         if( ( c = ConvertKey(message) ) > 0 )
  376.         BufferQueueChar( c );
  377.         }
  378.         break;
  379.     }
  380.     ReplyMsg((struct Message *) message);
  381. }
  382.  
  383. /*
  384.  *  Get all incoming messages and fill up the keyboard buffer,
  385.  *  thus allowing Intuition to (maybe) free up the IntuiMessages.
  386.  *  Return when no more messages left, or keyboard buffer half full.
  387.  *  We need to do this since there is no one-to-one correspondence
  388.  *  between characters and incoming messages.
  389.  */
  390.  
  391. int kbhit()
  392. {
  393.     register struct IntuiMessage *message;
  394.     while( KbdBuffered < KBDBUFFER / 2 )
  395.     {
  396. #ifdef AMIFLUSH
  397.     message = (struct IntuiMessage *) GetFMsg(HackPort);
  398. #else
  399.     message = (struct IntuiMessage *) GetMsg(HackPort);
  400. #endif
  401.     if(message)
  402.     {
  403.         ProcessMessage(message);
  404.         if( lastevent.type != WEUNK && lastevent.type != WEKEY )
  405.         break;
  406.     }
  407.     else
  408.         break;
  409.     }
  410.     return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
  411. }
  412.  
  413. /*
  414.  *  Get a character from the keyboard buffer, waiting if not available.
  415.  *  Ignore other kinds of events that happen in the mean time.
  416.  */
  417.  
  418. int WindowGetchar( )
  419. {
  420.     while ((lastevent.type = WEUNK), kbhit() <= 0) {
  421.     WaitPort(HackPort);
  422.     }
  423.     return BufferGetchar();
  424. }
  425.  
  426. WETYPE WindowGetevent()
  427. {
  428.     lastevent.type = WEUNK;
  429.     while (kbhit() == 0)
  430.     {
  431.     WaitPort(HackPort);
  432.     }
  433.  
  434.     if( KbdBuffered )
  435.     {
  436.     lastevent.type = WEKEY;
  437.     lastevent.u.key = BufferGetchar();
  438.     }
  439.     return( lastevent.type );
  440. }
  441.  
  442. /*
  443.  *  Clean up everything. But before we do, ask the user to hit return
  444.  *  when there is something that s/he should read.
  445.  */
  446.  
  447. void CleanUp()
  448. {
  449.     register struct IntuiMessage *msg;
  450.  
  451.     /* Finish closing things up */
  452.  
  453.     amii_raw_print("");
  454.     amii_getret();
  455.  
  456.     ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
  457.     if (ConsoleIO.io_Device)
  458.     CloseDevice( (struct IORequest *)&ConsoleIO );
  459.  
  460.     if (HackPort) {
  461.     Forbid();
  462.     while (msg = (struct IntuiMessage *) GetMsg(HackPort))
  463.         ReplyMsg((struct Message *) msg);
  464.     kill_nhwindows( 1 );
  465.     DeletePort( HackPort );
  466.     HackPort = NULL;
  467.     Permit();
  468.     }
  469.  
  470.     if (HackScreen) {
  471. #ifdef  INTUI_NEW_LOOK
  472.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  473.     {
  474.         while( CloseScreen(HackScreen) == FALSE )
  475.         {
  476.         struct EasyStruct easy =
  477.         {
  478.             sizeof( struct EasyStruct ),
  479.             0,
  480.             "Nethack Problem",
  481.             "Can't Close Screen, Close Remaining Windows",
  482.             "Okay",
  483.         };
  484.         EasyRequest( NULL, &easy, NULL, NULL );
  485.         }
  486.     }
  487. #else
  488.     CloseScreen(HackScreen);
  489. #endif
  490.     HackScreen = NULL;
  491.     }
  492.  
  493. #ifdef HACKFONT
  494.  
  495.     if (HackFont)
  496.     {
  497.     CloseFont(HackFont);
  498.     HackFont = NULL;
  499.     }
  500.  
  501.     if( DiskfontBase )
  502.     {
  503.     CloseLibrary(DiskfontBase);
  504.     DiskfontBase = NULL;
  505.     }
  506. #endif
  507.  
  508.     if (GfxBase) {
  509.     CloseLibrary((struct Library *)GfxBase);
  510.     GfxBase = NULL;
  511.     }
  512.  
  513.     if (IntuitionBase) {
  514.     CloseLibrary((struct Library *)IntuitionBase);
  515.     IntuitionBase = NULL;
  516.     }
  517.  
  518.     Initialized = 0;
  519. }
  520.  
  521. void Abort(rc)
  522. long rc;
  523. {
  524. #ifdef CHDIR
  525.     extern char orgdir[];
  526.     chdir(orgdir);
  527. #endif
  528.     if (Initialized && ConsoleDevice) {
  529.     printf("\n\nAbort with alert code %08lx...\n", rc);
  530.     amii_getret();
  531.     } else
  532.     Alert(rc);
  533. #ifdef __SASC
  534.     {
  535. /*  __emit(0x4afc);     /* illegal instruction */
  536.     __emit(0x40fc);     /* divide by */
  537.     __emit(0x0000);     /*  #0  */
  538.     /* NOTE: don't move CleanUp() above here - */
  539.     /* it is too likely to kill the system     */
  540.     /* before it can get the SnapShot out, if  */
  541.     /* there is something really wrong.    */
  542.     }
  543. #endif
  544.     CleanUp();
  545. #undef exit
  546. #ifdef AZTEC_C
  547.     _abort();
  548. #endif
  549.     exit((int) rc);
  550. }
  551.  
  552. #ifdef AMIFLUSH
  553. /* This routine adapted from AmigaMail IV-37 by Michael Sinz */
  554. static struct Message *
  555. GetFMsg(port)
  556.     struct MsgPort *port;
  557.     {
  558.     struct IntuiMessage *msg,*succ,*succ1;
  559.  
  560.     if(msg=(struct IntuiMessage *)GetMsg(port)){
  561.     if(!flags.amiflush)return((struct Message *)msg);
  562.     if(msg->Class==RAWKEY){
  563.         Forbid();
  564.         succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
  565.         while(succ1=(struct IntuiMessage *)
  566.           (succ->ExecMessage.mn_Node.ln_Succ)){
  567.         if(succ->Class==RAWKEY){
  568.             Remove((struct Node *)succ);
  569.             ReplyMsg((struct Message *)succ);
  570.         }
  571.         succ=succ1;
  572.         }
  573.         Permit();
  574.     }
  575.     }
  576.     return((struct Message *)msg);
  577. }
  578. #endif
  579.  
  580. /*
  581.  * Begin Revamped Text display routines
  582.  *
  583.  * Up until version 3.1, the only method for displaying text on the playing
  584.  * field was by using the console.device.  This was nice for a number of
  585.  * reasons, the most signifigant of which was a lot of the nuts and bolts was
  586.  * done for you via escape sequences interpreted by said device.  This did
  587.  * not come without a price however.  And that price was speed. It has now
  588.  * come to a point where the speed has now been deemed unacceptable.
  589.  *
  590.  * The following series of routines are designed to drop into the current
  591.  * nethack display code, using hooks provided for such a measure. It works
  592.  * on similar principals as the WindowPuts(), buffering I/O internally
  593.  * until either an explicit flush or internal buffering is exceeded, thereby
  594.  * forcing the flush.  The output (or glyphs) does not go to the
  595.  * console.device, however.  It is driven directly to the rasterport of the
  596.  * nethack window via the low-level Text() calls, increasing the speed by
  597.  * a very signifigant factor.
  598.  */
  599. /*
  600.  * Routine to simply flush whatever is buffered
  601.  */
  602. void
  603. flush_glyph_buffer( w )
  604.     struct Window *w;
  605. {
  606.     short i, x, y;
  607.  
  608.     /* If nothing is buffered, return before we do anything */
  609.     if(glyph_node_index == 0)
  610.     return;
  611.  
  612.     cursor_off( WIN_MAP );
  613.     start_glyphout( WIN_MAP );
  614.     /* Set up the drawing mode */
  615.     SetDrMd( w->RPort, JAM2);
  616.  
  617.     /* Go ahead and start dumping the stuff */
  618.     for(i=0; i<glyph_node_index; ++i) {
  619.     /* These coordinate calculations must be synced with the
  620.      * code in curs() in winami.c.  curs_on_u() calls curs()
  621.      * to draw the cursor on top of the player
  622.      */
  623.     y = w->BorderTop + (g_nodes[i].y-1) * w->RPort->TxHeight +
  624.         w->RPort->TxBaseline + 1;
  625.     x = g_nodes[i].x * w->RPort->TxWidth + w->BorderLeft;
  626.  
  627.     /* Move pens to correct location */
  628.     Move(w->RPort, (long)x, (long)y);
  629.  
  630.     /* Setup the colors */
  631.     SetAPen(w->RPort, (long)g_nodes[i].fg_color);
  632.     SetBPen(w->RPort, (long)g_nodes[i].bg_color);
  633.  
  634.     /* Do it */
  635.     Text(w->RPort, g_nodes[i].buffer, g_nodes[i].len);
  636.     }
  637.  
  638.     end_glyphout( WIN_MAP );
  639.     /* Clean up */
  640.     glyph_node_index = glyph_buffer_index = 0;
  641. }
  642.  
  643. /*
  644.  * Glyph buffering routine.  Called instead of WindowPuts().
  645.  */
  646. void
  647. amiga_print_glyph(window,color_index, glyph)
  648.     winid window;
  649.     int color_index, glyph;
  650. {
  651.     int fg_color, bg_color;
  652.     struct WinDesc *cw;
  653.     struct Window *w;
  654.     int curx;
  655.     int cury;
  656.  
  657.     if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
  658.     panic("bad winid in amiga_print_glyph: %d", window );
  659.  
  660.     w = cw->win;
  661.     curx=cw->curx;
  662.     cury=cw->cury;
  663.  
  664. #ifdef TEXTCOLOR
  665.     fg_color = foreg[color_index];
  666.     bg_color = backg[color_index];
  667. #else
  668.     fg_color = 1;
  669.     bg_color = 0;
  670. #endif /* TEXTCOLOR */
  671.  
  672.     /* See if we have enough character buffer space... */
  673.     if(glyph_buffer_index  >= GLYPH_BUFFER_SIZE)
  674.     flush_glyph_buffer( w );
  675.  
  676.     /*
  677.      * See if we can append it to the current active node of glyph buffer. It
  678.      * must satisfy the following conditions:
  679.      *
  680.      *    * background colors are the same, AND
  681.      *    * foreground colors are the same, AND
  682.      *    * they are precisely side by side
  683.      */
  684.     if((glyph_buffer_index != 0) &&
  685.        (fg_color == g_nodes[glyph_node_index-1].fg_color) &&
  686.        (bg_color == g_nodes[glyph_node_index-1].bg_color) &&
  687.        (g_nodes[glyph_node_index-1].x+
  688.     g_nodes[glyph_node_index-1].len == curx) &&
  689.        (g_nodes[glyph_node_index-1].y == cury)) {
  690.     /*
  691.      * Add it to the end of the buffer
  692.      */
  693.     glyph_buffer[glyph_buffer_index++] = glyph;
  694.     g_nodes[glyph_node_index-1].len ++;
  695.      } else {
  696.     /* See if we're out of glyph nodes */
  697.     if(glyph_node_index >= NUMBER_GLYPH_NODES)
  698.         flush_glyph_buffer( w );
  699.     g_nodes[glyph_node_index].len = 1;
  700.     g_nodes[glyph_node_index].x = curx;
  701.     g_nodes[glyph_node_index].y = cury;
  702.     g_nodes[glyph_node_index].fg_color = fg_color;
  703.     g_nodes[glyph_node_index].bg_color = bg_color;
  704.     g_nodes[glyph_node_index].buffer = &glyph_buffer[glyph_buffer_index];
  705.     glyph_buffer[glyph_buffer_index] = glyph;
  706.     ++glyph_buffer_index;
  707.     ++glyph_node_index;
  708.     }
  709. }
  710.  
  711. /*
  712.  * Define some variables which will be used to save context when toggling
  713.  * back and forth between low level text and console I/O.
  714.  */
  715. static long xsave, ysave, modesave, apensave, bpensave;
  716. static int usecolor;
  717.  
  718. /*
  719.  * The function is called before any glyphs are driven to the screen.  It
  720.  * removes the cursor, saves internal state of the window, then returns.
  721.  */
  722.  
  723. void
  724. start_glyphout(window)
  725.     winid window;
  726. {
  727.     struct WinDesc *cw;
  728.     struct Window *w;
  729.  
  730.     if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
  731.     panic( "bad winid %d in start_glyphout()", window );
  732.  
  733.     if( cw->flags & FLMAP_INGLYPH )
  734.     return;
  735.  
  736.     if( !(w = cw->win ) )
  737.     panic( "bad winid %d, no window ptr set", window );
  738.  
  739.     /*
  740.      * Save the context of the window
  741.      */
  742.     xsave = w->RPort->cp_x;
  743.     ysave = w->RPort->cp_y;
  744.     modesave = w->RPort->DrawMode;
  745.     apensave = w->RPort->FgPen;
  746.     bpensave = w->RPort->BgPen;
  747.  
  748.     /*
  749.      * Set the mode, and be done with it
  750.      */
  751.     usecolor = flags.use_color;
  752.     flags.use_color = FALSE;
  753.     cw->flags |= FLMAP_INGLYPH;
  754. }
  755.  
  756. /*
  757.  * General cleanup routine -- flushes and restores cursor
  758.  */
  759. void
  760. end_glyphout(window)
  761.     winid window;
  762. {
  763.     struct WinDesc *cw;
  764.     struct Window *w;
  765.  
  766.     if( ( cw = wins[ window ] ) == (struct WinDesc *)NULL )
  767.     panic("bad window id %d in end_glyphout()", window );
  768.  
  769.     if( ( cw->flags & FLMAP_INGLYPH ) == 0 )
  770.     return;
  771.     cw->flags &= ~(FLMAP_INGLYPH);
  772.  
  773.     if( !(w = cw->win ) )
  774.     panic( "bad winid %d, no window ptr set", window );
  775.  
  776.     /*
  777.      * Clean up whatever is left in the buffer
  778.      */
  779.     flags.use_color = usecolor;
  780.  
  781.     /*
  782.      * Reset internal data structs
  783.      */
  784.     SetAPen(w->RPort, apensave);
  785.     SetBPen(w->RPort, bpensave);
  786.     SetDrMd(w->RPort, modesave);
  787.  
  788.     Move(w->RPort, xsave, ysave);
  789. }
  790.  
  791. struct NewWindow *
  792. DupNewWindow( win )
  793.     struct NewWindow *win;
  794. {
  795.     struct NewWindow *nwin;
  796.     struct Gadget *ngd, *gd, *pgd = NULL;
  797.     struct PropInfo *pip;
  798.     struct StringInfo *sip;
  799.  
  800.     /* Copy the (Ext)NewWindow structure */
  801.  
  802.     nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
  803.     *nwin = *win;
  804.  
  805.     /* Now do the gadget list */
  806.  
  807.     nwin->FirstGadget = NULL;
  808.     for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
  809.     {
  810.     ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
  811.     *ngd = *gd;
  812.     if( gd->GadgetType == STRGADGET )
  813.     {
  814.         sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
  815.         *sip = *((struct StringInfo *)gd->SpecialInfo);
  816.         sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
  817.         *sip->Buffer = 0;
  818.         ngd->SpecialInfo = (APTR)sip;
  819.     }
  820.     else if( gd->GadgetType == PROPGADGET )
  821.     {
  822.         pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
  823.         *pip = *((struct PropInfo *)gd->SpecialInfo);
  824.         ngd->SpecialInfo = (APTR)pip;
  825.     }
  826.     if( pgd )
  827.         pgd->NextGadget = ngd;
  828.     else
  829.         nwin->FirstGadget = ngd;
  830.     pgd = ngd;
  831.     ngd->NextGadget = NULL;
  832.     }
  833.     return( nwin );
  834. }
  835.  
  836. void
  837. FreeNewWindow( win )
  838.     struct NewWindow *win;
  839. {
  840.     register struct Gadget *gd, *pgd;
  841.     register struct StringInfo *sip;
  842.  
  843.     for( gd = win->FirstGadget; gd; gd = pgd )
  844.     {
  845.     pgd = gd->NextGadget;
  846.     if( gd->GadgetType == STRGADGET )
  847.     {
  848.         sip = (struct StringInfo *)gd->SpecialInfo;
  849.         free( sip->Buffer );
  850.         free( sip );
  851.     }
  852.     else if( gd->GadgetType == PROPGADGET )
  853.     {
  854.         free( (struct PropInfo *)gd->SpecialInfo );
  855.     }
  856.     free( gd );
  857.     }
  858.     free( win );
  859. }
  860.  
  861. void
  862. bell()
  863. {
  864.     if (flags.silent) return;
  865.     DisplayBeep(NULL);
  866. }
  867.  
  868. void
  869. amii_delay_output()
  870. {
  871.     /* delay 50 ms */
  872.     Delay(2L);
  873. }
  874.  
  875. void
  876. amii_number_pad(state)
  877. int state;
  878. {
  879. }
  880.  
  881. /* fatal error */
  882. /*VARARGS1*/
  883. void error VA_DECL(const char *, s)
  884.     VA_START(s);
  885.     VA_INIT(s, char *);
  886.  
  887.     putchar('\n');
  888.     vprintf(s, VA_ARGS);
  889.     putchar('\n');
  890.  
  891.     VA_END();
  892.     Abort(0L);
  893. }
  894.