#include <exec/types.h>
#include <exec/memory.h>
#include <exec/alerts.h>

#include "diff.h"
#include "same.h"
#include "amiga.h"

#include <intuition/intuition.h> // for struct Window, etc.
#include <libraries/gadtools.h>  // for GT_VisualInfo, etc.

#include <stdlib.h>              // for EXIT_SUCCESS, etc.

MODULE UWORD chip CustomPointer[] =
{   0x0000, 0x0000, /* reserved */

    0xF800, 0xFC00, /* 1st row 1st plane, 1st row 2nd plane */
    0xF800, 0x8400, /* 2nd row 1st plane, 2nd row 2nd plane */
    0xF800, 0x8400, /* 3rd row 1st plane, 3rd row 2nd plane */
    0xF800, 0x8400, /* 4th row 1st plane, 4th row 2nd plane */
    0xF800, 0x8400, /* 5th row 1st plane, 5th row 2nd plane */
    0x8000, 0xFC00, /* 6th row 1st plane, 6th row 2nd plane */

    0x0000, 0x0000  /* reserved */

/*  11111000-------- 11111100--------
    11111000-------- 10000100--------
    11111000-------- 10000100--------
    11111000-------- 10000100--------
    11111000-------- 10000100--------
    10000000-------- 11111100-------- */

};

#define ALTJUMP         5

/* pseudo-gadgets */
#define GADGETX         (-2) // negatives must be within parentheses
#define EMPTYGADGET    ((FIELDY / 2) - 7)
#define SILVERGADGET   ((FIELDY / 2) - 5)
#define GOLDGADGET     ((FIELDY / 2) - 3)
#define DYNAMITEGADGET ((FIELDY / 2) - 1)
#define WOODGADGET     ((FIELDY / 2) + 1)
#define STONEGADGET    ((FIELDY / 2) + 3)
#define METALGADGET    ((FIELDY / 2) + 5)
#define FROSTGADGET    ((FIELDY / 2) + 7)

MODULE void setpointer(UBYTE brush);
MODULE void dot(void);
MODULE void undot(void);
MODULE void stamp(UBYTE square);
MODULE void fillfield(UBYTE which);
MODULE void underline(UBYTE square);
MODULE SBYTE xpixeltosquare(SWORD x);
MODULE SBYTE ypixeltosquare(SWORD y);
MODULE void levelappend(void);
MODULE void leveldelete(void);
MODULE void levelerase(void);
MODULE void levelinsert(void);
MODULE void copyfield(UBYTE source, UBYTE destination);

IMPORT struct Window*        MainWindowPtr;
IMPORT struct Menu*          MenuPtr;
IMPORT struct VisualInfo*    VisualInfoPtr;
IMPORT struct timerequest*   TimerRqPtr;
IMPORT struct InputEvent     GameEvent;
IMPORT struct Screen*        ScreenPtr;

IMPORT struct TeleportStruct teleport[MAXLEVELS + 1][4];

IMPORT ABOOL               anims,
                           clearthem,
                           icons,
                           modified,
                           thick;
IMPORT SBYTE               a,
                           board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
                           startx[MAXLEVELS + 1],
                           starty[MAXLEVELS + 1],
                           fex = FIELDX / 2,
                           fey = FIELDY / 2,
                           level, levels;

MODULE ABOOL               sticky = FALSE;
MODULE UBYTE               brush  = STONE;

