#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 brackets
#define EMPTYGADGET    ((FIELDY / 2) - 6)
#define SILVERGADGET   ((FIELDY / 2) - 4)
#define GOLDGADGET     ((FIELDY / 2) - 2)
#define DYNAMITEGADGET  (FIELDY / 2)
#define WOODGADGET     ((FIELDY / 2) + 2)
#define STONEGADGET    ((FIELDY / 2) + 4)
#define METALGADGET    ((FIELDY / 2) + 6)

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                mergelevels,
                                 pointerx, pointery,
                                 which,
                                 x, y;
    AUTO    UBYTE                IOBuffer[HISCORESIZE];
    AUTO    SWORD                mousex, mousey;
    AUTO    UWORD                code, qual;
    AUTO    ULONG                class, i;
    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 <= 6; which++)
    {   DrawBevelBox
        (   MainWindowPtr->RPort,
            STARTXPIXEL - (SQUAREX * 2) - 4,
            168 + (which * 2 * SQUAREY),
            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);

    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);

    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)
    {   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_MANUAL:
                            helpmanual();
                        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 Z:
                    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                    {   /* The undocumented merge function. You will
                        notice that there is absolutely no error checking.
                        This is because you shouldn't really be using this
                        function, unless you know what you are doing. */

                        say("Merging...", WHITE);
                        ZOpen("RAM:Merge.fset", FALSE);
                        ZRead(IOBuffer, 10);
                        mergelevels = IOBuffer[9];
                        for (i = 0; i <= HISCORES; i++)
                        {   ZRead(IOBuffer, HISCORESIZE);
                        }
                        ZRead(IOBuffer, 8);
                        ZRead((char *) &board[0][0][0], LEVELSIZE);

                        for (i = levels + 1; i <= levels + mergelevels; i++)
                        {   ZRead(IOBuffer, 8);
                            startx[i]            = IOBuffer[0];
                            starty[i]            = IOBuffer[1];
                            teleport[i][0].alive = IOBuffer[2];
                            teleport[i][0].x     = IOBuffer[3];
                            teleport[i][0].y     = IOBuffer[4];
                            teleport[i][1].alive = IOBuffer[5];
                            teleport[i][1].x     = IOBuffer[6];
                            teleport[i][1].y     = IOBuffer[7];
                            ZRead((char *) &board[i][0][0], LEVELSIZE);
                        }
                        ZClose();
                        levels += mergelevels;
                        modified = clearthem = TRUE;
                        say("Merge done.", WHITE);
                    }
                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 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 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 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;
                        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;
    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;
}   }