home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / software / giochi / wormwars / source / system.c < prev    next >
C/C++ Source or Header  |  2000-01-05  |  101KB  |  3,430 lines

  1. /* $Filename:    WormWars/Source/system.c $
  2.  * $VER:         Worm Wars 5.21 $
  3.  * $Description: API calls for Amiga $
  4.  *
  5.  * © Copyright 1999 James R. Jacobs. Freely distributable.
  6.  *        _
  7.  *       //        -=AMIGA=-
  8.  *      //
  9.  * _   //
  10.  * \\ //
  11.  *  \X/
  12.  
  13. #INCLUDES -------------------------------------------------------------- */
  14.  
  15. #include "system.h"                // #includes everything else
  16.  
  17. // GLOBAL VARIABLES (owned by engine.c, imported by amiga.lib) ------------
  18.  
  19. AGLOBAL    struct Library*            TimerBase                        = NULL;
  20.  
  21. // EXTERNAL VARIABLES (owned by engine.c, imported by system.c) -----------
  22.  
  23. IMPORT    struct Library*            SysBase;
  24.  
  25. IMPORT    ABOOL                    clearthem, modified;
  26. IMPORT    SBYTE                    a, board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  27.                                 brush, eachworm[4][2][9],
  28.                                 field[FIELDX + 1][FIELDY + 1],
  29.                                 level, levels, players,
  30.                                 startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  31. IMPORT    STRPTR                    pathname;
  32. IMPORT    SWORD                    secondsleft, secondsperlevel;
  33. IMPORT    ULONG                    delay, r;
  34. IMPORT    struct HiScoreStruct    hiscore[HISCORES + 1];
  35. IMPORT    struct TeleportStruct    teleport[MAXLEVELS + 1][4];
  36. IMPORT    struct WormStruct        worm[4];
  37. IMPORT    TEXT                    date[DATELENGTH + 1],
  38.                                 times[TIMELENGTH + 1];
  39.  
  40. // MODULE VARIABLES (used only within system.c) ---------------------------
  41.  
  42. MODULE    struct ASLBase*            ASLBase                            = NULL;
  43. MODULE    struct DiskFontBase*    DiskFontBase                    = NULL;
  44. MODULE    struct GadToolsBase*    GadToolsBase                    = NULL;
  45. MODULE    struct GfxBase*            GfxBase                            = NULL;
  46. MODULE    struct IconBase*        IconBase                        = NULL;
  47. MODULE    struct IntuitionBase*    IntuitionBase                    = NULL;
  48. MODULE    struct MEDPlayerBase*    MEDPlayerBase                    = NULL;
  49. MODULE    struct UtilityBase*        UtilityBase                        = NULL;
  50.  
  51. MODULE  struct CIA*             cia                             = (struct CIA *) 0xBFE001;
  52.  
  53. MODULE    struct RDArgs*            ArgsPtr                            = NULL;
  54. MODULE    struct FileRequester*    ASLRqPtr                        = NULL;
  55. MODULE    ABOOL                    AudioClosed                        = TRUE;
  56. MODULE    struct MsgPort*            AudioPortPtr[4]                    = {NULL, NULL, NULL, NULL};
  57. MODULE    struct IOAudio*            AudioRqPtr[4]                    = {NULL, NULL, NULL, NULL};
  58. MODULE    struct Gadget*            CheckboxGadgetPtr                = NULL;
  59. MODULE    SBYTE                    Controller                        = GPCT_NOCONTROLLER;
  60. MODULE    struct timeval*            CurrentValPtr                    = NULL;
  61. MODULE    struct Gadget*            CycleGadgetPtr[4]                = {NULL, NULL, NULL, NULL};
  62. MODULE    ABOOL                    eversent[4];
  63. MODULE    UBYTE*                    fbase                            = NULL;
  64. MODULE    ULONG                    fsize;
  65. MODULE    BPTR                    FilePtr                            = NULL;
  66. MODULE    struct TextFont*        FontPtr                            = NULL;
  67. MODULE    SBYTE                    fxable = 2, musicable = 2;
  68. MODULE    struct InputEvent        GameEvent;
  69. MODULE    struct Gadget*            GListPtr                        = NULL;
  70. MODULE    ABOOL                iconfailed            = FALSE;
  71. MODULE    ABOOL                    ignore                            = FALSE;
  72. MODULE    SBYTE                    InputClosed                        = TRUE;
  73. MODULE    struct MsgPort*          InputPortPtr                    = NULL;
  74. MODULE    struct IOStdReq*        InputRqPtr                        = NULL;
  75. MODULE    ABOOL                    iso                                = TRUE;
  76. MODULE    ABOOL                    joy                                = FALSE;
  77. MODULE    SBYTE                    JoyClosed                        = TRUE;
  78. MODULE    struct MsgPort*            JoyPortPtr                        = NULL;
  79. MODULE    struct IOStdReq*        JoyRqPtr                        = NULL;
  80. MODULE    ULONG                    length[SAMPLES + 1][2];
  81. MODULE    struct Window*            MainWindowPtr                    = NULL;
  82. MODULE    struct Menu*            MenuPtr                            = NULL;
  83. MODULE    SBYTE                    mode                            = FALSE;
  84. MODULE    SBYTE                    OldPri                            = 0;
  85. MODULE    APTR                    OldWindowPtr                    = NULL;
  86. MODULE    struct timeval*            PausedValPtr                    = NULL;
  87. MODULE    SWORD                    pixy;
  88. MODULE    struct Gadget*            PrevGadgetPtr                    = NULL;
  89. MODULE    struct Process*            ProcessPtr                        = NULL;
  90. MODULE    ULONG                    receipter[4]                    = {(ULONG) -1, (ULONG) -1, (ULONG) -1, (ULONG) -1};
  91. MODULE    UBYTE*                    sbase[SAMPLES + 1];
  92. MODULE    struct Screen*            ScreenPtr                        = NULL;
  93. MODULE    struct MMD0*            SongPtr                            = NULL;
  94. MODULE    ULONG                    speed[SAMPLES + 1];
  95. MODULE    ULONG                    ssize[SAMPLES + 1];
  96. MODULE    struct timeval*            StartValPtr                        = NULL;
  97. MODULE    ABOOL                    sticky                            = FALSE;
  98. MODULE    struct Gadget*            StringGadgetPtr[6]                = {NULL, NULL, NULL, NULL, NULL};
  99. MODULE    SBYTE                    TimerClosed                        = TRUE;
  100. MODULE    struct MsgPort*            TimerPortPtr                    = NULL;
  101. MODULE    struct timerequest*        TimerRqPtr                        = NULL;
  102. MODULE    struct VisualInfo*        VisualInfoPtr                    = NULL;
  103. MODULE    ULONG                    yes[SAMPLES + 1];
  104. MODULE    struct WBArg*            WBArg                            = NULL;
  105. MODULE    struct WBStartup*        WBMsg                            = NULL;
  106. MODULE    struct TextAttr            WormWars8 =
  107. {    (STRPTR) "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  108. };
  109. MODULE    struct TextAttr            Topaz8 =
  110. {    (STRPTR) "Topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
  111. };
  112.  
  113. // FUNCTIONS --------------------------------------------------------------
  114.  
  115. int main(int argc, char** argv)
  116. {
  117. BPTR                OldDir;
  118. SLONG                i;
  119. ABOOL                argument                = FALSE,
  120.                     success                    = FALSE;
  121. SBYTE                error                    = 0,
  122.                     player, which;
  123. TEXT                saystring[SAYLIMIT + 1];
  124. UWORD                Pens[10] =
  125. {    BLACK,        // DETAILPEN        text in title bar
  126.     WHITE,        // BLOCKPEN            fill title bar
  127.     WHITE,        // TEXTPEN            regular text on BACKGROUNDPEN
  128.     LIGHTGREY,    // SHINEPEN            bright edge
  129.     DARKGREY,    // SHADOWPEN        dark edge
  130.     PURPLE,        /* FILLPEN            filling active window borders
  131.                                     and selected gadgets */
  132.     BLACK,        // FILLTEXTPEN        text rendered over FILLPEN
  133.     BLACK,        // BACKGROUNDPEN    background colour
  134.     RED,        // HIGHLIGHTTEXTPEN    highlighted text on BACKGROUNDPEN
  135.     (UWORD) ~0    // and used against BLOCKPEN in ASL save requesters
  136. };
  137. SLONG                args[9]                    = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
  138. struct ColorSpec    Colours[21] =
  139. {   /* colour   red   green   blue   description */
  140.     {   0,      0x0,    0x0,    0x0},   //        BLACK
  141.     {   1,      0xF,    0xF,    0xF},   //        WHITE
  142.     {   2,      0x3,    0x3,    0x3},   //    DARKGREY
  143.     {   3,      0x6,    0x6,    0x6},   //  MEDIUMGREY
  144.     {   4,      0xA,    0xA,    0xA},   //   LIGHTGREY
  145.     {   5,      0x0,    0x0,    0x0},   //        black
  146.     {   6,      0xA,    0x2,    0xA},   //        PURPLE
  147.     {   7,      0x8,    0x4,    0x2},   //        brown
  148.     {   8,      0x3,    0x9,    0x3},   //    DARKGREEN
  149.     {   9,      0x4,    0xE,    0x4},   //  light GREEN
  150.     {   10,     0xF,    0x1,    0x1},   //    DARKRED
  151.     {   11,     0xF,    0x4,    0x4},   //  light RED
  152.     {   12,     0x3,    0x3,    0xF},   //    DARKBLUE
  153.     {   13,     0x6,    0x6,    0xF},   //  light BLUE
  154.     {   14,     0xA,    0x8,    0x3},   //    DARKYELLOW
  155.     {   15,     0xC,    0xC,    0x2},   //  light YELLOW
  156.     {   16,     0x0,    0x0,    0x0},   // pointer: transparent
  157.     {   17,     0xE,    0x4,    0x4},   // pointer: fill
  158.     {   18,     0x3,    0x3,    0x3},   // pointer: shadow
  159.     {   19,     0xC,    0xC,    0xC},   // pointer: shine
  160.     {   -1,     NULL,   NULL,   NULL
  161. }   };
  162.  
  163. /* Start of program.
  164.  
  165. version embedding into executable */
  166.  
  167. if (0) // that is, never
  168.     say(VERSION, ANYTHING);
  169.  
  170. if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37L)))
  171. {    Write(Output(), OLDKICKSTART, strlen(OLDKICKSTART));
  172.     cleanexit(EXIT_FAILURE);
  173. }
  174.  
  175. // From this point onwards, we can be sure we have Kickstart 2.04+...
  176.  
  177. for (which = 0; which <= SAMPLES; which++)
  178.     sbase[which] = NULL;
  179. enginesetup();
  180. ProcessPtr = (struct Process *) FindTask(NULL);
  181.  
  182. // argument parsing
  183.  
  184. if (argc) // started from CLI
  185. {    if (!(ArgsPtr = ReadArgs
  186.     (    "-F=NOFX/S,-M=NOMUSIC/S,-P=PRI/K/N,-O=OVERHEAD/S,"
  187.         "GREEN/K,RED/K,BLUE/K,YELLOW/K,FILE",
  188.         args,
  189.         NULL
  190.     )))
  191.     {    Printf("Usage: %s [-f=NOFX] [-m=NOMUSIC] [-p=PRI <priority>]\n[-o=OVERHEAD][[FILE=]<fieldset>]\n", argv[0]);
  192.         cleanexit(EXIT_FAILURE);
  193.     }
  194.     if (args[0])
  195.         fxable = 3;
  196.     if (args[1])
  197.         musicable = 3;
  198.     if (args[2])
  199.     {    if (args[2] < -128 || args[2] > 5)
  200.            {   Printf("%s: Priority range is -128 to +5\n", argv[0]);
  201.                cleanexit(EXIT_FAILURE);
  202.          }
  203.         OldPri = SetTaskPri((struct Task *) ProcessPtr, args[2]);
  204.     }
  205.     if (args[3])
  206.         iso = FALSE;
  207.     if (args[4])
  208.     {    if (!stricmp(args[4], "HUMAN"))
  209.             worm[0].control = HUMAN;
  210.         elif (!stricmp(args[4], "AMIGA"))
  211.             worm[0].control = AMIGA;
  212.         elif (!stricmp(args[4], "NONE"))
  213.             worm[0].control = NONE;
  214.         else
  215.         {    Printf("%s: Green worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  216.             cleanexit(EXIT_FAILURE);
  217.     }    }
  218.     if (args[5])
  219.     {    if (!stricmp(args[5], "HUMAN"))
  220.             worm[1].control = HUMAN;
  221.         elif (!stricmp(args[5], "AMIGA"))
  222.             worm[1].control = AMIGA;
  223.         elif (!stricmp(args[5], "NONE"))
  224.             worm[1].control = NONE;
  225.         else
  226.         {    Printf("%s: Red worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  227.             cleanexit(EXIT_FAILURE);
  228.     }    }
  229.     if (args[6])
  230.     {    if (!stricmp(args[6], "HUMAN"))
  231.             worm[2].control = HUMAN;
  232.         elif (!stricmp(args[6], "AMIGA"))
  233.             worm[2].control = AMIGA;
  234.         elif (!stricmp(args[6], "NONE"))
  235.             worm[2].control = NONE;
  236.         else
  237.         {    Printf("%s: Blue worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  238.             cleanexit(EXIT_FAILURE);
  239.     }    }
  240.     if (args[7])
  241.     {    if (!stricmp(args[7], "HUMAN"))
  242.             worm[3].control = HUMAN;
  243.         elif (!stricmp(args[7], "AMIGA"))
  244.             worm[3].control = AMIGA;
  245.         elif (!stricmp(args[7], "NONE"))
  246.             worm[3].control = NONE;
  247.         else
  248.         {    Printf("%s: Yellow worm control must be HUMAN, AMIGA or NONE\n", argv[0]);
  249.             cleanexit(EXIT_FAILURE);
  250.     }    }
  251.     if (args[8])
  252.     {    argument = TRUE;
  253.         pathname = args[8];
  254. }    }
  255. else // started from WB
  256. {    // open icon.library
  257.  
  258.     if (IconBase = (struct IconBase *) OpenLibrary("icon.library", 0L))
  259.     {    WBMsg = (struct WBStartup *) argv;
  260.         WBArg = WBMsg->sm_ArgList; // head of the arg list
  261.  
  262.         for (i = 0;
  263.              i < WBMsg->sm_NumArgs;
  264.              i++, WBArg++)
  265.         {    if (WBArg->wa_Lock)
  266.             {    // something that does not support locks
  267.                 parsewb();
  268.             }
  269.             else
  270.             {    // locks supported, change to the proper directory
  271.                 OldDir = CurrentDir(WBArg->wa_Lock);
  272.                 parsewb();
  273.                 CurrentDir(OldDir);
  274.     }    }    }
  275.     else iconfailed = TRUE;
  276. }
  277.  
  278. if (SysBase->lib_Version < 36L)
  279. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Need exec.library V36+!\0", 24);
  280.     cleanexit(EXIT_FAILURE);
  281. }
  282. if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L)))
  283. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open graphics.library!\0", 24);
  284.     cleanexit(EXIT_FAILURE);
  285. }
  286. if (!(GadToolsBase = (struct GadToolsBase *) OpenLibrary("gadtools.library", 37L)))
  287. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open GadTools.library V37+!\0", 24);
  288.     cleanexit(EXIT_FAILURE);
  289. }
  290. if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 0L)))
  291. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open ASL.library!\0", 24);
  292.     cleanexit(EXIT_FAILURE);
  293. }
  294. if (!(UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 0L)))
  295. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open utility.library!\0", 24);
  296.     cleanexit(EXIT_FAILURE);
  297. }
  298. if (!(DiskFontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L)))
  299.     error = 1;
  300.     
  301. if (!(InputPortPtr = (struct MsgPort *) CreateMsgPort()))
  302. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open input.device!\0", 24);
  303.     cleanexit(EXIT_FAILURE);
  304. }
  305. if (!(InputRqPtr = (struct IOStdReq *) CreateIORequest(InputPortPtr, sizeof(struct IOStdReq))))
  306. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create input I/O request!\0", 24);
  307.     cleanexit(EXIT_FAILURE);
  308. }
  309. if (InputClosed = OpenDevice("input.device", 0, InputRqPtr, 0))
  310. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open input.device!\0", 24);
  311.     cleanexit(EXIT_FAILURE);
  312. }
  313.     
  314. if (!(StartValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  315. {    DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
  316.     cleanexit(EXIT_FAILURE);
  317. }
  318. if (!(CurrentValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  319. {    DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
  320.     cleanexit(EXIT_FAILURE);
  321. }
  322. if (!(PausedValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  323. {    DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
  324.     cleanexit(EXIT_FAILURE);
  325. }
  326. if (!(TimerPortPtr = (struct MsgPort *) CreateMsgPort()))
  327. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer message port!\0", 24);
  328.     cleanexit(EXIT_FAILURE);
  329. }
  330. if (!(TimerRqPtr = (struct timerequest *) CreateIORequest(TimerPortPtr, sizeof(struct timerequest))))
  331. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create timer I/O request!\0", 24);
  332.     cleanexit(EXIT_FAILURE);
  333. }
  334. if (TimerClosed = OpenDevice(TIMERNAME, UNIT_VBLANK, TimerRqPtr, 0))
  335. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open timer.device!\0", 24);
  336.     cleanexit(EXIT_FAILURE);
  337. }
  338. TimerBase = (struct Library *) TimerRqPtr->tr_node.io_Device;
  339.  
  340. /* PREPARE DISPLAY -----------------------------------------------
  341.  
  342. font and screen */
  343.  
  344. if ((!error) && (FontPtr = (struct TextFont *) OpenDiskFont(&WormWars8)))
  345. {    /* loaded WormWars.font
  346.  
  347.     It would be possible to pass WA_Interleaved on any OS version,
  348.     provided that it was ignored by 2.04-2.1. */
  349.  
  350.     if (IntuitionBase->LibNode.lib_Version >= 39) // if we're running on OS3.0+
  351.     {    ScreenPtr = (struct Screen *) OpenScreenTags
  352.         (    NULL,
  353.             SA_Width,            640,
  354.             SA_Height,            256,
  355.             SA_Depth,            DEPTH,
  356.             SA_DisplayID,       HIRES_KEY | PAL_MONITOR_ID,
  357.             SA_Title,            TITLEBAR,
  358.             SA_Colors,            Colours,
  359.             SA_Font,            &WormWars8,
  360.             SA_Pens,            Pens,
  361.             SA_Interleaved,        TRUE,
  362.             TAG_DONE
  363.         );
  364.     } else
  365.     {    ScreenPtr = (struct Screen *) OpenScreenTags
  366.         (    NULL,
  367.             SA_Width,            640,
  368.             SA_Height,            256,
  369.             SA_Depth,            DEPTH,
  370.             SA_DisplayID,        HIRES_KEY | PAL_MONITOR_ID,
  371.             SA_Title,            TITLEBAR,
  372.             SA_Colors,            Colours,
  373.             SA_Font,            &WormWars8,
  374.             SA_Pens,            Pens,
  375.             TAG_DONE
  376.         );
  377.     }
  378.     if (!ScreenPtr)
  379.     {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen!\0", 24);
  380.         cleanexit(EXIT_FAILURE);
  381. }    }
  382. else
  383. {    if (!error)
  384.         error = 2;
  385.  
  386.     if (IntuitionBase->LibNode.lib_Version >= 39) // if we're running on OS3.0+
  387.     {    ScreenPtr = (struct Screen *) OpenScreenTags
  388.         (    NULL,
  389.             SA_Width,            640,
  390.             SA_Height,            256,
  391.             SA_Depth,            DEPTH,
  392.             SA_DisplayID,        HIRES_KEY | PAL_MONITOR_ID,
  393.             SA_Title,            TITLEBAR,
  394.                 SA_Colors,            Colours,
  395.                 SA_Font,            &Topaz8,
  396.             SA_Pens,            Pens,
  397.             SA_Interleaved,            TRUE,
  398.             TAG_DONE
  399.         );
  400.     } else
  401.     {    ScreenPtr = (struct Screen *) OpenScreenTags
  402.         (    NULL,
  403.             SA_Width,            640,
  404.             SA_Height,            256,
  405.             SA_Depth,            DEPTH,
  406.             SA_DisplayID,        HIRES_KEY | PAL_MONITOR_ID,
  407.             SA_Title,            TITLEBAR,
  408.                 SA_Colors,            Colours,
  409.                 SA_Font,            &Topaz8,
  410.             SA_Pens,            Pens,
  411.             TAG_DONE
  412.         );
  413.     }
  414.     if (!ScreenPtr)
  415.     {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen nor font!\0", 24);
  416.         cleanexit(EXIT_FAILURE);
  417. }    }
  418.  
  419. /* For some reason, we lose 2 memory chunks: 264 bytes and 10 bytes. This
  420. seems perhaps to not be our fault. */
  421.  
  422. // GadTools
  423.  
  424. if (!(CycleGadget.ng_VisualInfo = StringGadget.ng_VisualInfo = CheckboxGadget.ng_VisualInfo = VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)))
  425. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't get GadTools visual info!\0", 24);
  426.     cleanexit(EXIT_FAILURE);
  427. }
  428. if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
  429. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create menus!\0", 24);
  430.     cleanexit(EXIT_FAILURE);
  431. }
  432. if (!(LayoutMenus(MenuPtr, VisualInfoPtr, TAG_DONE)))
  433. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't lay out menus!\0", 24);
  434.     cleanexit(EXIT_FAILURE);
  435. }
  436. if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
  437. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools context!\0", 24);
  438.     cleanexit(EXIT_FAILURE);
  439. }
  440. for (player = 0; player <= 3; player++)
  441. {    CycleGadget.ng_TopEdge = 184 + (player * (FONTX + 8));
  442.     CycleGadget.ng_GadgetText = CycleText[player];
  443.     CycleGadgetPtr[player] = PrevGadgetPtr = (struct Gadget *) CreateGadget
  444.     (    CYCLE_KIND,
  445.         PrevGadgetPtr,
  446.         &CycleGadget,
  447.         GTCY_Labels, CycleOptions[player],
  448.         GTCY_Active, worm[player].control,
  449.         GT_Underscore, '_',
  450.         GA_Disabled, TRUE,
  451.         TAG_DONE
  452.     );
  453. }
  454. CheckboxGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  455. (    CHECKBOX_KIND,
  456.     PrevGadgetPtr,
  457.     &CheckboxGadget,
  458.     GTCB_Checked, iso,
  459.     GT_Underscore, '_',
  460.     GA_Disabled, TRUE,
  461.     TAG_DONE
  462. );
  463.  
  464. // main window
  465.  
  466. if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
  467.     WA_Top,                11,
  468.     WA_Width,            SCREENXPIXEL,
  469.     WA_Height,            SCREENYPIXEL,
  470.     WA_IDCMP,           IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | CYCLEIDCMP | STRINGIDCMP | CHECKBOXIDCMP | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS,
  471.     WA_Gadgets,            GListPtr,
  472.     WA_CustomScreen,    ScreenPtr,
  473.     WA_Borderless,        TRUE,
  474.     WA_Activate,        TRUE,
  475.     WA_SmartRefresh,    TRUE,
  476.     WA_RptQueue,        16,
  477.     TAG_DONE)))
  478.     {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open main window!\0", 24);
  479.         cleanexit(EXIT_FAILURE);
  480.     }
  481.  
  482. // redirection of AmigaDOS system requesters
  483.     
  484. OldWindowPtr = ProcessPtr->pr_WindowPtr;
  485. ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;
  486.  
  487. if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, PATTERN, ASL_Window, MainWindowPtr, TAG_DONE)))
  488. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create ASL request!\0", 24);
  489.     cleanexit(EXIT_FAILURE);
  490. }
  491.  
  492. /* String gadgets: first the window is opened with the cycle and
  493. checkbox gadgets.
  494.     It is necessary not to display the string gadgets yet, so the
  495. gadgets are then created and added to the gadget list. You will note
  496. there is no command given to render them as yet. When the attributes
  497. are modified at highscore time, the applicable gadget is refreshed
  498. then. */
  499.  
  500. for (which = 0; which <= HISCORES; which++)
  501. {    StringGadget.ng_TopEdge = 104 + (which * HISCOREDISTANCE);
  502.     StringGadgetPtr[which] = PrevGadgetPtr = (struct Gadget *) CreateGadget(STRING_KIND, PrevGadgetPtr, &StringGadget, GTST_MaxChars, NAMELENGTH, STRINGA_ReplaceMode, TRUE, GA_Disabled, TRUE, TAG_DONE);
  503. }
  504. if (!PrevGadgetPtr)
  505. {    DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools gadgets!\0", 24);
  506.     cleanexit(EXIT_FAILURE);
  507. }
  508.  
  509. if (iconfailed)
  510. {    say("Can't open icon.library!", RED);
  511.     anykey(TRUE);
  512. }
  513. if (error == 1)
  514. {    say("Can't open diskfont.library!", RED);
  515.     anykey(TRUE);
  516. } else if (error == 2)
  517. {    say("Can't open WormWars.font!", RED);
  518.     anykey(TRUE);
  519. }
  520.  
  521. if (!(JoyPortPtr = (struct MsgPort *) CreateMsgPort()))
  522. {    say("Can't create joystick message port!", BLUE);
  523.     anykey(TRUE);
  524. } else if (!(JoyRqPtr = (struct IOStdReq *) CreateIORequest(JoyPortPtr, sizeof(struct IOStdReq))))
  525. {    say("Can't create joystick I/O request!", BLUE);
  526.     anykey(TRUE);
  527. } else if (JoyClosed = OpenDevice("gameport.device", 1, JoyRqPtr, 0))
  528. {    say("Can't open gameport.device!", BLUE);
  529.     anykey(TRUE);
  530. } else
  531. {    Forbid();
  532.     JoyRqPtr->io_Command        = GPD_ASKCTYPE;
  533.     JoyRqPtr->io_Length            = 1;
  534.     JoyRqPtr->io_Flags            = IOF_QUICK;
  535.     JoyRqPtr->io_Data            = (APTR) &Controller;
  536.     DoIO(JoyRqPtr);
  537.     if (Controller == GPCT_NOCONTROLLER)
  538.     {    Controller                = GPCT_ABSJOYSTICK;
  539.         JoyRqPtr->io_Command    = GPD_SETCTYPE;
  540.         JoyRqPtr->io_Length     = 1;
  541.         JoyRqPtr->io_Data        = (APTR) &Controller;
  542.         DoIO(JoyRqPtr);
  543.         success = TRUE;
  544.     }
  545.     Permit();
  546.     /* Note that say(), anykey() calls must be outside the
  547.     Forbid()/Permit() pair. */
  548.     if (success)
  549.     {    JoyRqPtr->io_Command    = GPD_SETTRIGGER;
  550.         JoyRqPtr->io_Data        = (APTR) &Trigger;
  551.         JoyRqPtr->io_Length        = sizeof(struct GamePortTrigger);
  552.         DoIO(JoyRqPtr);
  553.         sendreadrequest();
  554.         joy = TRUE;
  555.     } else
  556.     {    say("Gameport already in use!", BLUE);
  557.         anykey(TRUE);
  558. }    }
  559.  
  560. /* By default, preload music and sound effects at startup.
  561. musicable and fxable values are:
  562.  
  563. 0: tried and failed
  564. 1: tried and succeeded
  565. 2: untried, will load at startup
  566. 3: untried, will load when needed */
  567.  
  568. if (musicable == 2)
  569.     loadthemusic();
  570. if (fxable == 2)
  571.     loadthefx();
  572.  
  573. if (fxable == 1)
  574.     toggle(F);
  575. else if (musicable == 1)
  576.     toggle(M);
  577.  
  578. say("Loading fieldset...", WHITE);
  579. if (argument)
  580.     if (loadfields(pathname))
  581.     {    strcpy(saystring, "Can't open ");
  582.         strcat(saystring, pathname);
  583.         strcat(saystring, "!");
  584.         say(saystring, RED);
  585.         anykey(TRUE);
  586.         argument = FALSE;
  587.         pathname = DEFAULTSET;
  588.     }
  589. if (!argument)
  590.     if (loadfields(DEFAULTSET))
  591.     {    strcpy(saystring, "Can't open ");
  592.         strcat(saystring, DEFAULTSET);
  593.         strcat(saystring, "!");
  594.         say(saystring, RED);
  595.         anykey(TRUE);
  596.         newfields();
  597.     }
  598.  
  599. while (1)
  600. {    titlescreen();
  601.  
  602.     // MAIN GAME LOOP -------------------------------------------------
  603.  
  604.     while (a == PLAYGAME)
  605.     {    if (!(++r % VERYSLOW))
  606.         {    GetSysTime(CurrentValPtr);
  607.             SubTime(CurrentValPtr, StartValPtr);
  608.             secondsleft = secondsperlevel - CurrentValPtr->tv_secs;
  609.             timeloop();
  610.         }
  611.         TimerRqPtr->tr_node.io_Command    = TR_ADDREQUEST;
  612.         TimerRqPtr->tr_time.tv_secs        = 0;
  613.         TimerRqPtr->tr_time.tv_micro    = delay;
  614.         SendIO(TimerRqPtr);
  615.         gameloop();
  616.         if (CheckIO(TimerRqPtr))
  617.             draw(CLOCKICON, ICONY, CLOCK);
  618.         else
  619.             draw(CLOCKICON, ICONY, BLACKENED);
  620.         WaitIO(TimerRqPtr);
  621.     }
  622.     say("Title Screen", WHITE);
  623. }
  624. }
  625.  
  626. // SUPPORT FUNCTIONS -----------------------------------------------------
  627.  
  628. /* NAME     anykey -- wait for a user press
  629. SYNOPSIS    anykey(ABOOL);
  630. FUNCTION    Waits for a user response. Optional automatic timeout.
  631. INPUTS      timeout - timeout?
  632. RESULTS     FALSE if user presses Escape, TRUE otherwise.
  633. FILE        system.c */
  634.  
  635. ABOOL anykey(ABOOL timeout)
  636. {    ABOOL                    done        = FALSE;
  637.     SBYTE                    count        = 0;
  638.     UWORD                    code, qual;
  639.     ULONG                    class;
  640.     struct IntuiMessage*    MsgPtr;
  641.  
  642.     clearkybd();
  643.     Forbid();
  644.     MainWindowPtr->Flags |= WFLG_RMBTRAP;
  645.     Permit();
  646.     
  647.     while (!done)
  648.     {    if (joy && GetMsg(JoyPortPtr))
  649.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  650.                 done = TRUE;
  651.             sendreadrequest();
  652.         }
  653.         if (joy)
  654.         {    Wait((1L << MainWindowPtr->UserPort->mp_SigBit) | (1L << JoyPortPtr->mp_SigBit));
  655.             while (GetMsg(JoyPortPtr))
  656.             {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  657.                     done = TRUE;
  658.                 sendreadrequest();
  659.         }    }
  660.         else Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  661.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  662.         {    class = MsgPtr->Class;
  663.             code  = MsgPtr->Code;
  664.             qual  = MsgPtr->Qualifier;
  665.             GT_ReplyIMsg(MsgPtr);
  666.             switch(class)
  667.             {
  668.             case IDCMP_RAWKEY:
  669.                 if ((!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
  670.                 {    done = TRUE;
  671.                     if (code == M)
  672.                         toggle(M);
  673.                     else if (code == F)
  674.                         toggle(F);
  675.                     else if (code == ESCAPE)
  676.                     {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  677.                         {    if (verify())
  678.                                 cleanexit(EXIT_SUCCESS);
  679.                         } else
  680.                         {    Forbid();
  681.                             MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  682.                             Permit();
  683.                             return FALSE;
  684.                 }   }    }
  685.                 break;
  686.             case IDCMP_CLOSEWINDOW:
  687.                 cleanexit(EXIT_SUCCESS);
  688.                 break;
  689.             case IDCMP_ACTIVEWINDOW:
  690.                 ignore = TRUE;
  691.                 break;
  692.             case IDCMP_MOUSEBUTTONS:
  693.                 if ((code == SELECTDOWN || code == MENUDOWN) && !(qual & IEQUALIFIER_REPEAT))
  694.                     if (ignore)
  695.                         ignore = FALSE;
  696.                     else done = TRUE;
  697.                 break;
  698.             case IDCMP_INTUITICKS:
  699.                 if (timeout && ++count > PATIENCE)
  700.                     done = TRUE;
  701.                 break;
  702.             default:
  703.                 break;
  704.     }    }    }
  705.  
  706.     Forbid();
  707.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  708.     Permit();
  709.     return TRUE;
  710. }
  711.  
  712. void celebrate(void)
  713. {    ABOOL                    done = FALSE;
  714.     ULONG                    class;
  715.     UWORD                    code, qual;
  716.     struct IntuiMessage*    MsgPtr;
  717.     UBYTE                   player;
  718.  
  719.     for (player = 0; player <= 3; player++)
  720.         if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  721.              worm[player].hiscore = worm[player].score;
  722.     waitasec();
  723.     clearkybd();
  724.     while (!done)
  725.     {    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  726.         {    class = MsgPtr->Class;
  727.             code  = MsgPtr->Code;
  728.             qual  = MsgPtr->Qualifier;
  729.             GT_ReplyIMsg(MsgPtr);
  730.             switch (class)
  731.             {
  732.             case IDCMP_RAWKEY:
  733.                 if (code == ESCAPE)
  734.                 {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  735.                     {    if (verify())
  736.                             cleanexit(EXIT_SUCCESS);
  737.                     } else
  738.                         done = TRUE;
  739.                 }
  740.                 else if (code == RETURN || code == ENTER || code == SPACEBAR)
  741.                     done = TRUE;
  742.                 else if (code == M)
  743.                     toggle(M);
  744.                 else if (code == F)
  745.                     toggle(F);
  746.                 break;
  747.             case IDCMP_MOUSEBUTTONS:
  748.                 if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
  749.                     if (ignore)
  750.                         ignore = FALSE;
  751.                     else done = TRUE;
  752.                 break;
  753.             case IDCMP_ACTIVEWINDOW:
  754.                 ignore = TRUE;
  755.                 break;
  756.             case IDCMP_CLOSEWINDOW:
  757.                 cleanexit(EXIT_SUCCESS);
  758.                 break;
  759.             default:
  760.                 break;
  761.         }    }
  762.         if (joy && GetMsg(JoyPortPtr))
  763.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  764.                 done = TRUE;
  765.             sendreadrequest();
  766.         }
  767.         SetRGB4(&ScreenPtr->ViewPort, 17, rand() % 16, rand() % 16, rand() % 16);
  768.         draw(rand() % (FIELDX + 1), rand() % (FIELDY + 1), rand() % LASTOBJECT);
  769.     }
  770.     SetRGB4(&ScreenPtr->ViewPort, 17, 14, 4, 4);
  771.     a = GAMEOVER;
  772. }
  773.  
  774. void cleanexit(SLONG rc)
  775. {   SBYTE i;
  776.     
  777. if (TimerRqPtr && (!CheckIO(TimerRqPtr)))
  778.                     {    AbortIO(TimerRqPtr);
  779.                         WaitIO(TimerRqPtr);                                }
  780.                         freefx();
  781.                         for (i = 0; i <= SAMPLES; i++)
  782.                             if (sbase[i])
  783.                                 FreeMem(sbase[i], ssize[i]);
  784. if (mode == MUSIC)        StopPlayer();
  785. if (SongPtr)            UnLoadModule(SongPtr);
  786. if (MEDPlayerBase)    {    FreePlayer();
  787.                         CloseLibrary(MEDPlayerBase);                    }
  788.  
  789. if (joy)            {    AbortIO(JoyRqPtr);
  790.                         WaitIO(JoyRqPtr);                                }
  791. if (Controller != GPCT_NOCONTROLLER)
  792.                     {    Forbid();
  793.                         Controller                = GPCT_NOCONTROLLER;
  794.                         JoyRqPtr->io_Command    = GPD_SETCTYPE;
  795.                         JoyRqPtr->io_Length        = 1;
  796.                         JoyRqPtr->io_Data        = (APTR) &Controller;
  797.                         DoIO(JoyRqPtr);
  798.                         Permit();                                        }
  799. if (!JoyClosed)            CloseDevice(JoyRqPtr);
  800. if (JoyRqPtr)            DeleteIORequest(JoyRqPtr);
  801. if (JoyPortPtr)            DeleteMsgPort(JoyPortPtr);
  802.  
  803. if (ASLRqPtr)            FreeAslRequest(ASLRqPtr);
  804. if (OldWindowPtr)        ProcessPtr->pr_WindowPtr = OldWindowPtr;
  805. if (MainWindowPtr)    {    clearkybd();
  806.                         ClearMenuStrip(MainWindowPtr);
  807.                         CloseWindow(MainWindowPtr);                        }
  808. if (GListPtr)            FreeGadgets(GListPtr);
  809. if (MenuPtr)            FreeMenus(MenuPtr);
  810. if (VisualInfoPtr)        FreeVisualInfo(VisualInfoPtr);
  811. if (ScreenPtr)            CloseScreen(ScreenPtr);
  812. if (FontPtr)            CloseFont(FontPtr);
  813. if (!TimerClosed)        CloseDevice(TimerRqPtr);
  814. if (TimerRqPtr)            DeleteIORequest(TimerRqPtr);
  815. if (TimerPortPtr)        DeleteMsgPort(TimerPortPtr);
  816. if (PausedValPtr)        FreeMem(PausedValPtr, sizeof(struct timeval));
  817. if (CurrentValPtr)        FreeMem(CurrentValPtr, sizeof(struct timeval));
  818. if (StartValPtr)        FreeMem(StartValPtr, sizeof(struct timeval));
  819. if (!InputClosed)        CloseDevice(InputRqPtr);
  820. if (InputRqPtr)            DeleteIORequest(InputRqPtr);
  821. if (InputPortPtr)        DeleteMsgPort(InputPortPtr);
  822. if (DiskFontBase)        CloseLibrary(DiskFontBase);
  823. if (UtilityBase)        CloseLibrary(UtilityBase);
  824. if (ASLBase)            CloseLibrary(ASLBase);
  825. if (GadToolsBase)        CloseLibrary(GadToolsBase);
  826. if (GfxBase)            CloseLibrary(GfxBase);
  827. if (IconBase)            CloseLibrary(IconBase);
  828. if (IntuitionBase)    {    OpenWorkBench();
  829.                         CloseLibrary(IntuitionBase);                    }
  830.                         SetTaskPri((struct Task *) ProcessPtr, OldPri);
  831. if (ArgsPtr)            FreeArgs(ArgsPtr);
  832.                         exit(rc);                // End of program.
  833. }
  834.  
  835. void clearjoystick(void)
  836. {    if (joy)
  837.         while (GetMsg(JoyPortPtr))
  838.             sendreadrequest();
  839. }
  840.  
  841. void clearkybd(void)
  842. {    struct IntuiMessage* MsgPtr;
  843.  
  844.     while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  845.         GT_ReplyIMsg(MsgPtr);
  846. }
  847.  
  848. void draw(SBYTE x, SBYTE y, SBYTE image)
  849. {    SWORD pixx;
  850.     
  851.     /* Isometric methodology:
  852.     
  853.     read the colour of the pixel, then set the colour in the image
  854.     to the same value.
  855.  
  856.     So if, for the top left pixel, we read colour 10 (= $A or %1010),
  857.     we have to clear the relevant bits in plane 0 and 2, and set them
  858.     in planes 1 and 3.
  859.  
  860.     plane 0 (least significant bit)
  861.         1234567890123456 pixels for top row (y = 0)
  862.         1234567890123456 pixels for next row (y = 1)
  863.         : : :
  864.     plane 1
  865.         : : :
  866.  
  867.      01234567890
  868.     0..#########
  869.     1..#########
  870.     2.#########.
  871.     3.#########.
  872.     4#########..
  873.     5#########..
  874.  
  875.     Image is effectively 9*6, but requires an 11*6 bitmap.
  876.  
  877.      31
  878.      268421
  879.      731000521
  880.      689942152631
  881.      8426842684268421
  882.      **.......**..... */
  883.  
  884.     if (a == PLAYGAME && iso)
  885.     {    IsoImage.ImageData = IsoImageData[image];
  886.         pixx = (x * ISOSQUAREX) + 20 + ((FIELDY - y) * 3);
  887.         pixy = (y * ISOSQUAREY) + STARTYPIXEL;
  888.         preserve(pixx,      0, image, 32768);
  889.         preserve(pixx,      1, image, 32768);
  890.         preserve(pixx,      2, image, 32768);
  891.         preserve(pixx,      3, image, 32768);
  892.         preserve(pixx +  1, 0, image, 16384);
  893.         preserve(pixx +  1, 1, image, 16384);
  894.         preserve(pixx +  9, 4, image,    64);
  895.         preserve(pixx +  9, 5, image,    64);
  896.         preserve(pixx + 10, 2, image,    32);
  897.         preserve(pixx + 10, 3, image,    32);
  898.         preserve(pixx + 10, 4, image,    32);
  899.         preserve(pixx + 10, 5, image,    32);
  900.         DrawImage
  901.         (    MainWindowPtr->RPort,
  902.             &IsoImage,
  903.             pixx,
  904.             pixy
  905.         );
  906.     } else
  907.     {    // blit square
  908.  
  909.         Image.ImageData = ImageData[image];
  910.         DrawImage
  911.         (    MainWindowPtr->RPort,
  912.             &Image,
  913.             STARTXPIXEL + (SQUAREX * x),
  914.             STARTYPIXEL + (SQUAREY * y)
  915.         );
  916. }    }
  917.  
  918. void preserve(SWORD x, SBYTE row, SBYTE image, UWORD amount)
  919. {    LONG colour;
  920.     
  921.     /* x = image top-left corner coordinate on destination screen.
  922.     row = y-row of the image.
  923.     image = image number
  924.     amount = value of the bit to be set/cleared. */
  925.  
  926.     colour = ReadPixel
  927.     (    MainWindowPtr->RPort,
  928.         x,
  929.         pixy + row
  930.     );
  931.     if (colour & 8)
  932.         IsoImageData[image][row + 18] |= amount;
  933.     else IsoImageData[image][row + 18] &= ~amount;
  934.     if (colour & 4)
  935.         IsoImageData[image][row + 12] |= amount;
  936.     else IsoImageData[image][row + 12] &= ~amount;
  937.     if (colour & 2)
  938.         IsoImageData[image][row + 6] |= amount;
  939.     else IsoImageData[image][row + 6] &= ~amount;
  940.     if (colour & 1)
  941.         IsoImageData[image][row] |= amount;
  942.     else IsoImageData[image][row] &= ~amount;
  943. }
  944.  
  945. void effect(SBYTE index)
  946. {           SBYTE    i;
  947.             SBYTE    ok                = -1;
  948.             ULONG   oldestreceipt    = (ULONG) -1L;
  949.     PERSIST    ULONG   receipt            = 1L;
  950.  
  951.     /* oldestreceipt = temporary variable for ascertaining oldest
  952.     sound still playing.
  953.     receipt = next unused receipt number (monotonically incrementing). */
  954.  
  955.     if (mode == FX)
  956.     {    for (i = 0; i <= 3; i++)
  957.         {    // decide on a channel
  958.  
  959.             if (ok == -1)
  960.             {    if (!eversent[i])
  961.                     ok = i;
  962.                 else if (CheckIO(AudioRqPtr[i]))
  963.                 {    WaitIO(AudioRqPtr[i]);
  964.                     ok = i;
  965.         }    }    }
  966.         if (ok == -1)
  967.         {   for (i = 0; i <= 3; i++)
  968.                 if (receipter[i] < oldestreceipt)
  969.                 {   ok = i;
  970.                     oldestreceipt = receipter[i];
  971.                 }
  972.             AbortIO(AudioRqPtr[ok]);
  973.             WaitIO(AudioRqPtr[ok]);
  974.         }
  975.         eversent[ok] = TRUE;
  976.         AudioRqPtr[ok]->ioa_Cycles                = 1;
  977.         AudioRqPtr[ok]->ioa_Request.io_Command  = CMD_WRITE;
  978.         AudioRqPtr[ok]->ioa_Request.io_Flags    = ADIOF_PERVOL;
  979.         AudioRqPtr[ok]->ioa_Request.io_Unit     = (1 << ok);
  980.         AudioRqPtr[ok]->ioa_Volume              = samp[index].volume;
  981.         AudioRqPtr[ok]->ioa_Period              = (UWORD) speed[index];
  982.         AudioRqPtr[ok]->ioa_Request.io_Message.mn_ReplyPort
  983.                                                 = AudioPortPtr[ok];
  984.         AudioRqPtr[ok]->ioa_Data                = (UBYTE *) sbase[index];
  985.         AudioRqPtr[ok]->ioa_Length              = length[index][yes[index]];
  986.         BeginIO(AudioRqPtr[ok]);
  987.         receipter[ok] = receipt;
  988. }   }
  989.  
  990. void fieldedit(void)
  991. {        UBYTE                    oldbrush = ANYTHING, stamp;
  992.         SBYTE                    deltax = 0, deltay = 0, lastx, lasty, pointerx, pointery, which, x, y;
  993.         UWORD                    code, qual;
  994.         ULONG                    class;
  995.         struct IntuiMessage*    MsgPtr;
  996.         ABOOL                    leftdown = FALSE, rightdown = FALSE, timer = FALSE;
  997.         struct MenuItem*        ItemPtr;
  998. PERSIST    SBYTE                    clipboard[FIELDX + 1][FIELDY + 1];
  999. PERSIST    ABOOL                    clipboarded = FALSE;
  1000.  
  1001. say("Field Editor", WHITE);
  1002. setpointer(brush);
  1003. if (level > levels)
  1004.     level = levels;
  1005. OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
  1006. OnMenu(MainWindowPtr, FULLMENUNUM(MN_LEVEL, NOITEM, NOSUB));
  1007. if (!clipboarded)
  1008.     OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1009.  
  1010. // draw pseudo-gadgets
  1011.  
  1012. clearscreen();
  1013. for (which = 0; which <= 8; which++)
  1014.     DrawBevelBox(MainWindowPtr->RPort, STARTXPIXEL - 5 - (SQUAREX * 3), 40 + STARTYPIXEL + (which * SQUAREY * 3), SQUAREX + 9, SQUAREY + 4, GT_VisualInfo, VisualInfoPtr);
  1015. SetAPen(MainWindowPtr->RPort, WHITE);
  1016. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (  GOLDGADGET * SQUAREY));
  1017. Text(MainWindowPtr->RPort, "F1:", 3);
  1018. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (SILVERGADGET * SQUAREY));
  1019. Text(MainWindowPtr->RPort, "F2:", 3);
  1020. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( EMPTYGADGET * SQUAREY));
  1021. Text(MainWindowPtr->RPort, "F3:", 3);
  1022. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (  WOODGADGET * SQUAREY));
  1023. Text(MainWindowPtr->RPort, "F4:", 3);
  1024. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( STONEGADGET * SQUAREY));
  1025. Text(MainWindowPtr->RPort, "F5:", 3);
  1026. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( METALGADGET * SQUAREY));
  1027. Text(MainWindowPtr->RPort, "F6:", 3);
  1028. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (   ONEGADGET * SQUAREY));
  1029. Text(MainWindowPtr->RPort, "F7:", 3);
  1030. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + (   TWOGADGET * SQUAREY));
  1031. Text(MainWindowPtr->RPort, "F8:", 3);
  1032. Move(MainWindowPtr->RPort, STARTXPIXEL - (FONTX * 8), STARTYPIXEL + 5 + ( STARTGADGET * SQUAREY));
  1033. Text(MainWindowPtr->RPort, "F9:", 3);
  1034. draw(GADGETX,   GOLDGADGET,   GOLD);
  1035. draw(GADGETX, SILVERGADGET, SILVER);
  1036. draw(GADGETX,  EMPTYGADGET,  EMPTY);
  1037. draw(GADGETX,   WOODGADGET,   WOOD);
  1038. draw(GADGETX,  STONEGADGET,  STONE);
  1039. draw(GADGETX,  METALGADGET,  METAL);
  1040. draw(GADGETX,    ONEGADGET,    ONE);
  1041. draw(GADGETX,    TWOGADGET,    TWO);
  1042. draw(GADGETX,  STARTGADGET,  START);
  1043. SetAPen(MainWindowPtr->RPort, BLACK);
  1044. RectFill
  1045. (    MainWindowPtr->RPort,
  1046.     STARTXPIXEL - SQUAREX - 1,
  1047.     UNDERLINEOFFSET - 1,
  1048.     STARTXPIXEL - SQUAREX + 3,
  1049.     UNDERLINEOFFSET + 4 + (SQUAREY * 25)
  1050. );
  1051. underline(brush);
  1052.  
  1053. turborender();
  1054. saylevel(WHITE);
  1055. clearkybd();
  1056. x = lastx = startx[level];
  1057. y = lasty = starty[level];
  1058.     
  1059. while (a == FIELDEDIT)
  1060. {    stamp = NOSQUARE;
  1061.  
  1062.     if (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  1063.     {    class = MsgPtr->Class;
  1064.         code  = MsgPtr->Code;
  1065.         qual  = MsgPtr->Qualifier;
  1066.         if (class == IDCMP_MENUVERIFY && MsgPtr->MouseX >= STARTXPIXEL && MsgPtr->MouseX <= ENDXPIXEL && MsgPtr->MouseY >= STARTYPIXEL && MsgPtr->MouseY <= ENDYPIXEL)
  1067.         {    MsgPtr->Code = MENUCANCEL;
  1068.             oldbrush = brush;
  1069.             brush = EMPTY;
  1070.             rightdown = TRUE;
  1071.         }
  1072.         ReplyMsg(MsgPtr);
  1073.         switch (class)
  1074.         {
  1075.         case IDCMP_MENUPICK:
  1076.             while (code != MENUNULL)
  1077.             {    ItemPtr = ItemAddress(MenuPtr, code);
  1078.                 switch (MENUNUM(code))
  1079.                 {
  1080.                 case MN_PROJECT:
  1081.                     switch (ITEMNUM(code))
  1082.                     {
  1083.                     case IN_NEW:
  1084.                         effect(FXFILENEW);
  1085.                         newfields();
  1086.                         say("New done.", WHITE);
  1087.                         break;
  1088.                     case IN_OPEN:
  1089.                         effect(FXFILEOPEN);
  1090.                         fileopen();
  1091.                         break;
  1092.                     case IN_SAVE:
  1093.                         effect(FXFILESAVE);
  1094.                         if (modified)
  1095.                         {    clearhiscores();
  1096.                             modified = FALSE;
  1097.                         }
  1098.                         filesaveas(FALSE);
  1099.                         break;
  1100.                     case IN_SAVEAS:
  1101.                         effect(FXFILESAVEAS);
  1102.                         if (modified)
  1103.                         {    clearhiscores();
  1104.                             modified = FALSE;
  1105.                         }
  1106.                         filesaveas(TRUE);
  1107.                         break;
  1108.                     case IN_ABOUT:
  1109.                         fileabout();
  1110.                         break;
  1111.                     case IN_QUIT:
  1112.                         if (verify())
  1113.                             cleanexit(EXIT_SUCCESS);
  1114.                         break;
  1115.                     default:
  1116.                         break;
  1117.                     }
  1118.                     break;
  1119.                 case MN_EDIT:
  1120.                     switch (ITEMNUM(code))
  1121.                     {
  1122.                     case IN_CUT:
  1123.                         effect(FXEDITCUT);
  1124.                         for (x = 0; x <= FIELDX; x++)
  1125.                             for (y = 0; y <= FIELDY; y++)
  1126.                                 clipboard[x][y] = board[level][x][y];
  1127.                         leveldelete();
  1128.                         clipboarded = TRUE;
  1129.                         modified = TRUE;
  1130.                         OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1131.                         break;
  1132.                     case IN_COPY:
  1133.                         effect(FXEDITCOPY);
  1134.                         for (x = 0; x <= FIELDX; x++)
  1135.                             for (y = 0; y <= FIELDY; y++)
  1136.                                 clipboard[x][y] = board[level][x][y];
  1137.                         clipboarded = TRUE;
  1138.                         OnMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, IN_PASTE, NOSUB));
  1139.                         break;
  1140.                     case IN_PASTE:
  1141.                         effect(FXEDITPASTE);
  1142.                         for (x = 0; x <= FIELDX; x++)
  1143.                             for (y = 0; y <= FIELDY; y++)
  1144.                                 board[level][x][y] = clipboard[x][y];
  1145.                         turborender();
  1146.                         modified = TRUE;
  1147.                         break;
  1148.                     default:
  1149.                         break;
  1150.                     }
  1151.                     break;
  1152.                 case MN_LEVEL:
  1153.                     switch (ITEMNUM(code))
  1154.                     {
  1155.                     case IN_INSERT:
  1156.                         levelinsert();
  1157.                         break;
  1158.                     case IN_DELETE:
  1159.                         effect(FXLEVELDELETE);
  1160.                         leveldelete();
  1161.                         break;
  1162.                     case IN_ERASE:
  1163.                         levelerase();
  1164.                         break;
  1165.                     case IN_APPEND:
  1166.                         levelappend();
  1167.                         break;
  1168.                     default:
  1169.                         break;
  1170.                     }
  1171.                     break;
  1172.                 default:
  1173.                     break;
  1174.                 }
  1175.                 code = ItemPtr->NextSelect;
  1176.             }
  1177.             break;
  1178.         case IDCMP_RAWKEY:
  1179.             lastx = x;
  1180.             lasty = y;
  1181.             switch(code)
  1182.             {
  1183.             case DELETE:
  1184.                 if (!(qual & IEQUALIFIER_REPEAT))
  1185.                 {    effect(FXCLICK);
  1186.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1187.                         level = 1;
  1188.                     else if (--level < 0)
  1189.                         level = levels;
  1190.                     saylevel(WHITE);
  1191.                     turborender();
  1192.                 }
  1193.                 break;
  1194.             case HELP:
  1195.                 if (!(qual & IEQUALIFIER_REPEAT))
  1196.                 {    effect(FXCLICK);
  1197.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1198.                         level = levels;
  1199.                     else if (++level > levels)
  1200.                         level = 0;
  1201.                     saylevel(WHITE);
  1202.                     turborender();
  1203.                 }
  1204.                 break;
  1205.             case M:
  1206.                 if (!(qual & IEQUALIFIER_REPEAT))
  1207.                     toggle(M);
  1208.                 break;
  1209.             case F:
  1210.                 if (!(qual & IEQUALIFIER_REPEAT))
  1211.                     toggle(F);
  1212.                 break;
  1213.             case ESCAPE:
  1214.                 if (!(qual & IEQUALIFIER_REPEAT))
  1215.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1216.                     {    if (verify())
  1217.                         cleanexit(EXIT_SUCCESS);
  1218.                     } else a = GAMEOVER;
  1219.             break;
  1220.             case SPACEBAR:
  1221.             case RETURN:
  1222.             case ENTER:
  1223.                 if (!(qual & IEQUALIFIER_REPEAT))
  1224.                     a = GAMEOVER;
  1225.             break;
  1226.             case N:
  1227.                 if (!(qual & IEQUALIFIER_REPEAT))
  1228.                 {    effect(FXFILENEW);
  1229.                     newfields();
  1230.                     say("New done.", WHITE);
  1231.                 }
  1232.             break;
  1233.             case O:
  1234.                 if (!(qual & IEQUALIFIER_REPEAT))
  1235.                 {    effect(FXFILEOPEN);
  1236.                     fileopen();
  1237.                 }
  1238.             break;
  1239.             case S:
  1240.                 if (!(qual & IEQUALIFIER_REPEAT))
  1241.                 {    effect(FXFILESAVE);
  1242.                     if (modified)
  1243.                     {    clearhiscores();
  1244.                         modified = FALSE;
  1245.                     }
  1246.                     filesaveas(FALSE);
  1247.                 }
  1248.                 break;
  1249.             case A:
  1250.                 if (!(qual & IEQUALIFIER_REPEAT))
  1251.                 {    effect(FXFILESAVEAS);
  1252.                     if (modified)
  1253.                     {    clearhiscores();
  1254.                         modified = FALSE;
  1255.                     }
  1256.                     filesaveas(TRUE);
  1257.                 }
  1258.             break;
  1259.             case Q:
  1260.                 if (!(qual & IEQUALIFIER_REPEAT))
  1261.                 {    if (verify())
  1262.                         cleanexit(EXIT_SUCCESS);
  1263.                 }
  1264.             break;
  1265.             case NUMERICOPEN:
  1266.                 effect(FXCLICK);
  1267.                 setpointer(NORMAL);
  1268.                 underline(-1);
  1269.                 if (brush-- == 0 || brush > LASTOBJECT)
  1270.                     brush = LASTOBJECT;
  1271.                 stamp = brush;
  1272.                 break;
  1273.             case NUMERICCLOSE:
  1274.                 effect(FXCLICK);
  1275.                 setpointer(NORMAL);
  1276.                 underline(-1);
  1277.                 if (++brush > LASTOBJECT)
  1278.                     brush = 0;
  1279.                 stamp = brush;
  1280.                 break;
  1281.             case I:
  1282.                 effect(FXCLICK);
  1283.                 if (!(qual & IEQUALIFIER_REPEAT))
  1284.                     levelinsert();
  1285.                 break;
  1286.             case D:
  1287.                 effect(FXCLICK);
  1288.                 if (!(qual & IEQUALIFIER_REPEAT) && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT)))
  1289.                 {    effect(FXLEVELDELETE);
  1290.                     leveldelete();
  1291.                 }
  1292.                 break;
  1293.             case E:
  1294.                 effect(FXCLICK);
  1295.                 if (!(qual & IEQUALIFIER_REPEAT) && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT)))
  1296.                     levelerase();
  1297.                 break;
  1298.             case K:
  1299.                 effect(FXCLICK);
  1300.                 if (!(qual & IEQUALIFIER_REPEAT))
  1301.                     levelappend();
  1302.             break;
  1303.             case C:
  1304.                 effect(FXPENGUINDEATH); // interesting
  1305.                 x = FIELDX / 2;
  1306.                 y = FIELDY / 2;
  1307.             break;
  1308.             case ALPHAONE:
  1309.                 effect(FXCLICK);
  1310.                 stamp = GOLD;
  1311.                 break;
  1312.             case ALPHATWO:
  1313.                 effect(FXCLICK);
  1314.                 stamp = SILVER;
  1315.                 break;
  1316.             case ALPHATHREE:
  1317.                 effect(FXCLICK);
  1318.                 stamp = EMPTY;
  1319.                 break;
  1320.             case ALPHAFOUR:
  1321.                 effect(FXCLICK);
  1322.                 stamp = WOOD;
  1323.                 break;
  1324.             case ALPHAFIVE:
  1325.                 effect(FXCLICK);
  1326.                 stamp = STONE;
  1327.                 break;
  1328.             case ALPHASIX:
  1329.                 effect(FXCLICK);
  1330.                 stamp = METAL;
  1331.                 break;
  1332.             case ALPHASEVEN:
  1333.                 effect(FXCLICK);
  1334.                 stamp = ONE;
  1335.                 break;
  1336.             case ALPHAEIGHT:
  1337.                 effect(FXCLICK);
  1338.                 stamp = TWO;
  1339.                 break;
  1340.             case ALPHANINE:
  1341.                 effect(FXCLICK);
  1342.                 stamp = START;
  1343.                 break;
  1344.             case F1:
  1345.                 if (!(qual & IEQUALIFIER_REPEAT))
  1346.                 {    effect(FXCLICK);
  1347.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1348.                         fillfield(GOLD);
  1349.                     else setbrush(GOLD);
  1350.                 }
  1351.                 break;
  1352.             case F2:
  1353.                 if (!(qual & IEQUALIFIER_REPEAT))
  1354.                 {    effect(FXCLICK);
  1355.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1356.                         fillfield(SILVER);
  1357.                     else setbrush(SILVER);
  1358.                 }
  1359.                 break;
  1360.             case F3:
  1361.                 if (!(qual & IEQUALIFIER_REPEAT))
  1362.                 {    effect(FXCLICK);
  1363.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1364.                         fillfield(EMPTY);
  1365.                     else setbrush(EMPTY);
  1366.                 }
  1367.                 break;
  1368.             case F4:
  1369.                 if (!(qual & IEQUALIFIER_REPEAT))
  1370.                 {    effect(FXCLICK);
  1371.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1372.                         fillfield(WOOD);
  1373.                     else setbrush(WOOD);
  1374.                 }
  1375.                 break;
  1376.             case F5:
  1377.                 if (!(qual & IEQUALIFIER_REPEAT))
  1378.                 {    effect(FXCLICK);
  1379.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1380.                         fillfield(STONE);
  1381.                     else setbrush(STONE);
  1382.                 }
  1383.                 break;
  1384.             case F6:
  1385.                 if (!(qual & IEQUALIFIER_REPEAT))
  1386.                 {    effect(FXCLICK);
  1387.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1388.                         fillfield(METAL);
  1389.                     else setbrush(METAL);
  1390.                 }
  1391.                 break;
  1392.             case F7:
  1393.                 if (!(qual & IEQUALIFIER_REPEAT))
  1394.                 {    effect(FXCLICK);
  1395.                     setbrush(ONE);
  1396.                 }
  1397.                 break;
  1398.             case F8:
  1399.                 if (!(qual & IEQUALIFIER_REPEAT))
  1400.                 {    effect(FXCLICK);
  1401.                     setbrush(TWO);
  1402.                 }
  1403.                 break;
  1404.             case F9:
  1405.                 if (!(qual & IEQUALIFIER_REPEAT))
  1406.                 {    effect(FXCLICK);
  1407.                     setbrush(START);
  1408.                 }
  1409.                 break;
  1410.             case NUMERICZERO:
  1411.                 effect(FXCLICK);
  1412.                 if (!(qual & IEQUALIFIER_REPEAT))
  1413.                 {    if (!sticky)
  1414.                     {    sticky = TRUE;
  1415.                         draw(STICKYICON, ICONY, STICKY);
  1416.                         stamp = brush;
  1417.                     } else
  1418.                     {    sticky = FALSE;
  1419.                         draw(STICKYICON, ICONY, BLACKENED);
  1420.                 }    }
  1421.                 break;
  1422.             case NUMERICDOT:
  1423.                 effect(FXCLICK);
  1424.                 if (!(qual & IEQUALIFIER_REPEAT))
  1425.                     stamp = brush;
  1426.                 break;
  1427.             case NUMERICFOUR:
  1428.             case LEFT:
  1429.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1430.                     x = 0;
  1431.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1432.                     x = xwrap(x - ALTJUMP);
  1433.                 else
  1434.                     x = xwrap(x - 1);
  1435.                 if (sticky)
  1436.                     stamp = brush;
  1437.                 break;
  1438.             case NUMERICSIX:
  1439.             case RIGHT:
  1440.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1441.                     x = FIELDX;
  1442.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1443.                     x = xwrap(x + ALTJUMP);
  1444.                 else
  1445.                     x = xwrap(x + 1);
  1446.                 if (sticky)
  1447.                     stamp = brush;
  1448.                 break;
  1449.             case NUMERICEIGHT:
  1450.             case UP:
  1451.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1452.                     y = 0;
  1453.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1454.                     y = ywrap(y - ALTJUMP);
  1455.                 else
  1456.                     y = ywrap(y - 1);
  1457.                 if (sticky)
  1458.                     stamp = brush;
  1459.                 break;
  1460.             case NUMERICFIVE:
  1461.             case NUMERICTWO:
  1462.             case DOWN:
  1463.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1464.                     y = FIELDY;
  1465.                 else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1466.                     y = ywrap(y + ALTJUMP);
  1467.                 else
  1468.                     y = ywrap(y + 1);
  1469.                 if (sticky)
  1470.                     stamp = brush;
  1471.                 break;
  1472.             case NUMERICSEVEN:
  1473.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1474.                 {    x = 0;
  1475.                     y = 0;
  1476.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1477.                 {    x = xwrap(x - ALTJUMP);
  1478.                     y = ywrap(y - ALTJUMP);
  1479.                 } else
  1480.                 {    x = xwrap(x - 1);
  1481.                     y = ywrap(y - 1);
  1482.                 }
  1483.                 if (sticky)
  1484.                     stamp = brush;
  1485.                 break;
  1486.             case NUMERICNINE:
  1487.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1488.                 {    x = FIELDX;
  1489.                     y = 0;
  1490.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1491.                 {    x = xwrap(x + ALTJUMP);
  1492.                     y = ywrap(y - ALTJUMP);
  1493.                 } else
  1494.                 {    x = xwrap(x + 1);
  1495.                     y = ywrap(y - 1);
  1496.                 }
  1497.                 if (sticky)
  1498.                     stamp = brush;
  1499.                 break;
  1500.             case NUMERICONE:
  1501.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1502.                 {    x = 0;
  1503.                     y = FIELDY;
  1504.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1505.                 {    x = xwrap(x - ALTJUMP);
  1506.                     y = ywrap(y + ALTJUMP);
  1507.                 } else
  1508.                 {    x = xwrap(x - 1);
  1509.                     y = ywrap(y + 1);
  1510.                 }
  1511.                 if (sticky)
  1512.                     stamp = brush;
  1513.                 break;
  1514.             case NUMERICTHREE:
  1515.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT) || (qual & IEQUALIFIER_CONTROL))
  1516.                 {    x = FIELDX;
  1517.                     y = FIELDY;
  1518.                 } else if ((qual & IEQUALIFIER_LALT) || (qual & IEQUALIFIER_RALT))
  1519.                 {    x = xwrap(x + ALTJUMP);
  1520.                     y = ywrap(y + ALTJUMP);
  1521.                 } else
  1522.                 {    x = xwrap(x + 1);
  1523.                     y = ywrap(y + 1);
  1524.                 }
  1525.                 if (sticky)
  1526.                     stamp = brush;
  1527.                 break;
  1528.             default:
  1529.                 break;
  1530.             }
  1531.             if (x != lastx || y != lasty)
  1532.             {    updatesquare(lastx, lasty);
  1533.                 if (stamp > LASTOBJECT)
  1534.                     dot(x, y);
  1535.             }
  1536.             break;
  1537.         case IDCMP_MOUSEBUTTONS:
  1538.             updatesquare(x, y);
  1539.             switch (code)
  1540.             {
  1541.             case SELECTUP:
  1542.                 leftdown = FALSE;
  1543.                 break;
  1544.             case SELECTDOWN:
  1545.                 effect(FXCLICK);
  1546.                 leftdown = TRUE;
  1547.                 break;
  1548.             case MENUUP:
  1549.                 rightdown = FALSE;
  1550.                 brush = oldbrush;
  1551.                 oldbrush = ANYTHING;
  1552.             break;
  1553.             default:
  1554.                 // MENUDOWN
  1555.             break;
  1556.             }
  1557.         break;
  1558.         case IDCMP_CLOSEWINDOW:
  1559.             cleanexit(EXIT_SUCCESS);
  1560.         break;
  1561.         case IDCMP_REFRESHWINDOW:
  1562.             GT_BeginRefresh(MainWindowPtr);
  1563.             GT_EndRefresh(MainWindowPtr, TRUE);
  1564.         break;
  1565.         default:
  1566.             // IDCMP_MENUVERIFY, IDCMP_INTUITICKS, IDCMP_ACTIVEWINDOW
  1567.         break;
  1568.     }    }
  1569.     else if (joy)
  1570.     {    if (GetMsg(JoyPortPtr))
  1571.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  1572.                 stamp = brush;
  1573.             deltax = (SBYTE) GameEvent.ie_position.ie_xy.ie_x;
  1574.             deltay = (SBYTE) GameEvent.ie_position.ie_xy.ie_y;
  1575.             if (GameEvent.ie_Qualifier == IEQUALIFIER_LEFTBUTTON)
  1576.                 stamp = brush;
  1577.             sendreadrequest();
  1578.         }
  1579.         if (deltax || deltay)
  1580.         {    if (!timer)
  1581.             {    TimerRqPtr->tr_node.io_Command = TR_ADDREQUEST;
  1582.                 TimerRqPtr->tr_time.tv_secs    = 0;
  1583.                 TimerRqPtr->tr_time.tv_micro   = JOYDELAY;
  1584.                 SendIO(TimerRqPtr);
  1585.                 timer = TRUE;
  1586.             } else if (CheckIO(TimerRqPtr))
  1587.             {    lastx = x;
  1588.                 lasty = y;
  1589.                 x = xwrap(x + deltax);
  1590.                 y = ywrap(y + deltay);    
  1591.                 updatesquare(lastx, lasty);
  1592.                 dot(x, y);
  1593.                 timer = FALSE;
  1594.     }    }    }
  1595.     if (leftdown || rightdown)
  1596.     {    pointerx = xpixeltosquare(MainWindowPtr->MouseX);
  1597.         pointery = ypixeltosquare(MainWindowPtr->MouseY);
  1598.         if (valid(pointerx, pointery))
  1599.         {    x = pointerx;
  1600.             y = pointery;
  1601.             stamp = brush;
  1602.             updatesquare(lastx, lasty);
  1603.         }
  1604.         else if (leftdown && pointerx == GADGETX &&
  1605.         (pointery == GOLDGADGET
  1606.         || pointery == SILVERGADGET
  1607.         || pointery == EMPTYGADGET
  1608.         || pointery == WOODGADGET
  1609.         || pointery == STONEGADGET
  1610.         || pointery == METALGADGET
  1611.         || pointery == ONEGADGET
  1612.         || pointery == TWOGADGET
  1613.         || pointery == STARTGADGET))
  1614.         {    switch (pointery)
  1615.             {
  1616.             case GOLDGADGET:
  1617.                 setbrush(GOLD);
  1618.                 break;
  1619.             case SILVERGADGET:
  1620.                 setbrush(SILVER);
  1621.                 break;
  1622.             case EMPTYGADGET:
  1623.                 setbrush(EMPTY);
  1624.                 break;
  1625.             case WOODGADGET:
  1626.                 setbrush(WOOD);
  1627.                 break;
  1628.             case STONEGADGET:
  1629.                 setbrush(STONE);
  1630.                 break;
  1631.             case METALGADGET:
  1632.                 setbrush(METAL);
  1633.                 break;
  1634.             case ONEGADGET:
  1635.                 setbrush(ONE);
  1636.                 break;
  1637.             case TWOGADGET:
  1638.                 setbrush(TWO);
  1639.                 break;
  1640.             case STARTGADGET:
  1641.                 setbrush(START);
  1642.                 break;
  1643.             default:
  1644.                 break;
  1645.     }    }    }
  1646.  
  1647.     if (stamp != NOSQUARE)
  1648.     {    if (stamp == START && board[level][x][y] != TELEPORT)
  1649.         {    if (x != startx[level] || y != starty[level])
  1650.             {    draw(startx[level], starty[level], EMPTY);
  1651.                 board[level][startx[level]][starty[level]] = EMPTY;
  1652.                 draw(x, y, START);
  1653.                 startx[level] = x;
  1654.                 starty[level] = y;
  1655.                 modified = TRUE;
  1656.                 clearthem = TRUE;
  1657.         }    }
  1658.         else if (x != startx[level] || y != starty[level])
  1659.         {    if (stamp == ONE || stamp == TWO)
  1660.             {    if (teleport[level][partner(stamp - ONE)].alive == FALSE || x != teleport[level][partner(stamp - ONE)].x || y != teleport[level][partner(stamp - ONE)].y)
  1661.                 {    if (teleport[level][stamp - ONE].alive == TRUE)
  1662.                     {    draw(teleport[level][stamp - ONE].x, teleport[level][stamp - ONE].y, EMPTY);
  1663.                         board[level][teleport[level][stamp - ONE].x][teleport[level][stamp - ONE].y] = EMPTY;
  1664.                     } else
  1665.                         teleport[level][stamp - ONE].alive = TRUE;
  1666.                     board[level][x][y] = TELEPORT;
  1667.                     draw(x, y, stamp);
  1668.                     teleport[level][stamp - ONE].x = x;
  1669.                     teleport[level][stamp - ONE].y = y;
  1670.                     modified = TRUE;
  1671.                     clearthem = TRUE;
  1672.             }    }
  1673.             else
  1674.             {    if (board[level][x][y] == TELEPORT)
  1675.                     if (teleport[level][0].alive == TRUE && x == teleport[level][0].x && y == teleport[level][0].y)
  1676.                         teleport[level][0].alive = FALSE;
  1677.                     else teleport[level][1].alive = FALSE;
  1678.                 draw(x, y, stamp);
  1679.                 board[level][x][y] = stamp;
  1680.                 dot(x, y);
  1681.                 modified = TRUE;
  1682.                 clearthem = TRUE;
  1683. }    }    }    }
  1684.  
  1685. // exit to title screen
  1686.  
  1687. OffMenu(MainWindowPtr, FULLMENUNUM(MN_EDIT, NOITEM, NOSUB));
  1688. OffMenu(MainWindowPtr, FULLMENUNUM(MN_LEVEL, NOITEM, NOSUB));
  1689. if (timer)
  1690. {    AbortIO(TimerRqPtr);
  1691.     WaitIO(TimerRqPtr);
  1692. }
  1693. if (oldbrush != ANYTHING)
  1694.     brush = oldbrush;
  1695. setpointer(NORMAL);
  1696. if (clearthem)
  1697.     clearhiscores();
  1698. matchteleports();
  1699. }
  1700.  
  1701. void fileabout(void)
  1702. {    ABOOL                    done = FALSE;
  1703.     SBYTE                    line;
  1704.     UWORD                    code, qual;
  1705.     ULONG                    class;
  1706.     struct Window*            AboutWindowPtr;
  1707.     struct IntuiMessage*    MsgPtr;
  1708.     SLONG                    projectval;
  1709.     TEXT                    projectstring[6];
  1710.  
  1711.     effect(FXAMIGAN);
  1712.     if (!(AboutWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1713.     WA_Left,            (SCREENXPIXEL / 2) - (ABOUTXPIXEL / 2),
  1714.     WA_Top,                (SCREENYPIXEL / 2) - (ABOUTYPIXEL / 2),
  1715.     WA_Width,            ABOUTXPIXEL,
  1716.     WA_Height,            ABOUTYPIXEL,
  1717.     WA_IDCMP,            IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  1718.     WA_Title,            "About Worm Wars",
  1719.     WA_Gadgets,            NULL,
  1720.     WA_CustomScreen,    ScreenPtr,
  1721.     WA_DragBar,            TRUE,
  1722.     WA_CloseGadget,        TRUE,
  1723.     WA_NoCareRefresh,    TRUE,
  1724.     WA_Activate,        TRUE,
  1725.     TAG_DONE)))
  1726.     {    say("Can't open About... window!", RED);
  1727.         anykey(TRUE);
  1728.     } else
  1729.     {    // calculate project size
  1730.         
  1731.         projectval =
  1732.             11                                                         // header
  1733.         +    ((HISCORES + 1) * (9 + NAMELENGTH + DATELENGTH + TIMELENGTH))
  1734.                                                                      // high scores
  1735.         +    ((levels + 1) * (7 + ((FIELDX + 1) * (FIELDY + 1))))     // level data
  1736.         +    levels
  1737.         +    strlen(VERSION)
  1738.                 +       1;
  1739.  
  1740.         SetAPen(AboutWindowPtr->RPort, worm[rand() % 4].colour);
  1741.         RectFill(AboutWindowPtr->RPort, 8, 13, ABOUTXPIXEL - 11, ABOUTYPIXEL - 6);
  1742.         SetAPen(AboutWindowPtr->RPort, ABOUTSHADOW);
  1743.         Move(AboutWindowPtr->RPort, 7, ABOUTYPIXEL - 5);
  1744.         Draw(AboutWindowPtr->RPort, 7, 12);
  1745.         Draw(AboutWindowPtr->RPort, ABOUTXPIXEL - 10, 12);
  1746.         SetAPen(AboutWindowPtr->RPort, ABOUTSHINE);
  1747.         Draw(AboutWindowPtr->RPort, ABOUTXPIXEL - 10, ABOUTYPIXEL - 5);
  1748.         Draw(AboutWindowPtr->RPort, 8, ABOUTYPIXEL - 5);
  1749.         SetAPen(AboutWindowPtr->RPort, BLACK);
  1750.         SetDrMd(AboutWindowPtr->RPort, JAM1);
  1751.         for (line = 0; line <= ABOUTLINES; line++)
  1752.         {    Move(AboutWindowPtr->RPort, about[line].x, about[line].y);
  1753.             Text(AboutWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
  1754.         }
  1755.         stcl_d(projectstring, projectval);
  1756.         align(projectstring, 5, ' ');
  1757.         Move(AboutWindowPtr->RPort, PROJECTX, PROJECTY);
  1758.         Text(AboutWindowPtr->RPort, projectstring, 5);
  1759.         DrawBevelBox(AboutWindowPtr->RPort, 18, 21, 49, 23, GT_VisualInfo, VisualInfoPtr);
  1760.         DrawImage(AboutWindowPtr->RPort, &About, 20, 23);
  1761.  
  1762.         while(!done)
  1763.         {    Wait(1L << AboutWindowPtr->UserPort->mp_SigBit);
  1764.             while (MsgPtr = (struct IntuiMessage *) GetMsg(AboutWindowPtr->UserPort))
  1765.             {    class = MsgPtr->Class;
  1766.                 code  = MsgPtr->Code;
  1767.                 qual  = MsgPtr->Qualifier;
  1768.                 ReplyMsg(MsgPtr);
  1769.                 switch(class)
  1770.                 {
  1771.                 case IDCMP_CLOSEWINDOW:
  1772.                     done = TRUE;
  1773.                     break;
  1774.                 case IDCMP_RAWKEY:
  1775.                        if (code == SPACEBAR || code == RETURN || code == ENTER || code == HELP)
  1776.                        done = TRUE;
  1777.                     else if (code == ESCAPE)
  1778.                         if (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1779.                         {    if (verify())
  1780.                             {   CloseWindow(AboutWindowPtr);
  1781.                                 cleanexit(EXIT_SUCCESS);
  1782.                         }    }
  1783.                         else done = TRUE;
  1784.                     break;
  1785.                 default:
  1786.                     break;
  1787.         }   }   }
  1788.         CloseWindow(AboutWindowPtr);
  1789.         clearkybd();
  1790. }    }
  1791.  
  1792. void fileopen(void)
  1793. {   TEXT temp1[81] = {"Opened "}, temp2[3], newpathname[255];
  1794.  
  1795.     strcpy(newpathname, pathname);
  1796.     if (AslRequestTags(ASLRqPtr, ASL_Hail, ASLOPENHAIL, ASL_FuncFlags, FILF_PATGAD, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
  1797.     {    strcpy(newpathname, ASLRqPtr->rf_Dir);
  1798.         AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1799.         if (!loadfields(newpathname))
  1800.         {   strcpy(pathname, newpathname);
  1801.             strcat(temp1, pathname);
  1802.             strcat(temp1, " (");
  1803.             stci_d(temp2, levels);
  1804.             strcat(temp1, temp2);
  1805.             strcat(temp1, " levels).");
  1806.             say(temp1, WHITE);
  1807.             if (a == FIELDEDIT)
  1808.                 turborender();
  1809.             else hiscores();
  1810.         } else
  1811.         {   strcpy(temp1, "Couldn't open ");
  1812.             strcat(temp1, newpathname);
  1813.             strcat(temp1, "!");
  1814.             say(temp1, WHITE);
  1815.     }   }
  1816.     if (a == GAMEOVER)
  1817.         anykey(TRUE);
  1818. }
  1819.  
  1820. void filesaveas(ABOOL flag)
  1821. {    ABOOL    cont = TRUE;
  1822.     TEXT    newpathname[255], temp1[SAYLIMIT + 1], temp2[3];
  1823.  
  1824.     // flag is TRUE for 'save as...', FALSE for 'save'.
  1825.  
  1826.     strcpy(newpathname, pathname);
  1827.     if (flag)
  1828.         if (AslRequestTags(ASLRqPtr, ASL_Hail, ASLSAVEHAIL, ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
  1829.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1830.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1831.         } else cont = FALSE;
  1832.     if (cont)
  1833.     {    strcpy(temp1, "Saving ");
  1834.         strcat(temp1, pathname);
  1835.         strcat(temp1, "...");
  1836.         say(temp1, WHITE);
  1837.         if (savefields(newpathname))
  1838.         {   strcpy(pathname, newpathname);
  1839.             strcpy(temp1, "Saved ");
  1840.             strcat(temp1, pathname);
  1841.             strcat(temp1, " (");
  1842.             stci_d(temp2, levels);
  1843.             strcat(temp1, temp2);
  1844.             strcat(temp1, " levels).");
  1845.         } else
  1846.         {   strcpy(temp1, "Couldn't save ");
  1847.             strcat(temp1, newpathname);
  1848.             strcat(temp1, "!");
  1849.         }
  1850.         say(temp1, WHITE);
  1851.         if (a == GAMEOVER)
  1852.             anykey(TRUE);
  1853. }   }
  1854.  
  1855. void freefx(void)
  1856. {    SBYTE i;
  1857.  
  1858.     stopfx(0L);
  1859.     if (!AudioClosed)
  1860.     {    CloseDevice((struct IORequest *) AudioRqPtr[0]);
  1861.         AudioClosed = TRUE;
  1862.     }
  1863.     for (i = 0; i <= 3; i++)
  1864.     {    if (AudioRqPtr[i])
  1865.         {    DeleteIORequest(AudioRqPtr[i]);
  1866.             AudioRqPtr[i] = NULL;
  1867.         }
  1868.         if (AudioPortPtr[i])
  1869.         {    DeleteMsgPort(AudioPortPtr[i]);
  1870.             AudioPortPtr[i] = NULL;
  1871.     }    }
  1872.     if (fbase)
  1873.     {    FreeMem(fbase, fsize);
  1874.         fbase = NULL;
  1875.     }
  1876.     if (FilePtr)
  1877.     {   Close(FilePtr);
  1878.         FilePtr = NULL;
  1879. }    }
  1880.  
  1881. void gameinput(void)
  1882. {        ABOOL                    done;
  1883.         UWORD                    code, qual;
  1884.         ULONG                    class;
  1885.         struct IntuiMessage*    MsgPtr;
  1886.         SBYTE                   keyplayer;
  1887.         UBYTE                   which;
  1888.  
  1889. for (which = 0; which <= NUMKEYS; which++)
  1890.     key[which].down = FALSE;
  1891.  
  1892. // keyboard
  1893.  
  1894. while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  1895. {    class  = MsgPtr->Class;
  1896.     code   = MsgPtr->Code;
  1897.     qual   = MsgPtr->Qualifier;
  1898.     ReplyMsg(MsgPtr);
  1899.     if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP)
  1900.     {    switch(code) {
  1901.         case M:
  1902.             toggle(M);
  1903.         break;
  1904.         case F:
  1905.             toggle(F);
  1906.         break;
  1907.         case P:
  1908.             clearkybd();
  1909.             say("Paused...press P to unpause", WHITE);
  1910.             pausetimer();
  1911.             done = FALSE;
  1912.             while (!done)
  1913.             {    Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  1914.                 while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  1915.                 {    class = MsgPtr->Class;
  1916.                     code  = MsgPtr->Code;
  1917.                     qual  = MsgPtr->Qualifier;
  1918.                     ReplyMsg(MsgPtr);
  1919.                     if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)))
  1920.                     {    if (code == ESCAPE)
  1921.                         {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1922.                             {    if (verify())
  1923.                                     cleanexit(EXIT_SUCCESS);
  1924.                             } else
  1925.                             {    a = GAMEOVER;
  1926.                                 done = TRUE;
  1927.                                 worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  1928.                         }    }
  1929.                         else if (code == M)
  1930.                             toggle(M);
  1931.                         else if (code == F)
  1932.                             toggle(F);
  1933.                         else if (code == P)
  1934.                         {    say("Unpaused", WHITE);
  1935.                             done = TRUE;
  1936.             }    }    }    }
  1937.             unpausetimer();
  1938.         break;
  1939.         case ESCAPE:
  1940.             if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1941.             {    if (verify())
  1942.                     cleanexit(EXIT_SUCCESS);
  1943.             } else
  1944.             {    a = GAMEOVER;
  1945.                 worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  1946.             }
  1947.         break;
  1948.         default:
  1949.             for (which = 0; which <= NUMKEYS; which++)
  1950.                 if (code == key[which].scancode)
  1951.                     key[which].down = TRUE;
  1952.         break;
  1953.     }    }    
  1954.     else if (class == IDCMP_CLOSEWINDOW)
  1955.         cleanexit(EXIT_SUCCESS);
  1956.     else if (class == IDCMP_REFRESHWINDOW)
  1957.     {   GT_BeginRefresh(MainWindowPtr);
  1958.         GT_EndRefresh(MainWindowPtr, TRUE);
  1959. }   }
  1960. /* Received but ignored: IDCMP_ACTIVEWINDOW, IDCMP_MOUSEBUTTONS and
  1961. IDCMP_INTUITICKS. */
  1962.  
  1963. for (which = 0; which <= NUMKEYS; which++)
  1964. {    if (key[which].down)
  1965.     {    if (key[which].special == ONEHUMAN)
  1966.         {    if (worm[0].control == HUMAN && worm[1].control != HUMAN)
  1967.                 queue(0, key[which].deltax, key[which].deltay);
  1968.             else if (worm[0].control != HUMAN && worm[1].control == HUMAN)
  1969.                 queue(1, key[which].deltax, key[which].deltay);
  1970.         } else if (key[which].special == MOVE || key[which].special == AMMO)
  1971.         {   if (worm[key[which].player].control == HUMAN)
  1972.                 keyplayer = key[which].player;
  1973.             else if (key[which].player == 1 && worm[0].control == HUMAN && worm[1].control != HUMAN)
  1974.                 keyplayer = 0;
  1975.             else if (key[which].player == 0 && worm[1].control == HUMAN && worm[0].control != HUMAN)
  1976.                 keyplayer = 1;
  1977.             else keyplayer = -1;
  1978.             if (keyplayer != -1)
  1979.                 queue(keyplayer, key[which].deltax, key[which].deltay);
  1980.         } else if (worm[1].lives) // assumes key[which].special == TRAINER
  1981.             train(key[which].scancode);
  1982. }    }
  1983.  
  1984. // joystick
  1985.  
  1986. if (worm[2].control == HUMAN)
  1987.     while (GetMsg(JoyPortPtr))
  1988.     {    if (GameEvent.ie_position.ie_xy.ie_x != 0 || GameEvent.ie_position.ie_xy.ie_y != 0)
  1989.             queue(2, GameEvent.ie_position.ie_xy.ie_x, GameEvent.ie_position.ie_xy.ie_y);
  1990.         if (GameEvent.ie_Code == IECODE_LBUTTON)
  1991.             queue(2, 0, 0);
  1992.         sendreadrequest();
  1993. }    }
  1994.  
  1995. void hiscores(void)
  1996. {    SBYTE                    which;
  1997.     TEXT                    tempstring[NAMELENGTH + 1];
  1998.  
  1999. /* render hiscores
  2000.  
  2001. #################################################### # = shadow
  2002. #   #   #   #                      #     #         % % = shine
  2003. #   #   #   #                      #     #         %
  2004. #   #   #   #                      #     #         %
  2005. #   #   #   #                      #     #         %
  2006. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
  2007.  
  2008. SetDrMd(MainWindowPtr->RPort, JAM1);
  2009. for (which = 0; which <= HISCORES; which++)
  2010. {    if (hiscore[which].player == -1)
  2011.         SetAPen(MainWindowPtr->RPort, LIGHTGREY);
  2012.     else SetAPen(MainWindowPtr->RPort, worm[hiscore[which].player].colour);
  2013.     RectFill(MainWindowPtr->RPort, 104, 105 + which * HISCOREDISTANCE, 536, 114 + which * HISCOREDISTANCE);
  2014.     if (hiscore[which].player == 0)
  2015.         SetAPen(MainWindowPtr->RPort, DARKGREEN);
  2016.     else if (hiscore[which].player == 1)
  2017.         SetAPen(MainWindowPtr->RPort, DARKRED);
  2018.     else if (hiscore[which].player == 2)
  2019.         SetAPen(MainWindowPtr->RPort, DARKBLUE);
  2020.     else if (hiscore[which].player == 3)
  2021.         SetAPen(MainWindowPtr->RPort, DARKYELLOW);
  2022.     else SetAPen(MainWindowPtr->RPort, DARKGREY);
  2023.     Move(MainWindowPtr->RPort, 103, 115 + which * HISCOREDISTANCE);
  2024.     Draw(MainWindowPtr->RPort, 103, 104 + which * HISCOREDISTANCE);
  2025.     Draw(MainWindowPtr->RPort, 537, 104 + which * HISCOREDISTANCE);
  2026.  
  2027.     if (hiscore[which].player != -1)
  2028.     {    // divider bars
  2029.     
  2030.         Move(MainWindowPtr->RPort, 182 - 55, 104 + which * HISCOREDISTANCE);
  2031.         Draw(MainWindowPtr->RPort, 182 - 55, 114 + which * HISCOREDISTANCE);
  2032.         Move(MainWindowPtr->RPort, 254 - 55, 104 + which * HISCOREDISTANCE);
  2033.         Draw(MainWindowPtr->RPort, 254 - 55, 114 + which * HISCOREDISTANCE);
  2034.         Move(MainWindowPtr->RPort, 290 - 55, 104 + which * HISCOREDISTANCE);
  2035.         Draw(MainWindowPtr->RPort, 290 - 55, 114 + which * HISCOREDISTANCE);
  2036.         Move(MainWindowPtr->RPort, 416, 104 + which * HISCOREDISTANCE);
  2037.         Draw(MainWindowPtr->RPort, 416, 114 + which * HISCOREDISTANCE);
  2038.         Move(MainWindowPtr->RPort, 464, 104 + which * HISCOREDISTANCE);
  2039.         Draw(MainWindowPtr->RPort, 464, 114 + which * HISCOREDISTANCE);
  2040.     }
  2041.     
  2042.     SetAPen(MainWindowPtr->RPort, WHITE);
  2043.     Move(MainWindowPtr->RPort, 159 - 55, 115 + which * HISCOREDISTANCE);
  2044.     Draw(MainWindowPtr->RPort, 482 + 55, 115 + which * HISCOREDISTANCE);
  2045.     Draw(MainWindowPtr->RPort, 482 + 55, 105 + which * HISCOREDISTANCE);
  2046.     SetAPen(MainWindowPtr->RPort, BLACK);
  2047.  
  2048.     if (hiscore[which].player != -1)
  2049.     {    stci_d(tempstring, which + 1);
  2050.         tempstring[1] = '.';
  2051.         Move(MainWindowPtr->RPort, 161 - 55, 112 + which * HISCOREDISTANCE);
  2052.         Text(MainWindowPtr->RPort, tempstring, 2);
  2053.         stci_d(tempstring, hiscore[which].score);
  2054.         align(tempstring, 7, ' ');
  2055.         Move(MainWindowPtr->RPort, 193 - 55, 112 + which * HISCOREDISTANCE);
  2056.         Text(MainWindowPtr->RPort, tempstring, 7);
  2057.         if (hiscore[which].level == -1)
  2058.             strcpy(tempstring, "All");
  2059.         else
  2060.         {    stci_d(tempstring, hiscore[which].level);
  2061.             align(tempstring, 3, ' ');
  2062.         }
  2063.         Move(MainWindowPtr->RPort, 206, 112 + which * HISCOREDISTANCE);
  2064.         Text(MainWindowPtr->RPort, tempstring, 3);
  2065.         Move(MainWindowPtr->RPort, 241, 112 + which * HISCOREDISTANCE);
  2066.         Text(MainWindowPtr->RPort, hiscore[which].name, strlen(hiscore[which].name));
  2067.         Move(MainWindowPtr->RPort, 418, 112 + which * HISCOREDISTANCE);
  2068.         Text(MainWindowPtr->RPort, hiscore[which].time, strlen(hiscore[which].time));
  2069.         Move(MainWindowPtr->RPort, 466, 112 + which * HISCOREDISTANCE);
  2070.         Text(MainWindowPtr->RPort, hiscore[which].date, strlen(hiscore[which].date));
  2071. }    }
  2072. SetDrMd(MainWindowPtr->RPort, JAM2);
  2073. }
  2074.  
  2075. void hiscorenames(void)
  2076. {
  2077. ULONG                    class;
  2078. ABOOL                    done;
  2079. SBYTE                    which;
  2080. struct IntuiMessage*    MsgPtr;
  2081.  
  2082. for (which = 0; which <= HISCORES; which++)
  2083.     if (hiscore[which].fresh)
  2084.     {    GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, FALSE, GTST_String, worm[hiscore[which].player].name, TAG_DONE);
  2085.         ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2086.         done = FALSE;
  2087.         while (!done)
  2088.         {    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2089.             {    class = MsgPtr->Class;
  2090.                 GT_ReplyIMsg(MsgPtr);
  2091.                 if (class == IDCMP_GADGETUP)
  2092.                     done = TRUE;
  2093.                 else if (class == IDCMP_MOUSEBUTTONS)
  2094.                     ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2095.                 else if (class == IDCMP_REFRESHWINDOW)
  2096.                 {    GT_BeginRefresh(MainWindowPtr);
  2097.                     GT_EndRefresh(MainWindowPtr, TRUE);
  2098.         }    }    }
  2099.         GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2100.         effect(FXHISCORE);
  2101.         strcpy(hiscore[which].name, ((struct StringInfo *) (StringGadgetPtr[which]->SpecialInfo))->Buffer);
  2102.         if (hiscore[which].name[0] >= 97 && hiscore[which].name[0] <= 123)
  2103.             hiscore[which].name[0] -= 32;
  2104.         strcpy(worm[hiscore[which].player].name, hiscore[which].name);
  2105.         hiscore[which].fresh = FALSE;
  2106.         hiscores();
  2107. }    }
  2108.  
  2109. ABOOL beginfx(void)
  2110. {           SBYTE    i;
  2111.     PERSIST    UBYTE    chan[]    = {15};
  2112.  
  2113.     for (i = 0; i <= 3; i++)
  2114.     {   eversent[i] = FALSE;
  2115.         if (!(AudioPortPtr[i] = (struct MsgPort *) CreateMsgPort()))
  2116.         {   freefx();
  2117.             draw(MUSICICON, ICONY, BLACKENED);
  2118.             mode = FALSE;
  2119.             say("No port for effects!", RED);
  2120.             anykey(TRUE);
  2121.             return FALSE;
  2122.         } else if (!(AudioRqPtr[i] = (struct IOAudio *) CreateIORequest(AudioPortPtr[i], sizeof(struct IOAudio))))
  2123.         {   freefx();
  2124.             draw(MUSICICON, ICONY, BLACKENED);
  2125.             mode = FALSE;
  2126.             say("No I/O memory for effects!", RED);
  2127.             anykey(TRUE);
  2128.             return FALSE;
  2129.     }   }
  2130.     AudioRqPtr[0]->ioa_Request.io_Message.mn_ReplyPort      = AudioPortPtr[0];
  2131.     AudioRqPtr[0]->ioa_Request.io_Message.mn_Node.ln_Pri    = 127;
  2132.     AudioRqPtr[0]->ioa_AllocKey                             = 0;
  2133.     AudioRqPtr[0]->ioa_Data                                 = chan;
  2134.     AudioRqPtr[0]->ioa_Length                               = 1;
  2135.     if (AudioClosed = OpenDevice(AUDIONAME, 0L, (struct IORequest *) AudioRqPtr[0], 0L))
  2136.     {   freefx();
  2137.         draw(MUSICICON, ICONY, BLACKENED);
  2138.         mode = FALSE;
  2139.         say("Can't allocate all channels for effects!", RED);
  2140.         anykey(TRUE);
  2141.         return FALSE;
  2142.     } else
  2143.     {   for (i = 1; i <= 3; i++)
  2144.             CopyMem(AudioRqPtr[0], AudioRqPtr[i], sizeof(struct IOAudio));
  2145.         return TRUE;
  2146. }   }
  2147.  
  2148. void resettime(void)
  2149. {    GetSysTime(StartValPtr);
  2150. }
  2151.  
  2152. void rundown(SBYTE player)
  2153. {    TEXT    tempstring[6];
  2154.     SBYTE    i, j, x, y;
  2155.     UWORD    counter = 0;
  2156.     ABOOL    done = FALSE;
  2157.     ULONG    levelbonus, timebonus, tailbonus;
  2158.     UBYTE   multiply = worm[player].multi * players;
  2159.  
  2160.     clearscreen();
  2161.     SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2162.  
  2163.     Image.ImageData = ImageData[TREASURE];
  2164.     DrawImage(MainWindowPtr->RPort, &Image, 201, 103);
  2165.     Move(MainWindowPtr->RPort, 218, 108);
  2166.     Text(MainWindowPtr->RPort, "Level Bonus:    ## x ##00 =", 27);
  2167.     stci_d(tempstring, multiply);
  2168.     align(tempstring, 2, ' ');
  2169.     Move(MainWindowPtr->RPort, 218 + (FONTX * 21), 108);
  2170.     Text(MainWindowPtr->RPort, tempstring, 2);
  2171.     stci_d(tempstring, level - 1);
  2172.     align(tempstring, 2, ' ');
  2173.     Move(MainWindowPtr->RPort, 218 + (FONTX * 16), 108);
  2174.     Text(MainWindowPtr->RPort, tempstring, 2);
  2175.  
  2176.     Image.ImageData = ImageData[CLOCK];
  2177.     DrawImage(MainWindowPtr->RPort, &Image, 201, 111);
  2178.     Move(MainWindowPtr->RPort, 218, 116);
  2179.     Text(MainWindowPtr->RPort, " Time Bonus: ##:## x  ##0 =", 27);
  2180.     stci_d(tempstring, multiply);
  2181.     align(tempstring, 2, ' ');
  2182.     Move(MainWindowPtr->RPort, 226 + (FONTX     * 21), 116);
  2183.     Text(MainWindowPtr->RPort, tempstring, 2);
  2184.     stci_d(tempstring, secondsleft / 60);
  2185.     align(tempstring, 2, ' ');
  2186.     Move(MainWindowPtr->RPort, 226 + (FONTX * 12), 116);
  2187.     Text(MainWindowPtr->RPort, tempstring, 2);
  2188.     stci_d(tempstring, secondsleft % 60);
  2189.     align(tempstring, 2, '0');
  2190.     Move(MainWindowPtr->RPort, 226 + (FONTX * 15), 116);
  2191.     Text(MainWindowPtr->RPort, tempstring, 2);
  2192.  
  2193.     Image.ImageData = ImageData[FIRSTTAIL + player];
  2194.     DrawImage(MainWindowPtr->RPort, &Image, 201, 119);
  2195.     Move(MainWindowPtr->RPort, 218, 124);
  2196.     Text(MainWindowPtr->RPort, " Tail Bonus:  #### x   ## =", 27);
  2197.     stci_d(tempstring, multiply);
  2198.     align(tempstring, 2, ' ');
  2199.     Move(MainWindowPtr->RPort, 226 + (FONTX * 22), 124);
  2200.     Text(MainWindowPtr->RPort, tempstring, 2);
  2201.     for (x = 0; x <= FIELDX; x++)
  2202.         for (y = 0; y <= FIELDY; y++)
  2203.             if (field[x][y] == FIRSTTAIL + player)
  2204.                 counter++;
  2205.     stci_d(tempstring, counter);
  2206.     align(tempstring, 4, ' ');
  2207.     Move(MainWindowPtr->RPort, 226 + (FONTX * 13), 124);
  2208.     Text(MainWindowPtr->RPort, tempstring, 4);
  2209.  
  2210.     levelbonus = (level - 1) * 100 * multiply;
  2211.     timebonus = secondsleft * 10 * multiply;
  2212.     tailbonus = counter * multiply;
  2213.  
  2214.     for (i = 0; i <= 3; i++)
  2215.         if (worm[i].control != NONE)
  2216.             for (j = 0; j <= LASTOBJECT; j++)
  2217.                 stat(i, j);
  2218.  
  2219.     while (!done)
  2220.     {    SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2221.         stci_d(tempstring, levelbonus);
  2222.         align(tempstring, 5, ' ');
  2223.         Move(MainWindowPtr->RPort, 218 + (FONTX * 27), 108);
  2224.         Text(MainWindowPtr->RPort, tempstring, 5);
  2225.  
  2226.         stci_d(tempstring, timebonus);
  2227.         align(tempstring, 5, ' ');
  2228.         Move(MainWindowPtr->RPort, 226 + (FONTX * 26), 116);
  2229.         Text(MainWindowPtr->RPort, tempstring, 5);
  2230.  
  2231.         stci_d(tempstring, tailbonus);
  2232.         align(tempstring, 5, ' ');
  2233.         Move(MainWindowPtr->RPort, 226 + (FONTX * 26), 124);
  2234.         Text(MainWindowPtr->RPort, tempstring, 5);
  2235.  
  2236.         done = TRUE;
  2237.         if (levelbonus)
  2238.         {   levelbonus -= multiply;
  2239.             wormscore(player, 1);
  2240.             done = FALSE;
  2241.         }
  2242.         if (timebonus)
  2243.         {   timebonus -= multiply;
  2244.             wormscore(player, 1);
  2245.             done = FALSE;
  2246.         }
  2247.         if (tailbonus)
  2248.         {   tailbonus -= multiply;
  2249.             wormscore(player, 1);
  2250.             done = FALSE;
  2251.         }
  2252.         effect(FXRUNDOWN);
  2253.     }
  2254.     clearkybd();
  2255.     effect(FXENDOFLEVEL);
  2256.     anykey(FALSE);
  2257. }
  2258.  
  2259. void say(STRPTR sentence, COLOUR colour)
  2260. {    SBYTE length = (SBYTE) strlen(sentence);
  2261.  
  2262.     // clear text area
  2263.  
  2264.     SetAPen(MainWindowPtr->RPort, BLACK);
  2265.     RectFill(MainWindowPtr->RPort, STARTXPIXEL, 1, ENDXPIXEL, FONTY + 2);
  2266.  
  2267.     // truncate text
  2268.  
  2269.     if (length > SAYLIMIT)
  2270.     {    *(sentence + SAYLIMIT - 1) = *(sentence + SAYLIMIT - 2) = *(sentence + SAYLIMIT - 3) = '.';
  2271.         length = SAYLIMIT;
  2272.     }
  2273.  
  2274.     // render shadow text
  2275.     
  2276.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2277.     SetAPen(MainWindowPtr->RPort, MEDIUMGREY);
  2278.     Move(MainWindowPtr->RPort, (SCREENXPIXEL / 2) - (length * FONTX / 2) + 1, FONTY + 1);
  2279.     Text(MainWindowPtr->RPort, sentence, length);
  2280.     
  2281.     // render actual text
  2282.     
  2283.     SetAPen(MainWindowPtr->RPort, colour);
  2284.     Move(MainWindowPtr->RPort, (SCREENXPIXEL / 2) - (length * FONTX / 2), FONTY);
  2285.     Text(MainWindowPtr->RPort, sentence, length);
  2286.     SetDrMd(MainWindowPtr->RPort, JAM2);
  2287. }
  2288.     
  2289. void sendreadrequest(void)
  2290. {    JoyRqPtr->io_Command    = GPD_READEVENT;
  2291.     JoyRqPtr->io_Flags        = NULL;
  2292.     JoyRqPtr->io_Length        = sizeof(struct InputEvent);
  2293.     JoyRqPtr->io_Data        = (APTR) &GameEvent;
  2294.     SendIO(JoyRqPtr);
  2295. }
  2296.  
  2297. void setpointer(SBYTE pointer) {
  2298. switch (pointer) {
  2299. case GOLD:
  2300.     SetRGB4(&ScreenPtr->ViewPort, 17, 10,  8,  3);        // fill
  2301.     SetRGB4(&ScreenPtr->ViewPort, 18,  8,  4,  2);        // shadow
  2302.     SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12,  2);        // shine
  2303.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2304.     break;
  2305. case SILVER:
  2306.     SetRGB4(&ScreenPtr->ViewPort, 17, 10, 10, 10);        // fill
  2307.     SetRGB4(&ScreenPtr->ViewPort, 18,  6,  6,  6);        // shadow
  2308.     SetRGB4(&ScreenPtr->ViewPort, 19, 15, 15, 15);        // shine
  2309.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2310.     break;
  2311. case EMPTY:
  2312.     SetRGB4(&ScreenPtr->ViewPort, 17,  2,  2,  2);        // fill
  2313.     SetRGB4(&ScreenPtr->ViewPort, 18,  0,  0,  0);        // shadow
  2314.     SetRGB4(&ScreenPtr->ViewPort, 19,  6,  6,  6);        // shine
  2315.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2316.     break;
  2317. case WOOD:
  2318.     SetRGB4(&ScreenPtr->ViewPort, 17,  8,  4,  2);        // fill
  2319.     SetRGB4(&ScreenPtr->ViewPort, 18,  2,  2,  2);        // shadow
  2320.     SetRGB4(&ScreenPtr->ViewPort, 19, 10,  8,  3);        // shine
  2321.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2322.     break;
  2323. case STONE:
  2324.     SetRGB4(&ScreenPtr->ViewPort, 17,  0,  0,  0);        // fill
  2325.     SetRGB4(&ScreenPtr->ViewPort, 18,  2,  2,  2);        // shadow
  2326.     SetRGB4(&ScreenPtr->ViewPort, 19,  6,  6,  6);        // shine
  2327.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2328.     break;
  2329. case METAL:
  2330.     SetRGB4(&ScreenPtr->ViewPort, 17,  6,  6, 15);        // fill
  2331.     SetRGB4(&ScreenPtr->ViewPort, 18,  3,  3, 15);        // shadow
  2332.     SetRGB4(&ScreenPtr->ViewPort, 19, 10, 10, 10);        // shine
  2333.     SetPointer(MainWindowPtr, &CustomPointer, 6, 5, -3, -2);
  2334.     break;
  2335. default:
  2336.     SetRGB4(&ScreenPtr->ViewPort, 17, 14,  4,  4);        // fill
  2337.     SetRGB4(&ScreenPtr->ViewPort, 18,  3,  3,  3);        // shadow
  2338.     SetRGB4(&ScreenPtr->ViewPort, 19, 12, 12, 12);        // shine
  2339.     ClearPointer(MainWindowPtr);
  2340.     break; }
  2341. }
  2342.  
  2343. void stat(SBYTE player, SBYTE line)
  2344. {    ABOOL    print = TRUE;
  2345.     SBYTE    i, len, theline;
  2346.     TEXT    output[9];
  2347.  
  2348.     strcpy(output, "        "); // 8 spaces
  2349.     switch (line)
  2350.     {
  2351.     case BONUS:
  2352.         do
  2353.         {    worm[player].oldscore += (LIFEMODULO - (worm[player].oldscore % LIFEMODULO));
  2354.             if (worm[player].score >= worm[player].oldscore)
  2355.             {    worm[player].lives++;
  2356.                 stat(player, LIFE);
  2357.             }
  2358.         } while (worm[player].score > worm[player].oldscore);
  2359.         worm[player].oldscore = worm[player].score;
  2360.         if (worm[player].multi > 1)
  2361.             SetAPen(MainWindowPtr->RPort, WHITE);
  2362.         else
  2363.             SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2364.         stcl_d(output, worm[player].score);
  2365.         for (i = 0; i <= 8; i++)
  2366.             if (!output[i])
  2367.                 output[i] = ' ';
  2368.         theline = 0;
  2369.         if (worm[player].score <= 999999L)
  2370.             len = 6;
  2371.         else
  2372.         {    // assert(worm[player].score <= 99999999L);
  2373.             len = 8;
  2374.         }
  2375.         break;
  2376.     case LIFE:
  2377.         if (worm[player].lives > STARTLIVES)
  2378.         {    SetAPen(MainWindowPtr->RPort, WHITE);
  2379.             if (worm[player].lives > LIVESLIMIT)
  2380.                 worm[player].lives = LIVESLIMIT;
  2381.         } else SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2382.         stci_d(output, worm[player].lives);
  2383.         for (i = 0; i <= 2; i++)
  2384.             if (!output[i])
  2385.             {    output[i] = ' ';
  2386.                 break;
  2387.             }
  2388.         theline = 1;
  2389.         len = 3;
  2390.         break;
  2391.     case BIAS:
  2392.         if (worm[player].bias > 0)
  2393.         {    if (worm[player].bias > BIASLIMIT)
  2394.                 worm[player].bias = BIASLIMIT;
  2395.             SetAPen(MainWindowPtr->RPort, WHITE);
  2396.         } else
  2397.             SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2398.         stci_d(output, worm[player].bias);
  2399.         for (i = 0; i <= 2; i++)
  2400.             if (!output[i])
  2401.             {    output[i] = ' ';
  2402.                 break;
  2403.             }
  2404.         theline = 2;
  2405.         len = 3;
  2406.         break;
  2407.     case NITRO:
  2408.         SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2409.         if (worm[player].speed == FAST)
  2410.             strcpy(output, STATFAST);
  2411.         else if (worm[player].speed == NORMAL)
  2412.             strcpy(output, STATNORMAL);
  2413.         else // assumes worm[player].speed == SLOW
  2414.             strcpy(output, STATSLOW);
  2415.         theline = 3;
  2416.         len = 6;
  2417.         break;
  2418.     case AMMO:
  2419.         if (worm[player].ammo)
  2420.         {    if (worm[player].ammo > AMMOLIMIT)
  2421.                 worm[player].ammo = AMMOLIMIT;
  2422.             SetAPen(MainWindowPtr->RPort, WHITE);
  2423.         } else
  2424.             SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2425.         stci_d(output, worm[player].ammo);
  2426.         for (i = 0; i <= 2; i++)
  2427.             if (!output[i])
  2428.             {    output[i] = ' ';
  2429.                 break;
  2430.             }
  2431.         if (iso)
  2432.             theline = 4;
  2433.         else theline = 5;
  2434.         len = 3;
  2435.         break;
  2436.     case POWER:
  2437.         switch(worm[player].power)
  2438.         {    case 0:
  2439.                 SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2440.                 strcpy(output, STATSINGLE);
  2441.                 break;
  2442.             case 2:
  2443.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2444.                 strcpy(output, STATTRIPLE);
  2445.                 break;
  2446.             case 4:
  2447.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2448.                 strcpy(output, STATQUINTUPLE);
  2449.                 break;
  2450.             case 6:
  2451.                 SetAPen(MainWindowPtr->RPort, WHITE);
  2452.                 strcpy(output, STATSEPTUPLE);
  2453.                 break;
  2454.             default:
  2455.                 break;
  2456.         }
  2457.         if (iso)
  2458.             theline = 5;
  2459.         else theline = 6;
  2460.         len = 6;
  2461.         break;
  2462.     case ARMOUR:
  2463.         if (worm[player].armour > MODELIMIT)
  2464.             worm[player].armour = MODELIMIT;
  2465.         if (worm[player].mode == ARMOUR)
  2466.             SetAPen(MainWindowPtr->RPort, WHITE);
  2467.         else
  2468.             SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2469.         stci_d(output, worm[player].armour);
  2470.         for (i = 0; i <= 2; i++)
  2471.             if (!output[i])
  2472.             {    output[i] = ' ';
  2473.                 break;
  2474.             }
  2475.         if (iso)
  2476.             theline = 6;
  2477.         else theline = 8;
  2478.         len = 3;
  2479.         break;
  2480.     case TONGUE:
  2481.         if (worm[player].tongue > MODELIMIT)
  2482.             worm[player].tongue = MODELIMIT;
  2483.         if (worm[player].mode == TONGUE)
  2484.             SetAPen(MainWindowPtr->RPort, WHITE);
  2485.         else
  2486.             SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2487.         stci_d(output, worm[player].tongue);
  2488.         for (i = 0; i <= 2; i++)
  2489.             if (!output[i])
  2490.             {    output[i] = ' ';
  2491.                 break;
  2492.             }
  2493.         if (iso)
  2494.             theline = 7;
  2495.         else theline = 9;
  2496.         len = 3;
  2497.         break;
  2498.     default:
  2499.         print = FALSE;
  2500.         break;
  2501.     }
  2502.  
  2503.     if (print)
  2504.     {    if (iso)
  2505.             switch(player)
  2506.             {
  2507.             case 0:
  2508.                 Move(MainWindowPtr->RPort, 0  ,   8 + (theline * FONTY));
  2509.                 break;
  2510.             case 1:
  2511.                 Move(MainWindowPtr->RPort, 528, 189 + (theline * FONTY));
  2512.                 break;
  2513.             case 2:
  2514.                 Move(MainWindowPtr->RPort, 66 ,   8 + (theline * FONTY));
  2515.                 break;
  2516.             case 3:
  2517.                 Move(MainWindowPtr->RPort, 592, 189 + (theline * FONTY));
  2518.                 break;
  2519.             default:
  2520.                 // assert(0);
  2521.                 break;
  2522.             }
  2523.         else
  2524.         {    Move
  2525.             (    MainWindowPtr->RPort,
  2526.                 (FONTX * 3) + (worm[player].statx * ENDXPIXEL),
  2527.                 STARTYPIXEL + 6 + (theline * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  2528.             );
  2529.         }
  2530.         Text(MainWindowPtr->RPort, output, len);
  2531. }    }
  2532.  
  2533. void stopfx(ULONG receipt)
  2534. {    SBYTE i;
  2535.  
  2536.     if (mode == FX)
  2537.         for (i = 0; i <= 3; i++)
  2538.             if (eversent[i] && (!(CheckIO(AudioRqPtr[i]))) && (receipt == 0L || receipt == receipter[i]))
  2539.             {   AbortIO(AudioRqPtr[i]);
  2540.                 WaitIO(AudioRqPtr[i]);
  2541. }           }
  2542.  
  2543. void titlescreen(void)
  2544. {    SBYTE                    lisa = 0, object = LASTOBJECT, player;
  2545.     SWORD                    descx = FIRSTDESCX;
  2546.     ULONG                    class;
  2547.     UWORD                    code, qual;
  2548.     struct IntuiMessage*    MsgPtr;
  2549.     struct Gadget*            WhichGadgetPtr;
  2550.     struct MenuItem*        ItemPtr;
  2551.  
  2552.     effect(FXTITLESCREEN);
  2553.     Forbid();
  2554.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  2555.     Permit();
  2556.     clearscreen();
  2557.  
  2558.     SetMenuStrip(MainWindowPtr, MenuPtr);
  2559.     for (player = 0; player <= 3; player++)
  2560.         GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2561.     GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2562.  
  2563.     clearkybd();
  2564.     clearjoystick();
  2565.     hiscores();
  2566.     hiscorenames();
  2567.  
  2568.     effect(FXSTAMPED);
  2569.     DrawImage(MainWindowPtr->RPort, &Logo, 203, 22);
  2570.  
  2571.     do
  2572.     {    TimerRqPtr->tr_node.io_Command    = TR_ADDREQUEST;
  2573.         TimerRqPtr->tr_time.tv_secs        = 0;
  2574.         TimerRqPtr->tr_time.tv_micro    = ANIMDELAY;
  2575.         SendIO(TimerRqPtr);
  2576.  
  2577.         if (descx == FIRSTDESCX)
  2578.         {    if (++object > LASTOBJECT)
  2579.                 object = 0;
  2580.             say(objectdesc[object], WHITE);
  2581.             Image.ImageData = ImageData[object];
  2582.             DrawImage(MainWindowPtr->RPort, &Image, SECONDDESCX, DESCY);
  2583.         }
  2584.         SetAPen(MainWindowPtr->RPort, BLACK);
  2585.         Move(MainWindowPtr->RPort, descx - 1, DESCY - 1);
  2586.         Draw(MainWindowPtr->RPort, descx - 1, DESCY + 1 + SQUAREY);
  2587.         Move(MainWindowPtr->RPort, descx + 1 + SQUAREX, DESCY - 1);
  2588.         Draw(MainWindowPtr->RPort, descx + 1 + SQUAREX, DESCY + 1 + SQUAREY);
  2589.         Image.ImageData = ImageData[object];
  2590.         DrawImage(MainWindowPtr->RPort, &Image, descx, DESCY);
  2591.         if (++descx > SECONDDESCX)
  2592.             descx = FIRSTDESCX;
  2593.  
  2594.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2595.         {    WhichGadgetPtr = (struct Gadget *) MsgPtr->IAddress;
  2596.             class = MsgPtr->Class;
  2597.             code  = MsgPtr->Code;
  2598.             qual  = MsgPtr->Qualifier;
  2599.             GT_ReplyIMsg(MsgPtr);
  2600.             switch (class) {
  2601.             case IDCMP_RAWKEY:
  2602.                 if (!(qual & IEQUALIFIER_REPEAT))
  2603.                     switch (code) {
  2604.                     case F:
  2605.                         toggle(F);
  2606.                         break;
  2607.                     case M:
  2608.                         toggle(M);
  2609.                         break;
  2610.                     case SPACEBAR:
  2611.                         effect(FXCLICK);
  2612.                         a = FIELDEDIT;
  2613.                         break;
  2614.                     case F1:
  2615.                     case ALPHAONE:
  2616.                     case NUMERICONE:
  2617.                         effect(FXCLICK);
  2618.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2619.                         {    if (--worm[0].control < 0)
  2620.                                 worm[0].control = 2;
  2621.                         } else
  2622.                         {    if (++worm[0].control > 2)
  2623.                                 worm[0].control = 0;
  2624.                         }
  2625.                         GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, worm[0].control, TAG_DONE);
  2626.                         break;
  2627.                     case F2:
  2628.                     case ALPHATWO:
  2629.                     case NUMERICTWO:
  2630.                         effect(FXCLICK);
  2631.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2632.                         {    if (--worm[1].control < 0)
  2633.                                 worm[1].control = 2;
  2634.                         } else
  2635.                         {    if (++worm[1].control > 2)
  2636.                                 worm[1].control = 0;
  2637.                         }
  2638.                         GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, worm[1].control, TAG_DONE);
  2639.                     break;
  2640.                     case F3:
  2641.                     case ALPHATHREE:
  2642.                     case NUMERICTHREE:
  2643.                         effect(FXCLICK);
  2644.                         if (joy)
  2645.                         {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2646.                             {    if (--worm[2].control < 0)
  2647.                                     worm[2].control = 2;
  2648.                             } else
  2649.                             {    if (++worm[2].control > 2)
  2650.                                     worm[2].control = 0;
  2651.                         }    }
  2652.                         else if (worm[2].control == NONE)
  2653.                             worm[2].control = AMIGA;
  2654.                         else
  2655.                             worm[2].control = NONE;
  2656.                         GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, worm[2].control, TAG_DONE);
  2657.                     break;
  2658.                     case F4:
  2659.                     case ALPHAFOUR:
  2660.                     case NUMERICFOUR:
  2661.                         effect(FXCLICK);
  2662.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2663.                         {    if (--worm[3].control < 0)
  2664.                                 worm[3].control = 2;
  2665.                         } else
  2666.                         {    if (++worm[3].control > 2)
  2667.                                 worm[3].control = 0;
  2668.                         }
  2669.                         GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, worm[3].control, TAG_DONE);
  2670.                     break;
  2671.                     case RETURN:
  2672.                     case ENTER:
  2673.                         a = PLAYGAME;
  2674.                         break;
  2675.                     case I:
  2676.                         effect(FXCLICK);
  2677.                         iso = !iso;
  2678.                         GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GTCB_Checked, iso, TAG_DONE);
  2679.                         break;
  2680.                     case ESCAPE:
  2681.                         if (verify())
  2682.                             cleanexit(EXIT_SUCCESS);
  2683.                         break;
  2684.                     case HELP:
  2685.                         fileabout();
  2686.                         break;
  2687.                     case INTERNATIONALONE:
  2688.                         if (lisa == 2)
  2689.                         {    say(FIRSTLISA, RED);
  2690.                             anykey(FALSE);
  2691.                             lisa = 0;
  2692.                         } else
  2693.                             lisa = 1;
  2694.                         break;
  2695.                     case INTERNATIONALTWO:
  2696.                         if (lisa == 1)
  2697.                         {    say(SECONDLISA, BLUE);
  2698.                             anykey(FALSE);
  2699.                             lisa = 0;
  2700.                         } else
  2701.                             lisa = 2;
  2702.                         break;
  2703.                     default:
  2704.                         break;
  2705.                     }
  2706.                 break;
  2707.             case IDCMP_MENUPICK:
  2708.                 while (code != MENUNULL)
  2709.                 {    ItemPtr = ItemAddress(MenuPtr, code);
  2710.                     switch (MENUNUM(code))
  2711.                     {
  2712.                     case MN_PROJECT:
  2713.                         switch (ITEMNUM(code))
  2714.                         {
  2715.                         case IN_NEW:
  2716.                             effect(FXFILENEW);
  2717.                             newfields();
  2718.                             say("New done.", WHITE);
  2719.                             anykey(TRUE);
  2720.                             say(objectdesc[object], WHITE);
  2721.                             break;
  2722.                         case IN_OPEN:
  2723.                             effect(FXFILEOPEN);
  2724.                             fileopen();
  2725.                             say(objectdesc[object], WHITE);
  2726.                             break;
  2727.                         case IN_SAVE:
  2728.                             effect(FXFILESAVE);
  2729.                             filesaveas(FALSE);
  2730.                             say(objectdesc[object], WHITE);
  2731.                             break;
  2732.                         case IN_SAVEAS:
  2733.                             effect(FXFILESAVEAS);
  2734.                             filesaveas(TRUE);
  2735.                             say(objectdesc[object], WHITE);
  2736.                             break;
  2737.                         case IN_ABOUT:
  2738.                             fileabout();
  2739.                             break;
  2740.                         case IN_QUIT:
  2741.                             if (verify())
  2742.                                 cleanexit(EXIT_SUCCESS);
  2743.                             break;
  2744.                         default:
  2745.                             break;
  2746.                         }
  2747.                         break;
  2748.                     default:
  2749.                         break;
  2750.                     }
  2751.                     code = ItemPtr->NextSelect;
  2752.                 }
  2753.                 break;
  2754.             case IDCMP_MOUSEBUTTONS:
  2755.                 if (code == SELECTDOWN)
  2756.                     if (ignore)
  2757.                         ignore = FALSE;
  2758.                     else a = PLAYGAME;
  2759.                 break;
  2760.             case IDCMP_REFRESHWINDOW:
  2761.                 GT_BeginRefresh(MainWindowPtr);
  2762.                 GT_EndRefresh(MainWindowPtr, TRUE);
  2763.                 break;
  2764.             case IDCMP_GADGETUP:
  2765.                 if (WhichGadgetPtr == CheckboxGadgetPtr)
  2766.                     iso = !iso;
  2767.                 else
  2768.                 {    for (player = 0; player <= 3; player++)
  2769.                         if (WhichGadgetPtr == CycleGadgetPtr[player])
  2770.                         {    if (code == HUMAN && player == 2 && (!joy))
  2771.                             {    if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2772.                                     worm[2].control = NONE;
  2773.                                 else
  2774.                                     worm[2].control = AMIGA;
  2775.                                 GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, worm[2].control, TAG_DONE);
  2776.                             } else
  2777.                                 worm[player].control = code;
  2778.                             break;
  2779.                         }
  2780.                 }
  2781.                 break;
  2782.             case IDCMP_ACTIVEWINDOW:
  2783.                 ignore = TRUE;
  2784.                 break;
  2785.             case IDCMP_CLOSEWINDOW:
  2786.                 cleanexit(EXIT_SUCCESS);
  2787.                 break;
  2788.             default:
  2789.                 // IDCMP_MENUVERIFY, IDCMP_INTUITICKS
  2790.                 break;
  2791.         }    }
  2792.         if (joy && GetMsg(JoyPortPtr))
  2793.         {    if (GameEvent.ie_Code == IECODE_LBUTTON)
  2794.                 a = PLAYGAME;
  2795.             sendreadrequest();
  2796.         }
  2797.         if (a == PLAYGAME)
  2798.         {    if (worm[0].control == NONE && worm[1].control == NONE && worm[2].control == NONE && worm[3].control == NONE)
  2799.             {    say("No worms active!", WHITE);
  2800.                 anykey(TRUE);
  2801.                 a = GAMEOVER;
  2802.         }    }
  2803.         if (CheckIO(TimerRqPtr))
  2804.             draw(CLOCKICON, ICONY, CLOCK);
  2805.         else draw(CLOCKICON, ICONY, BLACKENED);
  2806.         WaitIO(TimerRqPtr);
  2807.     } while (a == GAMEOVER);
  2808.  
  2809.     for (player = 0; player <= 3; player++)
  2810.         GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2811.     GT_SetGadgetAttrs(CheckboxGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2812.     Image.ImageData = ImageData[BLACKENED];
  2813.     DrawImage(MainWindowPtr->RPort, &Image, FIRSTDESCX, DESCY);
  2814.     DrawImage(MainWindowPtr->RPort, &Image, SECONDDESCX, DESCY);
  2815.     if (a == FIELDEDIT)
  2816.         fieldedit();
  2817.     else
  2818.     {    newgame();
  2819.         clearkybd();
  2820.         Forbid();
  2821.         MainWindowPtr->Flags |= WFLG_RMBTRAP;
  2822.         Permit();
  2823. }    }
  2824.  
  2825. void toggle(SBYTE key)
  2826. {    PERSIST ABOOL songstarted = FALSE;
  2827.  
  2828.     switch(key)
  2829.     {
  2830.     case F:
  2831.         if (mode == FX)                    // F in FX mode: no sound
  2832.         {    freefx();
  2833.             mode = FALSE;
  2834.             draw(MUSICICON, ICONY, BLACKENED);
  2835.         } else if (fxable > 0)            // F otherwise: change to FX mode
  2836.         {    if (mode == MUSIC)            // stop any music that is playing
  2837.             {    StopPlayer();
  2838.                 FreePlayer();
  2839.             }
  2840.             if (fxable == 3)            // load samples if needed
  2841.                 loadthefx();
  2842.             if (fxable == 1)            // if we have samples in memory
  2843.             {    if (beginfx())
  2844.                 {    mode = FX;
  2845.                     effect(FXFX);
  2846.                     draw(MUSICICON, ICONY, FX);
  2847.         }    }    }
  2848.         break;
  2849.     case M:
  2850.         if (mode == MUSIC)                // M in MUSIC mode: no sound
  2851.         {    StopPlayer();
  2852.             FreePlayer();
  2853.             mode = FALSE;
  2854.             draw(MUSICICON, ICONY, BLACKENED);
  2855.         } else if (musicable > 0)        // M otherwise: change to music mode
  2856.         {    if (mode == FX)                // stop any samples that are playing
  2857.                 freefx();
  2858.             /* Of course, these statements are ordered in this
  2859.             way for a reason, so don't change it. */
  2860.             if (musicable == 3)
  2861.                 loadthemusic();
  2862.             if (musicable == 1)
  2863.             {    if (GetPlayer(0))
  2864.                 {    say("No channels for music!", RED);
  2865.                     anykey(TRUE);
  2866.                     mode = FALSE;
  2867.                     draw(MUSICICON, ICONY, BLACKENED);
  2868.                 } else
  2869.                 {    if (songstarted)
  2870.                         ContModule(SongPtr);
  2871.                     else
  2872.                     {    PlayModule(SongPtr);
  2873.                         songstarted = TRUE;
  2874.                     }
  2875.                     mode = MUSIC;
  2876.                     draw(MUSICICON, ICONY, MUSIC);
  2877.         }    }    }
  2878.         break;
  2879.     default:
  2880.         break;
  2881. }    }
  2882.     
  2883. void underline(SBYTE square)
  2884. {    /* Removes old underline, draws new underline.
  2885.     
  2886.     square: which square-type to underline, or -1 for clear only.
  2887.     Squares which do not correspond to any pseudo-gadgets
  2888.     (eg. objects) are converted to -1s. */
  2889.  
  2890.     PERSIST    SWORD oldy = -1;
  2891.             SWORD y;
  2892.  
  2893.     switch(square)
  2894.     {
  2895.     case GOLD:
  2896.         y = UNDERLINEOFFSET;
  2897.         break;
  2898.     case SILVER:
  2899.         y = UNDERLINEOFFSET + (SQUAREY *  3);
  2900.         break;
  2901.     case EMPTY:
  2902.         y = UNDERLINEOFFSET + (SQUAREY *  6);
  2903.         break;
  2904.     case WOOD:
  2905.         y = UNDERLINEOFFSET + (SQUAREY *  9);
  2906.         break;
  2907.     case STONE:
  2908.         y = UNDERLINEOFFSET + (SQUAREY * 12);
  2909.         break;
  2910.     case METAL:
  2911.         y = UNDERLINEOFFSET + (SQUAREY * 15);
  2912.         break;
  2913.     case ONE:
  2914.         y = UNDERLINEOFFSET + (SQUAREY * 18);
  2915.         break;
  2916.     case TWO:
  2917.         y = UNDERLINEOFFSET + (SQUAREY * 21);
  2918.         break;
  2919.     case START:
  2920.         y = UNDERLINEOFFSET + (SQUAREY * 24);
  2921.         break;
  2922.     default:
  2923.         square = -1;
  2924.         break;
  2925.     }
  2926.  
  2927.     if (oldy != -1)
  2928.     {    SetAPen(MainWindowPtr->RPort, BLACK);
  2929.         Move(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, oldy);
  2930.         Draw(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, oldy + SQUAREY + 3);
  2931.     }
  2932.     if (square != -1)
  2933.     {    SetAPen(MainWindowPtr->RPort, WHITE);
  2934.         Move(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, y);
  2935.         Draw(MainWindowPtr->RPort, STARTXPIXEL - SQUAREX + 1, y + SQUAREY + 3);
  2936.         oldy = y;
  2937. }    }
  2938.  
  2939. ABOOL verify(void)
  2940. {    pausetimer();
  2941.     if (modified && (EasyRequest(MainWindowPtr, &EasyStruct, NULL) == 0))
  2942.         return FALSE;
  2943.     else return TRUE;
  2944.     unpausetimer();
  2945. }
  2946.  
  2947. void waitasec(void)
  2948. {   Delay(50);
  2949. }
  2950.  
  2951. void systemsetup(void)
  2952. {    worm[0].control    = NONE;
  2953.     worm[1].control    = HUMAN;
  2954.     worm[2].control    = NONE;
  2955.     worm[3].control = AMIGA;
  2956. }
  2957.  
  2958. ABOOL ZOpen(STRPTR fieldname, ABOOL write)
  2959. {    if (!write)
  2960.         if (FilePtr = Open(fieldname, MODE_OLDFILE))
  2961.             return TRUE;
  2962.         else return FALSE;
  2963.     else
  2964.         if (FilePtr = Open(fieldname, MODE_NEWFILE))
  2965.             return TRUE;
  2966.         else return FALSE;
  2967. }
  2968. ABOOL ZRead(STRPTR IOBuffer, ULONG length)
  2969. {    if (Read(FilePtr, IOBuffer, length) == length)
  2970.         return TRUE;
  2971.     else return FALSE;
  2972. }
  2973. ABOOL ZWrite(STRPTR IOBuffer, ULONG length)
  2974. {    if (Write(FilePtr, IOBuffer, length) == length)
  2975.         return TRUE;
  2976.     else return FALSE;
  2977. }
  2978. ABOOL ZClose(void)
  2979. {    if (Close(FilePtr))
  2980.     {    FilePtr = NULL;
  2981.         return TRUE;
  2982.     } else
  2983.     {    /* "If Close() returns DOSFALSE, the user has already cancelled an
  2984.         error requester and the function has already freed the FileHandle
  2985.         (and even marked it so any attempt to close it again will bring up
  2986.         the "Software Failure" requester). Therefore FilePtr should be set
  2987.         to zero in any case." - Jilles Tjoelker. */
  2988.  
  2989.         FilePtr = NULL;
  2990.         return FALSE;
  2991. }    }
  2992.  
  2993. void timing(void)
  2994. {    ;
  2995. }
  2996.  
  2997. void loadthefx(void)
  2998. {    UBYTE*          p8data;
  2999.  
  3000.     TEXT            saystring[SAYLIMIT + 1];
  3001.  
  3002.     SBYTE           code = 0, i;
  3003.     SBYTE           iobuffer[8];        // buffer for 8SVX.VHDR 
  3004.     SBYTE*          psample[2];         // sample pointers
  3005.     struct Chunk*   p8Chunk;            // pointers for 8SVX parsing
  3006.     Voice8Header*   pVoice8Header;
  3007.     ULONG           rd8count;
  3008.  
  3009.     say("Loading sound effects...", WHITE);
  3010.     fxable = 1;
  3011.  
  3012.     for (i = 0; i <= SAMPLES; i++)
  3013.         sbase[i] = NULL;
  3014.     for (i = 0; i <= SAMPLES; i++)
  3015.     {   if (!(FilePtr = Open(samp[i].filename, MODE_OLDFILE)))
  3016.             code = 1;                               // can't open file
  3017.         else
  3018.         {   rd8count = Read(FilePtr, iobuffer, 8L);
  3019.             if (rd8count == -1)
  3020.                 code = 2;                           // can't read file
  3021.             else if (rd8count < 8)
  3022.                 code = 3;                           // not an IFF 8SVX; too short
  3023.             else
  3024.             {   p8Chunk = (struct Chunk *) iobuffer;
  3025.                 if (p8Chunk->ckID != ID_FORM)
  3026.                     code = 4;                       // not an IFF FORM
  3027.                 else if (!(fbase = (UBYTE *) AllocMem(fsize = p8Chunk->ckSize, MEMF_PUBLIC | MEMF_CLEAR)))
  3028.                     code = 5;                       // no memory for read
  3029.                 else
  3030.                 {   p8data = fbase;
  3031.                     rd8count = Read(FilePtr, p8data, p8Chunk->ckSize);
  3032.                     if (rd8count == -1)
  3033.                         code = 6;                   // read error
  3034.                     else if (rd8count < p8Chunk->ckSize)
  3035.                         code = 7;                   // malformed IFF; too short
  3036.                     else if (MAKE_ID(*p8data, *(p8data + 1), *(p8data + 2), *(p8data + 3)) != ID_8SVX)
  3037.                         code = 8;                   // not an IFF 8SVX
  3038.                     else
  3039.                     {   p8data = p8data + 4;
  3040.                         while (p8data < fbase + fsize)
  3041.                         {   p8Chunk = (struct Chunk *) p8data;
  3042.                             switch(p8Chunk->ckID) {
  3043.                             case ID_VHDR:
  3044.                                 pVoice8Header = (Voice8Header *) (p8data + 8L);
  3045.                                 break;
  3046.                             case ID_BODY:
  3047.                                 psample[0]    = (SBYTE *) (p8data + 8L);
  3048.                                 psample[1]    = psample[0] + pVoice8Header->oneShotHiSamples;
  3049.                                 length[i][0]  = (ULONG) pVoice8Header->oneShotHiSamples;
  3050.                                 length[i][1]  = (ULONG) pVoice8Header->repeatHiSamples;
  3051.  
  3052.                                 /* To grab the volume level from the IFF
  3053.                                 8SVX file itself, add this here:
  3054.  
  3055.                                 samp[i].volume  = (SBYTE) (pVoice8Header->volume / 156); */
  3056.  
  3057.                                    break;
  3058.                                default:
  3059.                                    break;
  3060.                             }
  3061.                             p8data += 8L + p8Chunk->ckSize;
  3062.                             if (p8Chunk->ckSize & 1L == 1)
  3063.                                 p8data++;
  3064.                         }
  3065.                         if (length[i][0] == 0)
  3066.                             yes[i] = 1;
  3067.                         else yes[i] = 0;
  3068.                         if (length[i][yes[i]] <= 102400)
  3069.                             ssize[i] = length[i][yes[i]];
  3070.                         else ssize[i] = 102400;
  3071.                         sbase[i] = (UBYTE *) AllocMem(ssize[i], MEMF_CHIP | MEMF_CLEAR);
  3072.                         if (!sbase[i])
  3073.                             code = 9;               // no chip memory
  3074.                         else
  3075.                         {   CopyMem(psample[yes[i]], sbase[i], ssize[i]);
  3076.                             psample[yes[i]] += ssize[i];
  3077.                             speed[i] = PALCLOCK / pVoice8Header->samplesPerSec;
  3078.                             if (fbase)
  3079.                             {   FreeMem(fbase, fsize);
  3080.                                 fbase = NULL;
  3081.                             }
  3082.                             if (FilePtr)
  3083.                             {   Close(FilePtr);
  3084.                                 FilePtr = NULL;
  3085.         }   }   }   }   }   }
  3086.         if (code)
  3087.         {   freefx();
  3088.             fxable = 0;
  3089.             strcpy(saystring, samp[i].filename);
  3090.             strcat(saystring, ": ");
  3091.             strcat(saystring, sfxerror[code]);
  3092.             say(saystring, RED);
  3093.             anykey(TRUE);
  3094.             break;
  3095. }    }   }
  3096.  
  3097. void loadthemusic(void)
  3098. {    if (!(MEDPlayerBase = (struct MEDPlayerBase *) OpenLibrary("medplayer.library", 0L)))
  3099.     {    say("Can't open MEDPlayer.library!", RED);
  3100.         anykey(TRUE);
  3101.     } else
  3102.     {    say("Loading music...", WHITE);
  3103.         if (SongPtr = (struct MMD0 *) LoadModule(MEDMODULE))
  3104.             musicable = TRUE;
  3105.         else
  3106.         {    say("Can't load music!", RED);
  3107.             anykey(TRUE);
  3108. }    }    }
  3109.  
  3110. void dot(SBYTE x, SBYTE y)
  3111. {    SWORD xx, yy;
  3112.  
  3113.     /* Squares are dotted as follows:
  3114.     
  3115.      012345678
  3116.     0.........
  3117.     1.........
  3118.     2...WWW...
  3119.     3...WWWB..
  3120.     4....BBB..
  3121.     5......... */
  3122.  
  3123.     xx = (x * SQUAREX) + STARTXPIXEL;
  3124.     yy = (y * SQUAREY) + STARTYPIXEL;
  3125.  
  3126.     SetAPen(MainWindowPtr->RPort, WHITE);
  3127.     WritePixel(MainWindowPtr->RPort, xx + 3, yy + 2);
  3128.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 2);
  3129.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 2);
  3130.     WritePixel(MainWindowPtr->RPort, xx + 3, yy + 3);
  3131.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 3);
  3132.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 3);
  3133.     SetAPen(MainWindowPtr->RPort, BLACK);
  3134.     WritePixel(MainWindowPtr->RPort, xx + 6, yy + 3);
  3135.     WritePixel(MainWindowPtr->RPort, xx + 4, yy + 4);
  3136.     WritePixel(MainWindowPtr->RPort, xx + 5, yy + 4);
  3137.     WritePixel(MainWindowPtr->RPort, xx + 6, yy + 4);
  3138. }
  3139.  
  3140. void clearscreen(void)
  3141. {    SBYTE player;
  3142.  
  3143.     DrawImage
  3144.     (    MainWindowPtr->RPort,
  3145.         &Background,
  3146.         0,
  3147.         0
  3148.     );
  3149.     if (mode == MUSIC)
  3150.         draw(MUSICICON, ICONY, MUSIC);
  3151.     else if (mode == FX)
  3152.         draw(MUSICICON, ICONY, FX);
  3153.     else draw(MUSICICON, ICONY, BLACKENED);
  3154.     if (sticky)
  3155.         draw(STICKYICON, ICONY, STICKY);
  3156.     else draw(STICKYICON, ICONY, BLACKENED);
  3157.     draw(CLOCKICON, ICONY, CLOCK);
  3158.     
  3159. if (a != FIELDEDIT)
  3160.     if (!iso)
  3161.     {    for (player = 0; player <= 3; player++)
  3162.         {    if (worm[player].control != NONE)
  3163.             {    Image.ImageData = ImageData[BONUS];
  3164.                 DrawImage
  3165.                 (    MainWindowPtr->RPort,
  3166.                     &Image,
  3167.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3168.                     STARTYPIXEL + 1               + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3169.                 );
  3170.                 Image.ImageData = ImageData[LIFE];
  3171.                 DrawImage
  3172.                 (    MainWindowPtr->RPort,
  3173.                     &Image,
  3174.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3175.                     STARTYPIXEL + 1 + (1 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3176.                 );
  3177.                 Image.ImageData = ImageData[BIAS];
  3178.                 DrawImage
  3179.                 (    MainWindowPtr->RPort,
  3180.                     &Image,
  3181.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3182.                     STARTYPIXEL + 1 + (2 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3183.                 );
  3184.                 Image.ImageData = ImageData[NITRO];
  3185.                 DrawImage
  3186.                 (    MainWindowPtr->RPort,
  3187.                     &Image,
  3188.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3189.                     STARTYPIXEL + 1 + (3 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3190.                 );
  3191.                 Image.ImageData = ImageData[AMMO];
  3192.                 DrawImage
  3193.                 (    MainWindowPtr->RPort,
  3194.                     &Image,
  3195.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3196.                     STARTYPIXEL + 1 + (5 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3197.                 );
  3198.                 Image.ImageData = ImageData[POWER];
  3199.                 DrawImage
  3200.                 (    MainWindowPtr->RPort,
  3201.                     &Image,
  3202.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3203.                     STARTYPIXEL + 1 + (6 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3204.                 );
  3205.                 Image.ImageData = ImageData[ARMOUR];
  3206.                 DrawImage
  3207.                 (    MainWindowPtr->RPort,
  3208.                     &Image,
  3209.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3210.                     STARTYPIXEL + 1 + (8 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3211.                 );
  3212.                 Image.ImageData = ImageData[TONGUE];
  3213.                 DrawImage
  3214.                 (    MainWindowPtr->RPort,
  3215.                     &Image,
  3216.                     (worm[player].statx * ENDXPIXEL) + FONTX,
  3217.                     STARTYPIXEL + 1 + (9 * FONTY) + (worm[player].staty * (ENDYPIXEL - 1 - (11 * FONTY)))
  3218.                 );
  3219.     }    }    }
  3220.     else // assert (iso);
  3221.     {    if (worm[0].control != NONE || worm[2].control != NONE)
  3222.         {    Image.ImageData = ImageData[BONUS];
  3223.             DrawImage(MainWindowPtr->RPort, &Image, 54, 4);
  3224.             Image.ImageData = ImageData[LIFE];
  3225.             DrawImage(MainWindowPtr->RPort, &Image, 54, 12);
  3226.             Image.ImageData = ImageData[BIAS];
  3227.             DrawImage(MainWindowPtr->RPort, &Image, 54, 20);
  3228.             Image.ImageData = ImageData[NITRO];
  3229.             DrawImage(MainWindowPtr->RPort, &Image, 54, 28);
  3230.             Image.ImageData = ImageData[AMMO];
  3231.             DrawImage(MainWindowPtr->RPort, &Image, 54, 36);
  3232.             Image.ImageData = ImageData[POWER];
  3233.             DrawImage(MainWindowPtr->RPort, &Image, 54, 44);
  3234.             Image.ImageData = ImageData[ARMOUR];
  3235.             DrawImage(MainWindowPtr->RPort, &Image, 54, 52);
  3236.             Image.ImageData = ImageData[TONGUE];
  3237.             DrawImage(MainWindowPtr->RPort, &Image, 54, 60);
  3238.         }
  3239.         if (worm[1].control != NONE || worm[3].control != NONE)
  3240.         {    Image.ImageData = ImageData[BONUS];
  3241.             DrawImage(MainWindowPtr->RPort, &Image, 579, 183);
  3242.             Image.ImageData = ImageData[LIFE];
  3243.             DrawImage(MainWindowPtr->RPort, &Image, 579, 191);
  3244.             Image.ImageData = ImageData[BIAS];
  3245.             DrawImage(MainWindowPtr->RPort, &Image, 579, 199);
  3246.             Image.ImageData = ImageData[NITRO];
  3247.             DrawImage(MainWindowPtr->RPort, &Image, 579, 207);
  3248.             Image.ImageData = ImageData[AMMO];
  3249.             DrawImage(MainWindowPtr->RPort, &Image, 579, 215);
  3250.             Image.ImageData = ImageData[POWER];
  3251.             DrawImage(MainWindowPtr->RPort, &Image, 579, 223);
  3252.             Image.ImageData = ImageData[ARMOUR];
  3253.             DrawImage(MainWindowPtr->RPort, &Image, 579, 231);
  3254.             Image.ImageData = ImageData[TONGUE];
  3255.             DrawImage(MainWindowPtr->RPort, &Image, 579, 239);
  3256. }    }    }
  3257.  
  3258. void datestamp(void)
  3259. {    ULONG                seconds, micros;
  3260.     struct ClockData    Date;
  3261.     TEXT                temp[5];
  3262.  
  3263.     CurrentTime(&seconds, µs);
  3264.     Amiga2Date(seconds, &Date);
  3265.     stci_d(times, Date.hour);            // hh
  3266.     align(times, 2, ' ');
  3267.     times[2] = ':';                     // hh:
  3268.     times[3] = 0;
  3269.     stci_d(temp, Date.min);
  3270.     align(temp, 2, '0');
  3271.     temp[2] = 0;
  3272.     strcat(times, temp);                // hh:mm
  3273.  
  3274.     stci_d(date, Date.mday);            // dd
  3275.     align(date, 2, ' ');
  3276.     date[2] = '/';
  3277.     date[3] = 0;                        // dd/
  3278.     stci_d(temp, Date.month);
  3279.     align(temp, 2, ' ');
  3280.     temp[2] = 0;
  3281.     strcat(date, temp);                    // dd/mm
  3282.     strcat(date, "/");                    // dd/mm/
  3283.     stci_d(temp, Date.year);
  3284.     temp[0] = temp[2];
  3285.     temp[1] = temp[3];
  3286.     temp[2] = 0;
  3287.     strcat(date, temp);                    // dd/mm/yy
  3288. }
  3289.  
  3290. void turborender(void)
  3291. {    SBYTE            x, y;
  3292.  
  3293.     for (x = 0; x <= FIELDX; x++)
  3294.         for (y = 0; y <= FIELDY; y++)
  3295.             draw(x, y, board[level][x][y]);
  3296.  
  3297.     if (a == FIELDEDIT)
  3298.     {    draw(startx[level], starty[level], START);
  3299.         if (teleport[level][0].alive)
  3300.         {    draw(teleport[level][0].x, teleport[level][0].y, ONE);
  3301.             draw(teleport[level][1].x, teleport[level][1].y, TWO);
  3302. }    }    }
  3303.  
  3304. SWORD xpixeltosquare(SWORD x)
  3305. {    x = (x - STARTXPIXEL) / SQUAREX;
  3306.     if (x < 0)
  3307.         x--;
  3308.     return (x);
  3309. }
  3310. SWORD ypixeltosquare(SWORD y)
  3311. {    y = (y - STARTYPIXEL) / SQUAREY;
  3312.     if (y < 0)
  3313.         y--;
  3314.     return (y);
  3315. }
  3316.  
  3317. void parsewb(void)
  3318. {    struct DiskObject*    DiskObject;
  3319.     char**                ToolArray;
  3320.     char*                s;
  3321.  
  3322.     if ((*WBArg->wa_Name) && (DiskObject = GetDiskObject(WBArg->wa_Name)))
  3323.     {    ToolArray = (char **) DiskObject->do_ToolTypes;
  3324.         
  3325.         if (s = (char *) FindToolType(ToolArray, "NOFX"))
  3326.             fxable = 3;
  3327.         if (s = (char *) FindToolType(ToolArray, "NOMUSIC"))
  3328.             musicable = 3;
  3329.         if (s = (char *) FindToolType(ToolArray, "OVERHEAD"))
  3330.             iso = FALSE;
  3331.         if (s = (char *) FindToolType(ToolArray, "FILE"))
  3332.             strcpy(pathname, WBArg->wa_Name);
  3333.         if (s = (char *) FindToolType(ToolArray, "GREEN"))
  3334.         {    if (MatchToolValue(s, "HUMAN"))
  3335.                 worm[0].control = HUMAN;
  3336.             elif (MatchToolValue(s, "AMIGA"))
  3337.                 worm[0].control = AMIGA;
  3338.             elif (MatchToolValue(s, "NONE"))
  3339.                 worm[0].control = NONE;
  3340.         }
  3341.         if (s = (char *) FindToolType(ToolArray, "RED"))
  3342.         {    if (MatchToolValue(s, "HUMAN"))
  3343.                 worm[1].control = HUMAN;
  3344.             elif (MatchToolValue(s, "AMIGA"))
  3345.                 worm[1].control = AMIGA;
  3346.             elif (MatchToolValue(s, "NONE"))
  3347.                 worm[1].control = NONE;
  3348.         }
  3349.         if (s = (char *) FindToolType(ToolArray, "BLUE"))
  3350.         {    if (MatchToolValue(s, "HUMAN"))
  3351.                 worm[2].control = HUMAN;
  3352.             elif (MatchToolValue(s, "AMIGA"))
  3353.                 worm[2].control = AMIGA;
  3354.             elif (MatchToolValue(s, "NONE"))
  3355.                 worm[2].control = NONE;
  3356.         }
  3357.         if (s = (char *) FindToolType(ToolArray, "YELLOW"))
  3358.         {    if (MatchToolValue(s, "HUMAN"))
  3359.                 worm[2].control = HUMAN;
  3360.             elif (MatchToolValue(s, "AMIGA"))
  3361.                 worm[3].control = AMIGA;
  3362.             elif (MatchToolValue(s, "NONE"))
  3363.                 worm[3].control = NONE;
  3364.         }
  3365.         FreeDiskObject(DiskObject);
  3366. }    }
  3367.  
  3368. void pausetimer(void)
  3369. {    GetSysTime(CurrentValPtr);
  3370. }
  3371.  
  3372. void unpausetimer(void)
  3373. {    GetSysTime(PausedValPtr);
  3374.     SubTime(PausedValPtr, CurrentValPtr);
  3375.     AddTime(StartValPtr, PausedValPtr);
  3376. }
  3377.  
  3378. UBYTE ReadJoystick(UWORD joynum)
  3379. {    extern struct Custom far custom;
  3380.     UBYTE ret = 0;
  3381.     UWORD joy;
  3382.  
  3383.     if (joynum == 0)
  3384.         joy = custom.joy0dat;
  3385.     else joy = custom.joy1dat;
  3386.  
  3387.     ret += (joy >> 1 ^ joy) & 0x0100 ? JOYUP : 0;  
  3388.     ret += (joy >> 1 ^ joy) & 0x0001 ? JOYDOWN : 0;
  3389.     ret += joy & 0x0200 ? JOYLEFT : 0;
  3390.     ret += joy & 0x0002 ? JOYRIGHT : 0;
  3391.  
  3392.     if (joynum == 0)
  3393.     {    ret += !(cia->ciapra & 0x0040) ? JOYFIRE1 : 0;  /* Read FireButtons */
  3394.         ret += !(POTGOR & 0x0400) ? JOYFIRE2 : 0;          /* on joyport 0     */
  3395.     } else
  3396.     {    ret += !(cia->ciapra & 0x0080) ? JOYFIRE1 : 0; /* Read FireButtons */
  3397.         ret += !(POTGOR & 0x4000) ? JOYFIRE2 : 0;         /* on joyport 1     */
  3398.     }
  3399.  
  3400.     return(ret);
  3401. }
  3402.  
  3403. void joy0(void)
  3404. {    UBYTE joyval;
  3405.     ABOOL fire = FALSE;
  3406.     SBYTE xx = 0, yy = 0;
  3407.  
  3408.     if (worm[3].control == HUMAN && worm[3].lives)
  3409.     {    joyval = ReadJoystick(0);
  3410.  
  3411.         if (joyval & JOYUP)
  3412.             yy = -1;
  3413.         elif (joyval & JOYDOWN)
  3414.             yy = 1;
  3415.         if (joyval & JOYLEFT)
  3416.             xx = -1;
  3417.         elif (joyval & JOYRIGHT)
  3418.             xx = 1;
  3419.         if (joyval & JOYFIRE1)
  3420.             fire = TRUE;
  3421.         elif (joyval & JOYFIRE2)
  3422.             fire = TRUE;
  3423.         if (joyval != 0)
  3424.         {    if (fire)
  3425.                 queue(3, 0, 0);
  3426.             else queue(3, xx, yy);
  3427. }    }    }
  3428.       
  3429. // Must have blank line at EOF.
  3430.