AGLOBAL void fieldedit(void)
{   AUTO    ABOOL                leftdown  = FALSE,
                                 timer     = FALSE;
    AUTO    SBYTE                pointerx, pointery,
                                 which,
                                 x, y;
    AUTO    SWORD                mousex, mousey;
    AUTO    UWORD                code, qual;
    AUTO    ULONG                class;
    AUTO    struct IntuiMessage* MsgPtr;
    AUTO    struct MenuItem*     ItemPtr;
    PERSIST ABOOL                clipboarded = FALSE;
    PERSIST UBYTE                clipboard[FIELDX + 1][FIELDY + 1];

    say("Field Editor", WHITE);
    setpointer(brush);
    if (level > levels)
        level = levels;
    OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
    if (!clipboarded)
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));

    /* draw pseudo-gadgets */
    
    clearscreen();
    for (which = 0; which <= 7; which++)
    {   DrawBevelBox
        (   MainWindowPtr->RPort,
            STARTXPIXEL - (SQUAREX * 2) - 4,
            156 + (which * 2 * SQUAREY), // -12 per new gadget added
            SQUAREX + 8,
            SQUAREY + 8,
            GT_VisualInfo, VisualInfoPtr,
            TAG_DONE
        );
    }
    SetAPen(MainWindowPtr->RPort, WHITE);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (   EMPTYGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F1:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (  SILVERGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F2:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (    GOLDGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F3:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (DYNAMITEGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F4:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (    WOODGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F5:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (   STONEGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F6:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (   METALGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F7:", 3);
    Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 10 + (   FROSTGADGET * SQUAREY));
    Text(MainWindowPtr->RPort, "F8:", 3);

    draw(GADGETX,    EMPTYGADGET,    EMPTY);
    draw(GADGETX,   SILVERGADGET,   SILVER);
    draw(GADGETX,     GOLDGADGET,     GOLD);
    draw(GADGETX, DYNAMITEGADGET, DYNAMITE);
    draw(GADGETX,     WOODGADGET,     WOOD);
    draw(GADGETX,    STONEGADGET,    STONE);
    draw(GADGETX,    METALGADGET,    METAL);
    draw(GADGETX,    FROSTGADGET,    FROST);

    underline(brush);
    turborender();
    saylevel(WHITE);
    clearkybd();

    fex = startx[level];
    fey = starty[level];
    dot();

    if (!(ModifyIDCMP(MainWindowPtr, IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | IDCMP_REFRESHWINDOW | IDCMP_MOUSEMOVE)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: ModifyIDCMP() failed!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    while (a == FIELDEDIT)
    {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
        while (MsgPtr = GT_GetIMsg(MainWindowPtr->UserPort))
        {   class  = MsgPtr->Class;
            code   = MsgPtr->Code;
            qual   = MsgPtr->Qualifier;
            mousex = MsgPtr->MouseX;
            mousey = MsgPtr->MouseY;
            if (class == IDCMP_MENUVERIFY)
            {   if
                (   mousex >= STARTXPIXEL
                 && mousex <=   ENDXPIXEL
                 && mousey >= STARTYPIXEL
                 && mousey <=   ENDYPIXEL
                )
                {   MsgPtr->Code = MENUCANCEL;
            }   }
            GT_ReplyIMsg(MsgPtr);
            switch (class)
            {
            case IDCMP_MOUSEMOVE:
                if (leftdown)
                {   pointerx = xpixeltosquare(mousex);
                    pointery = ypixeltosquare(mousey);
                    if
                    (   (pointerx != fex || pointery != fey)
                     && valid(pointerx, pointery)
                    )
                    {   undot();
                        fex = pointerx;
                        fey = pointery;
                        stamp(brush);
                }   }
            break;
            case IDCMP_MENUPICK:
                while (code != MENUNULL)
                {   ItemPtr = ItemAddress(MenuPtr, code);
                    switch (MENUNUM(code))
                    {
                    case MN_PROJECT:
                        switch (ITEMNUM(code))
                        {
                        case IN_NEW:
                            newfields();
                            say("New done.", WHITE);
                        break;
                        case IN_OPEN:
                            fileopen(FALSE);
                        break;
                        case IN_REVERT:
                            fileopen(TRUE);
                        break;
                        case IN_SAVE:
                            if (modified)
                            {   clearhiscores();
                                modified = FALSE;
                            }
                            filesaveas(FALSE);
                            turborender();
                        break;
                        case IN_SAVEAS:
                            if (modified)
                            {   clearhiscores();
                                modified = FALSE;
                            }
                            filesaveas(TRUE);
                            turborender();
                        break;
                        case IN_PROJECTDELETE:
                            filedelete();
                        break;
                        case IN_QUIT:
                            if (verify())
                                cleanexit(EXIT_SUCCESS);
                        break;
                        default:
                        break;
                        }
                    break;
                    case MN_EDIT:
                        switch (ITEMNUM(code))
                        {
                        case IN_CUT:
                            for (x = 0; x <= FIELDX; x++)
                                for (y = 0; y <= FIELDY; y++)
                                    clipboard[x][y] = board[level][x][y];
                            leveldelete();
                            clipboarded = TRUE;
                            modified = TRUE;
                            OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
                        break;
                        case IN_COPY:
                            for (x = 0; x <= FIELDX; x++)
                                for (y = 0; y <= FIELDY; y++)
                                    clipboard[x][y] = board[level][x][y];
                            clipboarded = TRUE;
                            OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
                        break;
                        case IN_PASTE:
                            for (x = 0; x <= FIELDX; x++)
                                for (y = 0; y <= FIELDY; y++)
                                    board[level][x][y] = clipboard[x][y];
                            turborender();
                            modified = TRUE;
                        break;
                        case IN_ERASE:
                            levelerase();
                        break;
                        case IN_INSERT:
                            levelinsert();
                        break;
                        case IN_EDITDELETE:
                            leveldelete();
                        break;
                        case IN_APPEND:
                            levelappend();
                        break;
                        default:
                        break;
                        }
                    break;
                    case MN_SETTINGS:
                        switch(ITEMNUM(code))
                        {
                        case IN_ANIMATIONS:
                            if (ItemPtr->Flags & CHECKED)
                            {   anims = TRUE;
                            } else
                            {   anims = FALSE;
                            }
                        break;
                        case IN_CREATEICONS:
                            if (ItemPtr->Flags & CHECKED)
                            {   icons = TRUE;
                            } else
                            {   icons = FALSE;
                            }
                        break;
                        case IN_THICKTAILS:
                            if (ItemPtr->Flags & CHECKED)
                            {   thick = TRUE;
                            } else
                            {   thick = FALSE;
                            }
                        break;
                        default:
                        break;
                        }
                    break;
                    case MN_HELP:
                        switch(ITEMNUM(code))
                        {
                        case IN_CREATURES:
                            help(ORB);
                        break;
                        case IN_OBJECTS:
                            help(AFFIXER);
                        break;
                        case IN_ABOUT:
                            helpabout();
                        break;
                        default:
                        break;
                        }
                    break;
                    default:
                    break;
                    } // hctiws
                    code = ItemPtr->NextSelect;
                } // elihw
            break;
            case IDCMP_RAWKEY:
                if (!(qual & IEQUALIFIER_REPEAT))
                {   effect(FXCLICK);
                }
                switch(code)
                {
                case DELETE:
                    if (!(qual & IEQUALIFIER_REPEAT))
                    {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            level = 1;
                        elif (--level < 0)
                            level = levels;
                        saylevel(WHITE);
                        turborender();
                    }
                break;
                case HELP:
                    if (!(qual & IEQUALIFIER_REPEAT))
                    {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                            level = levels;
                        elif (++level > levels)
                            level = 0;
                        saylevel(WHITE);
                        turborender();
                    }
                break;
                case M:
                    if (!(qual & IEQUALIFIER_REPEAT))
                        toggle(M);
                break;
                case F:
                    if (!(qual & IEQUALIFIER_REPEAT))
                        toggle(F);
                break;
                case ESCAPE:
                    if (!(qual & IEQUALIFIER_REPEAT))
                    {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                        {   if (verify())
                            {   cleanexit(EXIT_SUCCESS);
                        }   }
                        else
                        {   a = GAMEOVER;
                    }   }
                break;
                case SPACEBAR:
                case RETURN:
                case ENTER:
                    if (!(qual & IEQUALIFIER_REPEAT))
                        a = GAMEOVER;
                break;
                case NUMERICOPEN:
                    setpointer(NORMAL);
                    underline(255);

                    brush--;
                    if (brush <= 0 || brush > LASTOBJECT) // note sign issues
                    {   brush = LASTOBJECT;
                    }   stamp(brush);
                break;
                case NUMERICCLOSE:
                    setpointer(NORMAL);
                    underline(255);

                    brush++;
                    if (brush > LASTOBJECT)
                    {   brush = 0;
                        stamp(brush);
                    }
                break;
                case C:
                    effect(FXCENTRE); /* interesting */
                    undot();
                    fex = FIELDX / 2;
                    fey = FIELDY / 2;
                    dot();
                break;
                case S:
                    stamp(START);
                break;
                case KEY_T:
                    stamp(TELEPORT);
                break;
                case KEY_U:
                    stamp(ARROWUP);
                break;
                case D:
                    stamp(ARROWDOWN);
                break;
                case O:
                    stamp(OCTOPUS);
                break;
                case ALPHAONE:
                    stamp(EMPTY);
                break;
                case ALPHATWO:
                    stamp(SILVER);
                break;
                case ALPHATHREE:
                    stamp(GOLD);
                break;
                case ALPHAFOUR:
                    stamp(DYNAMITE);
                break;
                case ALPHAFIVE:
                    stamp(WOOD);
                break;
                case ALPHASIX:
                    stamp(STONE);
                break;
                case ALPHASEVEN:
                    stamp(METAL);
                break;
                case ALPHAEIGHT:
                    stamp(FROST);
                break;
                case F1:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(EMPTY);
                    } else setbrush(EMPTY);
                break;
                case F2:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(SILVER);
                    } else setbrush(SILVER);
                break;
                case F3:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(GOLD);
                    } else setbrush(GOLD);
                break;
                case F4:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(DYNAMITE);
                    } else setbrush(DYNAMITE);
                break;
                case F5:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(WOOD);
                    } else setbrush(WOOD);
                break;
                case F6:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(STONE);
                    } else setbrush(STONE);
                break;
                case F7:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(METAL);
                    } else setbrush(METAL);
                break;
                case F8:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   fillfield(FROST);
                    } else setbrush(FROST);
                break;
                case NUMERICZERO:
                    if (!(qual & IEQUALIFIER_REPEAT))
                    {   if (!sticky)
                        {   sticky = TRUE;
                            say("Sticky mode on", WHITE);
                            stamp(brush);
                        } else
                        {   sticky = FALSE;
                            say("Sticky mode off", WHITE);
                            dot();
                    }   }
                break;
                case NUMERICDOT:
                    stamp(brush);
                break;
                case KEY_X:
                    undot();
                    fex = FIELDX - fex;
                    dot();
                break;
                case KEY_Y:
                    undot();
                    fey = FIELDY - fey;
                    dot();
                break;
                case NUMERICFOUR:
                case LEFT:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = 0;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex - ALTJUMP);
                    } else
                    {   fex = xwrap(fex - 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICSIX:
                case RIGHT:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = FIELDX;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex + ALTJUMP);
                    } else
                    {   fex = xwrap(fex + 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICEIGHT:
                case UP:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fey = 0;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fey = ywrap(fey - ALTJUMP);
                    } else
                    {   fey = ywrap(fey - 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICFIVE:
                case NUMERICTWO:
                case DOWN:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fey = FIELDY;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fey = ywrap(fey + ALTJUMP);
                    } else
                    {   fey = ywrap(fey + 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICSEVEN:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = 0;
                        fey = 0;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex - ALTJUMP);
                        fey = ywrap(fey - ALTJUMP);
                    } else
                    {   fex = xwrap(fex - 1);
                        fey = ywrap(fey - 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICNINE:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = FIELDX;
                        fey = 0;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex + ALTJUMP);
                        fey = ywrap(fey - ALTJUMP);
                    } else
                    {   fex = xwrap(fex + 1);
                        fey = ywrap(fey - 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICONE:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = 0;
                        fey = FIELDY;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex - ALTJUMP);
                        fey = ywrap(fey + ALTJUMP);
                    } else
                    {   fex = xwrap(fex - 1);
                        fey = ywrap(fey + 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                case NUMERICTHREE:
                    undot();
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
                    {   fex = FIELDX;
                        fey = FIELDY;
                    } elif ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
                    {   fex = xwrap(fex + ALTJUMP);
                        fey = ywrap(fey + ALTJUMP);
                    } else
                    {   fex = xwrap(fex + 1);
                        fey = ywrap(fey + 1);
                    }
                    if (sticky)
                    {   stamp(brush);
                    } else
                    {   dot();
                    }
                break;
                default:
                break;
                } // hctiws
            break;
            case IDCMP_MOUSEBUTTONS:
                if (code == SELECTDOWN)
                {   pointerx = xpixeltosquare(mousex);
                    pointery = ypixeltosquare(mousey);
                    leftdown = TRUE;
                    if (pointerx == GADGETX)
                    {   switch (pointery)
                        {
                        case GOLDGADGET:
                            setbrush(GOLD);
                        break;
                        case SILVERGADGET:
                            setbrush(SILVER);
                        break;
                        case EMPTYGADGET:
                            setbrush(EMPTY);
                        break;
                        case WOODGADGET:
                            setbrush(WOOD);
                        break;
                        case DYNAMITEGADGET:
                            setbrush(DYNAMITE);
                        break;
                        case STONEGADGET:
                            setbrush(STONE);
                        break;
                        case METALGADGET:
                            setbrush(METAL);
                        break;
                        case FROSTGADGET:
                            setbrush(FROST);
                        break;
                        default:
                        break;
                    }   }
                    else
                    {   if (valid(pointerx, pointery))
                        {   undot();
                            fex = pointerx;
                            fey = pointery;
                            stamp(brush);
                }   }   }
                elif (code == SELECTUP)
                {   leftdown = FALSE;
                } elif (code == MENUUP)
                {   pointerx = xpixeltosquare(mousex);
                    pointery = ypixeltosquare(mousey);
                    if (valid(pointerx, pointery))
                    {   undot();
                        fex = pointerx;
                        fey = pointery;
                        stamp(EMPTY);
                }   }
            break;
            case IDCMP_CLOSEWINDOW:
                cleanexit(EXIT_SUCCESS);
            break;
            case IDCMP_REFRESHWINDOW:
                GT_BeginRefresh(MainWindowPtr);
                GT_EndRefresh(MainWindowPtr, TRUE);
            break;
            default:
                /* IDCMP_MENUVERIFY, IDCMP_INTUITICKS, IDCMP_ACTIVEWINDOW */
            break;
    }   }   }

    /* exit to title screen */

    if (!(ModifyIDCMP(MainWindowPtr->RPort, IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | CYCLEIDCMP | STRINGIDCMP | CHECKBOXIDCMP | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS)))
    {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: ModifyIDCMP() failed!\0", 24);
	cleanexit(EXIT_FAILURE);
    }
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
    if (timer)
    {   AbortIO((struct IORequest *) TimerRqPtr);
         WaitIO((struct IORequest *) TimerRqPtr);
    }
    setpointer(NORMAL);
    if (clearthem)
        clearhiscores();
    matchteleports();
}

MODULE void stamp(UBYTE square)
{   if (square == START)
    {   draw(startx[level], starty[level], EMPTY);
        board[level][startx[level]][starty[level]] = EMPTY;
        startx[level] = fex;
        starty[level] = fey;
        board[level][fex][fey] = EMPTY;
    } else
    {   board[level][fex][fey] = square;
    }

    draw(fex, fey, square);
    dot();
    modified = clearthem = TRUE;
}

MODULE void undot(void)
{   if (startx[level] == fex && starty[level] == fey)
        draw(fex, fey, START);
    else draw(fex, fey, board[level][fex][fey]);
}

MODULE void fillfield(UBYTE which)
{   SBYTE x, y;

    // Service routine for field editor.

    for (x = 0; x <= FIELDX; x++)
    {   for (y = 0; y <= FIELDY; y++)
        {   board[level][x][y] = which;
            draw(x, y, which);
    }   }
    board[level][startx[level]][starty[level]] = EMPTY;
    draw(startx[level], starty[level], START);
    dot();
}

AGLOBAL void setbrush(UBYTE newbrush)
{   brush = newbrush;
    setpointer(brush);
    underline(brush);
}

MODULE void underline(UBYTE square)
{   /* Removes old underline, draws new underline.

    square: which square-type to underline, or 255 for clear only.
    Squares which do not correspond to any pseudo-gadgets
    (eg. objects) are converted to 255s. */

    PERSIST SWORD oldy = 255;
    AUTO    SWORD y;

    switch(square)
    {
    case EMPTY:
        y = STARTYPIXEL + (EMPTYGADGET * SQUAREY);
    break;
    case SILVER:
        y = STARTYPIXEL + (SILVERGADGET * SQUAREY);
    break;
    case GOLD:
        y = STARTYPIXEL + (GOLDGADGET * SQUAREY);
    break;
    case DYNAMITE:
        y = STARTYPIXEL + (DYNAMITEGADGET * SQUAREY);
    break;
    case WOOD:
        y = STARTYPIXEL + (WOODGADGET * SQUAREY);
    break;
    case STONE:
        y = STARTYPIXEL + (STONEGADGET * SQUAREY);
    break;
    case METAL:
        y = STARTYPIXEL + (METALGADGET * SQUAREY);
    break;
    default:
        square = 255;
        y = 0; // to avoid spurious warnings
    break;
    }

    if (oldy != 255)
    {   SetAPen(MainWindowPtr->RPort, BLACK);
        Move(MainWindowPtr->RPort, STARTXPIXEL - 4, oldy);
        Draw(MainWindowPtr->RPort, STARTXPIXEL - 4, oldy + SQUAREY);
    }
    if (square != 255)
    {   SetAPen(MainWindowPtr->RPort, WHITE);
        Move(MainWindowPtr->RPort, STARTXPIXEL - 4, y);
        Draw(MainWindowPtr->RPort, STARTXPIXEL - 4, y + SQUAREY);
        oldy = y;
}   }

MODULE void dot(void)
{   SWORD x, xx, y, yy;

	/* Squares are dotted as follows:
	
         012345678901
        0............
        1............
        2............
        3............
        4....WWW.....
        5....WWWB....
        6....WWWB....
        7.....BBB....
        8............
        9............
       10............
       11............ */

	xx = (fex * SQUAREX) + STARTXPIXEL;
	yy = (fey * SQUAREY) + STARTYPIXEL;

	if (sticky)
		SetAPen(MainWindowPtr->RPort, RED);
	else SetAPen(MainWindowPtr->RPort, WHITE);
        for (x = 4; x <= 6; x++)
        {   for (y = 4; y <= 6; y++)
            {   WritePixel(MainWindowPtr->RPort, xx + x, yy + y);
        }   }
        SetAPen(MainWindowPtr->RPort, BLACK);
        WritePixel(MainWindowPtr->RPort, xx + 7, yy + 5);
        WritePixel(MainWindowPtr->RPort, xx + 7, yy + 6);
        WritePixel(MainWindowPtr->RPort, xx + 5, yy + 7);
        WritePixel(MainWindowPtr->RPort, xx + 6, yy + 7);
        WritePixel(MainWindowPtr->RPort, xx + 7, yy + 7);
}

MODULE void setpointer(UBYTE pointer)
{   switch (pointer)
    {
    case EMPTY:
        SetRGB4(&ScreenPtr->ViewPort, 17,  2,  2,  2);          /* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18,  2,  2,  2);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19,  2,  2,  2);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    case DYNAMITE:
        SetRGB4(&ScreenPtr->ViewPort, 17, 15,  8, 15);          /* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18, 15,  8, 15);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19, 15,  8, 15);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    case WOOD:
	SetRGB4(&ScreenPtr->ViewPort, 17,  8,  4,  2);		/* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18,  8,  4,  2);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19,  8,  4,  2);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    case STONE:
	SetRGB4(&ScreenPtr->ViewPort, 17,  0,  0,  0);		/* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18,  0,  0,  0);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19,  0,  0,  0);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    case METAL:
        SetRGB4(&ScreenPtr->ViewPort, 17, 10, 10, 10);          /* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18, 10, 10, 10);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19, 10, 10, 10);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    case FROST:
        SetRGB4(&ScreenPtr->ViewPort, 17, 12, 12, 15);          /* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18, 12, 12, 15);          /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12, 15);          /* shine */
        SetPointer(MainWindowPtr, CustomPointer, 6, 6, -3, -3);
    break;
    default:
        SetRGB4(&ScreenPtr->ViewPort, 17, 14,  4,  4); /* fill */
        SetRGB4(&ScreenPtr->ViewPort, 18,  3,  3,  3); /* shadow */
        SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12, 12); /* shine */
	ClearPointer(MainWindowPtr);
    break;
}   }

MODULE SBYTE xpixeltosquare(SWORD x)
{   x = (x - STARTXPIXEL) / SQUAREX;
    if (x < 0)
        x--;
    return ((SBYTE) x);
}
MODULE SBYTE ypixeltosquare(SWORD y)
{   y = (y - STARTYPIXEL) / SQUAREY;
    if (y < 0)
        y--;
    return ((SBYTE) y);
}

MODULE void levelappend(void)
{   UBYTE oldlevel;

    if (levels < MAXLEVELS)
    {   oldlevel = level;
        level = ++levels;
        newfield();
        level = oldlevel;
        saylevel(WHITE);
}   }
MODULE void leveldelete(void)
{   SBYTE i;

    /* pull boards */

    if (levels > 1)
    {   if (level < levels)
        for (i = level; i < levels; i++)
            copyfield(i + 1, i);
        else
            level--;
        levels--;
        saylevel(WHITE);
        turborender();
}   }
MODULE void levelerase(void)
{   newfield();
    turborender();
}
MODULE void levelinsert(void)
{   UBYTE i;

    /* push boards */

    if (levels < MAXLEVELS)
    {   for (i = levels; i >= level; i--)
            copyfield(i, i + 1);
        levels++;
        saylevel(WHITE);
        newfield();
        turborender();
}   }
MODULE void copyfield(UBYTE source, UBYTE destination)
{   SBYTE which, x, y;

    for (x = 0; x <= FIELDX; x++)
        for (y = 0; y <= FIELDY; y++)
            board[destination][x][y] = board[source][x][y];
    startx[destination] = startx[source];
    starty[destination] = starty[source];
    for (which = 0; which <= 1; which++)
    {   teleport[destination][which].alive = teleport[source][which].alive;
        teleport[destination][which].x     = teleport[source][which].x;
        teleport[destination][which].y     = teleport[source][which].y;
}   }
