home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Games / WormWars / Source / engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-09  |  112.0 KB  |  3,610 lines

  1. /* $Filename:       WormWars/Source/engine.c(pp) $
  2.  * $VER:            WormWars 4.4 $
  3.  * $Description:    Game engine $
  4.  *
  5.  * © Copyright 1999 James R. Jacobs. Freely distributable.
  6.  */
  7.  
  8. #include <string.h>
  9. #include <math.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>            // EXIT_SUCCESS, EXIT_FAILURE
  12.  
  13. #include "stdafx.h"
  14. #include "diff.h"
  15. #include "same.h"
  16. #include "engine.h"
  17.  
  18. // PRIVATE STRUCTURES -----------------------------------------------------
  19.  
  20. struct
  21. {    SBYTE        x, y, oldx, oldy;
  22.     ABOOL        alive, moved, teleported, visible, reflected;
  23. } bullet[POWERLIMIT + 1];
  24. struct
  25. {    SBYTE        x, y, type;
  26.     ABOOL        alive, moved;
  27. } drip[DRIPS + 1];
  28. struct
  29. {    SBYTE        x, y, deltax, deltay, last;
  30.     ABOOL        alive, moved;
  31. } frag[ORBS + 2][8];
  32. struct
  33. {    SBYTE        x, y, last;
  34.     ABOOL        alive;
  35. } killer[KILLERS + 1];
  36. struct
  37. {   SBYTE       x, y, deltax, deltay;
  38.     ABOOL        alive, moved;
  39. } missile[4];
  40.  
  41. struct
  42. {    UWORD        frequency;
  43.     SLONG        score;
  44. } object[LASTOBJECT + 1] =
  45. {    {1280,  60},    //    AFFIXER
  46.     {  80,  20},    //  AMMO
  47.     { 110,  20},    //    ARMOUR
  48.     {  90,  50},    //    BIAS
  49.     { 200,  30},    //    BOMB
  50.     {  80,  10},    //    BONUS
  51.     {1020,    60},    //    CLOCK
  52.     { 360,  50},    //    GROWER
  53.     {1900,    90},    //    HEALER
  54.     {1360,  60},    //    ICE
  55.     { 150,  50},    //    LIFE
  56.     { 240,  40},    //    MISSILE
  57.     { 640,  50},    //    MULTIPLIER
  58.     { 400,  10},    //    NITRO
  59.     { 240,  30},    //    POWER
  60.     { 480,  50},    //    PROTECTOR
  61.     { 600,  40},    //    SLAYER
  62.     { 980,  40},    //    SLOWER
  63.     { 730,  70},    //    SWITCHER
  64.     { 320,  20},    //    TONGUE
  65.     {2200, 100},    //    TREASURE
  66.     {3600, 100}        //    UMBRELLA
  67. };
  68.  
  69. /*    -200        common
  70.     220-400        uncommon
  71.     420-980        rare
  72.     1000+        very rare    */
  73.  
  74. struct
  75. {   SBYTE       x, y, deltax, deltay, relx, rely;
  76.     BOOL        alive, last, visible;
  77. } protector[4][PROTECTORS + 1];
  78. struct
  79. {    SBYTE        x, y, time;
  80.     BOOL        alive;
  81. } timebomb[TIMEBOMBS + 1];
  82. struct
  83. {    SBYTE        deltax;
  84.     SBYTE        deltay;
  85. } thequeue[4][QUEUELIMIT + 1];
  86.  
  87. SBYTE eachworm[4][2][9] =
  88. {    {    {    GREENHEADUP,        GREENHEADUP,        GREENHEADUP,
  89.             GREENHEADLEFT,        ANYTHING,            GREENHEADRIGHT,
  90.             GREENHEADDOWN,        GREENHEADDOWN,        GREENHEADDOWN
  91.         },
  92.         {    GREENMODEUP,        GREENMODEUP,        GREENMODEUP,
  93.             GREENMODELEFT,        ANYTHING,            GREENMODERIGHT,
  94.             GREENMODEDOWN,        GREENMODEDOWN,        GREENMODEDOWN
  95.     }    },
  96.     {    {    REDHEADUP,            REDHEADUP,            REDHEADUP,
  97.             REDHEADLEFT,        ANYTHING,            REDHEADRIGHT,
  98.             REDHEADDOWN,        REDHEADDOWN,        REDHEADDOWN
  99.         },
  100.         {    REDMODEUP,            REDMODEUP,            REDMODEUP,
  101.             REDMODELEFT,        ANYTHING,            REDMODERIGHT,
  102.             REDMODEDOWN,        REDMODEDOWN,        REDMODEDOWN
  103.     }    },
  104.     {    {    BLUEHEADUP,            BLUEHEADUP,            BLUEHEADUP,
  105.             BLUEHEADLEFT,        ANYTHING,            BLUEHEADRIGHT,
  106.             BLUEHEADDOWN,        BLUEHEADDOWN,        BLUEHEADDOWN
  107.         },
  108.         {    BLUEMODEUP,            BLUEMODEUP,            BLUEMODEUP,
  109.             BLUEMODELEFT,        ANYTHING,            BLUEMODERIGHT,
  110.             BLUEMODEDOWN,        BLUEMODEDOWN,        BLUEMODEDOWN
  111.     }    },
  112.     {    {    YELLOWHEADUP,        YELLOWHEADUP,        YELLOWHEADUP,
  113.             YELLOWHEADLEFT,        ANYTHING,            YELLOWHEADRIGHT,
  114.             YELLOWHEADDOWN,        YELLOWHEADDOWN,        YELLOWHEADDOWN
  115.         },
  116.         {    YELLOWMODEUP,        YELLOWMODEUP,        YELLOWMODEUP,
  117.             YELLOWMODELEFT,        ANYTHING,            YELLOWMODERIGHT,
  118.             YELLOWMODEDOWN,        YELLOWMODEDOWN,        YELLOWMODEDOWN
  119. }    }    };
  120.  
  121. // MODULE VARIABLES (used only within engine.c(pp)) -----------------------
  122.  
  123. MODULE    ABOOL                    letters[4][LETTERS + 1], trainer;
  124. MODULE    SBYTE                    dripspeed, fragspeed, killerspeed, orbspeed,
  125.                                 ice, noletter, treasurer;
  126. MODULE    SWORD                    dripfreq, killerfreq, orbfreq, slimefreq;
  127.  
  128. // GLOBAL VARIABLES (owned by engine.c(pp), imported by system.c(pp)) -----
  129.  
  130. AGLOBAL    ABOOL                    clearthem    = FALSE,
  131.                                 modified    = FALSE;
  132. AGLOBAL    SBYTE                    a = GAMEOVER,
  133.                                 board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  134.                                 brush = STONE,
  135.                                 field[FIELDX + 1][FIELDY + 1], hi = 3,
  136.                                 level = 1, levels, lo = 0, reallevel,
  137.                                 startx[MAXLEVELS + 1],
  138.                                 starty[MAXLEVELS + 1];
  139. AGLOBAL    SWORD                    secondsleft, secondsperlevel;
  140. AGLOBAL    STRPTR                    pathname = (STRPTR) DEFAULTSET;
  141. AGLOBAL    ULONG                    delay, r;
  142. AGLOBAL    struct HiScoreStruct    hiscore[HISCORES + 1];
  143. AGLOBAL    struct OrbStruct        orb[ORBS + 1];
  144. AGLOBAL    struct TeleportStruct    teleport[MAXLEVELS + 1][4];
  145. AGLOBAL    struct WormStruct        worm[4];
  146.  
  147. /* FUNCTIONS --------------------------------------------------------------
  148.  
  149. NAME        align -- right-justify a string within another string
  150. SYNOPSIS    align(STRPTR, SBYTE, TEXT);
  151. FUNCTION    Moves all text in a string to the right, padding with
  152.             spaces. Does not itself add a null terminator.
  153. INPUTS      string - pointer to the string of text
  154.               size - size in characters of the containing string
  155.             filler - what to pad the left of the string with
  156. NOTE        Null terminators are written over by thissy function, but that
  157.             does not matter, because calling functions use Text() with an
  158.             explicit length. This function only works with monospaced
  159.             fonts.
  160. MODULE      engine.c */
  161.  
  162. void align(STRPTR string, SBYTE size, TEXT filler)
  163. {   SBYTE i, shift, length;
  164.  
  165.     length = strlen((const char*) string);
  166.     shift = size - length;
  167.     for (i = 1; i <= length; i++)
  168.         *(string + size - i) = *(string + size - i - shift);
  169.     for (i = 0; i <= shift - 1; i++)
  170.         *(string + i) = filler;
  171. }
  172.  
  173. ABOOL blocked(SBYTE which, SBYTE deltax, SBYTE deltay)
  174. {   SBYTE thissy;
  175.  
  176.     thissy = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
  177.     if ((thissy < STONE || thissy > KILLER) && thissy != METAL)
  178.         return(FALSE);
  179.     else return(TRUE);
  180. }
  181.  
  182. void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
  183. {    SBYTE    counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
  184.     SLONG    score = 0L;
  185.  
  186.     effect(FXBOMBBLAST);
  187.  
  188.     strength = BOMBADD + (rand() % BOMBRAND);
  189.  
  190.     leftxmax = centrex - strength;
  191.     if (leftxmax < 0)
  192.         leftxmax = 0;
  193.     rightxmax = centrex + strength;
  194.     if (rightxmax > FIELDX)
  195.         rightxmax = FIELDX;
  196.     uppymax = centrey - strength;
  197.     if (uppymax < 0)
  198.         uppymax = 0;
  199.     downymax = centrey + strength;
  200.     if (downymax > FIELDY)
  201.         downymax = FIELDY;
  202.  
  203.     leftx = centrex;
  204.     rightx = centrex;
  205.     uppy = centrey;
  206.     downy = centrey;
  207.     for (counter = 1; counter <= strength; counter++)
  208.     {    if (leftx > leftxmax)
  209.         {    leftx--;
  210.             for (y = uppy; y <= downy; y++)
  211.                 score += squareblast(triggerer, player, field[leftx][y], leftx, y);
  212.         }
  213.         if (rightx < rightxmax)
  214.         {    rightx++;
  215.             for (y = uppy; y <= downy; y++)
  216.                 score += squareblast(triggerer, player, field[rightx][y], rightx, y);
  217.         }
  218.         if (uppy > uppymax)
  219.         {    uppy--;
  220.             for (x = leftx; x <= rightx; x++)
  221.                 score += squareblast(triggerer, player, field[x][uppy], x, uppy);
  222.         }
  223.         if (downy < downymax)
  224.         {    downy++;
  225.             for (x = leftx; x <= rightx; x++)
  226.                 score += squareblast(triggerer, player, field[x][downy], x, downy);
  227.     }    }
  228.  
  229.     if (triggerer == HEAD)
  230.     {    wormscore(player, score);
  231.         if (worm[player].bias)
  232.             stat(player, LIFE);
  233.     } else
  234.         orbscore(player, score);
  235. }
  236.  
  237. void bouncekiller(SBYTE which, SBYTE x, SBYTE y)
  238. {    SBYTE i;
  239.  
  240.     if (field[x][y] == KILLER)
  241.         for (i = 0; i <= KILLERS; i++)
  242.             if (killer[i].alive && x == killer[i].x && y == killer[i].y)
  243.             {    killer[i].alive = FALSE;
  244.                 draw(x, y, BONUS);
  245.                 field[x][y] = BONUS;
  246.                 orbscore(which, KILLKILLER);
  247. }            }
  248.  
  249. ABOOL bounceorb(SBYTE which, SBYTE x, SBYTE y)
  250. {    if (field[x][y] == METAL)
  251.         return TRUE;
  252.     elif (orb[which].mode == NONE)
  253.     {    if (field[x][y] >= FIRSTNONE && field[x][y] <= LASTNONE)
  254.             return TRUE;
  255.         else return FALSE;
  256.     } elif (orb[which].mode == TONGUE)
  257.     {    if (field[x][y] >= FIRSTTONGUE && field[x][y] <= LASTTONGUE)
  258.             return TRUE;
  259.         else return FALSE;
  260.     } else // assumes orb[which].mode == ARMOUR
  261.     {    if (field[x][y] >= FIRSTARMOUR && field[x][y] <= LASTARMOUR)
  262.             return TRUE;
  263.         else return FALSE;
  264. }    }
  265.  
  266. SBYTE bsign(SBYTE value)
  267. {    if (value < 0)
  268.         return (-1);
  269.     elif (value > 0)
  270.         return (1);
  271.     else
  272.         return (0);
  273. }
  274.  
  275. void changefield(void)
  276. {   SBYTE x, y;
  277.  
  278.     for (x = 0; x <= FIELDX; x++)
  279.         for (y = 0; y <= FIELDY; y++)
  280.             field[x][y] = board[level][x][y];
  281. }
  282.  
  283. void clearhiscores(void)
  284. {    SBYTE i;
  285.     
  286.     clearthem = FALSE;
  287.     for (i = 0; i <= HISCORES; i++)
  288.     {    hiscore[i].player = -1;
  289.         hiscore[i].level = 0;
  290.         hiscore[i].score = 0L;
  291.         hiscore[i].name[0] = 0;
  292.         hiscore[i].fresh = FALSE;
  293. }   }
  294.  
  295. void clearletters(void)
  296. {    SBYTE player, which;
  297.  
  298.     for (player = 0; player <= 3; player++)
  299.         for (which = 0; which <= LETTERS; which++)
  300.         {    letters[player][which] = FALSE;
  301.             drawletter(player, FIRSTLETTER + which, BLACK);
  302. }        }
  303.  
  304. void copyfield(SBYTE source, SBYTE destination)
  305. {    SBYTE which, x, y;
  306.  
  307.     for (x = 0; x <= FIELDX; x++)
  308.         for (y = 0; y <= FIELDY; y++)
  309.             board[destination][x][y] = board[source][x][y];
  310.     startx[destination] = startx[source];
  311.     starty[destination] = starty[source];
  312.     for (which = 0; which <= 1; which++)
  313.     {    teleport[destination][which].alive = teleport[source][which].alive;
  314.         teleport[destination][which].x     = teleport[source][which].x;
  315.         teleport[destination][which].y     = teleport[source][which].y;
  316. }    }
  317.  
  318. void death(void)
  319. {    SBYTE    counter, i, pain, player, survivor, which;
  320.     ABOOL    flag, slow;
  321.  
  322.     for (player = lo; player <= hi; player++)
  323.     {    if (worm[player].lives)
  324.         {   if (!worm[player].alive)
  325.             {    slow = FALSE;
  326.                 pain = 0;
  327.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  328.                 {    if (player == worm[player].cause - FIRSTTAIL)
  329.                         pain = TAILPAIN;
  330.                     else pain = OTHERTAILPAIN;
  331.                     slow = TRUE;
  332.                 } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  333.                     pain = WORMFIREPAIN;
  334.                 elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  335.                     pain = HEADPAIN;
  336.                 elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  337.                     pain = PROTECTORPAIN;
  338.                 elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  339.                     pain = MISSILEPAIN;
  340.                 elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
  341.                     pain = DRIPPAIN;
  342.                 else switch (worm[player].cause)
  343.                 {
  344.                 case BOMB:
  345.                     pain = BOMBPAIN;
  346.                     break;
  347.                 case WOOD:
  348.                     pain = WOODPAIN;
  349.                     slow = TRUE;
  350.                     break;
  351.                 case FRAGMENT:
  352.                     pain = FRAGMENTPAIN;
  353.                     break;
  354.                 case KILLER:
  355.                     pain = KILLERPAIN;
  356.                     slow = TRUE;
  357.                     break;
  358.                 case SLAYER:
  359.                     pain = SLAYERPAIN;
  360.                     break;
  361.                 case STONE:
  362.                     pain = STONEPAIN;
  363.                     slow = TRUE;
  364.                     break;
  365.                 case TELEPORT:
  366.                     pain = TELEPORTPAIN;
  367.                     slow = TRUE;
  368.                     break;
  369.                 case SLIME:
  370.                     pain = SLIMEPAIN;
  371.                     slow = TRUE;
  372.                     break;
  373.                 case METAL:
  374.                     pain = METALPAIN;
  375.                     slow = TRUE;
  376.                     break;
  377.                 default:
  378.                     break;
  379.                 }
  380.                 if (worm[player].victor >= 0 && worm[player].victor != player)
  381.                 {    wormscore(worm[player].victor, KILLWORM);
  382.                     if (worm[worm[player].victor].bias)
  383.                     {    worm[worm[player].victor].lives += pain;
  384.                         stat(worm[player].victor, LIFE);
  385.                 }    }
  386.                 if (slow)
  387.                 {    worm[player].speed = slowdown(worm[player].speed);
  388.                     stat(player, NITRO); 
  389.                 }
  390.                 if (pain > worm[player].lives)
  391.                     worm[player].lives = 0;
  392.                 else worm[player].lives -= pain;
  393.                 draw(worm[player].x, worm[player].y, SKULL);
  394.                 drawcause(player, NORMAL);
  395.                 stat(player, LIFE);
  396.                 if (level)
  397.                     worm[player].levelreached = level;
  398.                 else worm[player].levelreached = reallevel;
  399.                 if (worm[player].lives)
  400.                 {    flag = FALSE;
  401.                     for (i = lo; i <= hi; i++)
  402.                         if (worm[i].control == HUMAN)
  403.                             flag = TRUE;
  404.                     if (!flag || worm[player].control == HUMAN)
  405.                         effect(FXPAIN + player);
  406.                     // Amiga-worms only make pain sounds in demo mode
  407.                     worm[player].alive = TRUE;
  408.                     worm[player].causewait = r + CAUSEWAIT;
  409.                 } else
  410.                 {    // kill worm
  411.  
  412.                     effect(FXWORMDEATH);
  413.                     if (ice == player)
  414.                         ice = -1;
  415.                     field[worm[player].x][worm[player].y] = SKULL;
  416.                     for (which = 0; which <= PROTECTORS; which++)
  417.                     {    if (protector[player][which].alive && protector[player][which].visible)
  418.                         {    draw(protector[player][which].x, protector[player][which].y, EMPTY);
  419.                             field[protector[player][which].x][protector[player][which].y] = EMPTY;
  420.                     }    }
  421.                     counter = 0;
  422.                     for (which = lo; which <= hi; which++)
  423.                         if (worm[which].lives)
  424.                         {    survivor = which;
  425.                             counter++;
  426.                         }
  427.                     if (counter == 1)
  428.                         wormscore(survivor, SURVIVOR);
  429.     }    }    }    }
  430.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  431.     {    // End of game
  432.         newhiscores();
  433.         effect(FXDEFEAT);
  434.         a = GAMEOVER;
  435.         if (lo == hi)
  436.             say((STRPTR) "Game over!", worm[lo].colour);
  437.         elif (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
  438.             say((STRPTR) "Green wins!", GREEN);
  439.         elif (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
  440.             say((STRPTR) "Red wins!", RED);
  441.         elif (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
  442.             say((STRPTR) "Blue wins!", BLUE);
  443.         elif (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
  444.             say((STRPTR) "Yellow wins!", YELLOW);
  445.         else say((STRPTR) "A draw!", WHITE);
  446.         waitasec();
  447.         anykey(FALSE);
  448. }    }
  449.  
  450. void drawcause(SBYTE player, SBYTE state)
  451. {    if (state == BLACK)
  452.         draw(-2 + ((FIELDX + 4) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), BLACKENED);
  453.     else draw(-2 + ((FIELDX + 4) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), worm[player].cause);
  454. }
  455.  
  456. void drawletter(SBYTE player, SBYTE letter, SBYTE state)
  457. {    SBYTE thissy;
  458.     
  459.     if (state == BLACK)
  460.         thissy = BLACKENED;
  461.     else thissy = letter;
  462.     if (!worm[player].statx)
  463.         if (!worm[player].staty)
  464.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  465.                 (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  466.                 thissy);
  467.         else
  468.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  469.                 (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  470.                 thissy);
  471.     else
  472.         if (!worm[player].staty)
  473.             draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
  474.                 (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  475.                 thissy);
  476.             else
  477.                 draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
  478.                 (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  479.                 thissy);
  480. }
  481.  
  482. /* NAME     enginesetup -- once-only initialization of engine variables
  483. SYNOPSIS    enginesetup(void);
  484. FUNCTION    Sets up the unchanging worm variables.
  485. MODULE      engine.c */
  486.  
  487. void enginesetup(void)
  488. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  489.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  490.     worm[0].colour    = GREEN;
  491.     worm[1].colour    = RED;
  492.     worm[2].colour    = BLUE;
  493.     worm[3].colour    = YELLOW;
  494.     worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
  495.  
  496.     systemsetup();
  497. }
  498.  
  499. /* NAME     fastloop -- things done often
  500. SYNOPSIS    fastloop(void);
  501. FUNCTION    Checks for and handles level completion.
  502. MODULE      engine.c */
  503.  
  504. void fastloop(void)
  505. {    ABOOL    complete;
  506.     SBYTE    advancer = -1, player, which;
  507.     
  508.     // handle level completion
  509.  
  510.     for (player = lo; player <= hi; player++)
  511.     {    complete = TRUE;
  512.         for (which = 0; which <= LETTERS; which++)
  513.             if (!letters[player][which])
  514.                 complete = FALSE;
  515.         if (complete)
  516.             advancer = player;
  517.     }
  518.     if (advancer != -1)
  519.     {    if (level++ == 0)
  520.         {    level = reallevel + 1;
  521.             reallevel = 0;
  522.         }
  523.         stopfx(0L);
  524.         if (level > levels)
  525.             effect(FXVICTORY);
  526.         newlevel(advancer);
  527. }    }
  528.  
  529. void fillfield(SBYTE which)
  530. {    SBYTE x, y;
  531.  
  532.     for (x = 0; x <= FIELDX; x++)
  533.         for (y = 0; y <= FIELDY; y++)
  534.         {    board[level][x][y] = which;
  535.             draw(x, y, which);
  536.         }
  537.     board[level][startx[level]][starty[level]] = EMPTY;
  538.     draw(startx[level], starty[level], START);
  539.     if (teleport[level][0].alive)
  540.     {    board[level][teleport[level][0].x][teleport[level][0].y] = TELEPORT;
  541.         draw(teleport[level][0].x, teleport[level][0].y, ONE);
  542.     }
  543.     if (teleport[level][1].alive)
  544.     {    board[level][teleport[level][1].x][teleport[level][1].y] = TELEPORT;
  545.         draw(teleport[level][1].x, teleport[level][1].y, TWO);
  546. }    }
  547.  
  548. ABOOL findempty(SBYTE* x, SBYTE* y, SBYTE first, SBYTE last)
  549. {    SBYTE count = 0, xx, yy;
  550.  
  551.     do
  552.     {    xx = rand() % (FIELDX + 1);
  553.         yy = rand() % (FIELDY + 1);
  554.     } while ((field[xx][yy] < first || field[xx][yy] > last) && ++count < PATIENCE);
  555.     if (count < PATIENCE)
  556.     {    *x = xx;
  557.         *y = yy;
  558.         return(TRUE);
  559.     } else return(FALSE);
  560. }
  561.  
  562. /* NAME     fragloop -- controls fragments
  563. SYNOPSIS    fragloop(void);
  564. FUNCTION    Controls all fragments.
  565. MODULE      engine.c */
  566.  
  567. void fragloop(void)
  568. {    SBYTE    i, j, k, thissy, which;
  569.  
  570. for (which = 0; which <= ORBS + 1; which++)
  571.     for (i = 0; i <= 7; i++)
  572.         if (frag[which][i].alive)
  573.         {   if (frag[which][i].moved)
  574.             {   draw(frag[which][i].x, frag[which][i].y, frag[which][i].last);
  575.                 field[frag[which][i].x][frag[which][i].y] = frag[which][i].last;
  576.             } else frag[which][i].moved = TRUE;
  577.             frag[which][i].x += frag[which][i].deltax;
  578.             frag[which][i].y += frag[which][i].deltay;
  579.             if (!(valid(frag[which][i].x, frag[which][i].y)))
  580.                 frag[which][i].alive = FALSE;
  581.             else
  582.             {    thissy = field[frag[which][i].x][frag[which][i].y];
  583.                 if (thissy >= FIRSTFRAGDEATH && thissy <= LASTFRAGDEATH)
  584.                 {   effect(FXTHUD);
  585.                     frag[which][i].alive = FALSE;
  586.                     if (thissy == KILLER)
  587.                     {   effect(FXKILLERDEATH);
  588.                         j = whichkiller(frag[which][i].x, frag[which][i].y);
  589.                         killer[j].alive = FALSE;
  590.                         field[killer[j].x][killer[j].y] = BONUS;
  591.                         draw(killer[j].x, killer[j].y, BONUS);
  592.                 }   }
  593.                 elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  594.                 {    effect(FXUSEPROTECTOR);
  595.                     reflect(which, i);
  596.                 } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  597.                 {    frag[which][i].alive = FALSE;
  598.                     missile[thissy - FIRSTMISSILE].alive = FALSE;
  599.                     field[missile[thissy - FIRSTMISSILE].x][missile[thissy - FIRSTMISSILE].y] = EMPTY;
  600.                     draw(missile[thissy - FIRSTMISSILE].x, missile[thissy - FIRSTMISSILE].y, EMPTY);
  601.                 } elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  602.                 {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  603.                     {    worm[thissy - FIRSTHEAD].cause = FRAGMENT;
  604.                         worm[thissy - FIRSTHEAD].victor = -1;
  605.                         worm[thissy - FIRSTHEAD].alive = FALSE;
  606.                     } else
  607.                     {    effect(FXUSEARMOUR);
  608.                         reflect(which, i);
  609.                 }    }
  610.                 elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  611.                 {    j = whichdrip(frag[which][i].x, frag[which][i].y);
  612.                     drip[j].alive = FALSE;
  613.                     frag[which][i].alive = FALSE;
  614.                     field[frag[which][i].x][frag[which][i].y] = BONUS;
  615.                     draw(frag[which][i].x, frag[which][i].y, BONUS);
  616.                 } else switch(thissy)
  617.                 {
  618.                 case METAL:
  619.                     reflect(which, i);
  620.                     break;
  621.                 case ORB:
  622.                     j = whichorb(frag[which][i].x, frag[which][i].y);
  623.                     if (orb[j].mode != ARMOUR)
  624.                         orb[j].explode = TRUE;
  625.                     else effect(FXUSEARMOUR);
  626.                     frag[which][i].alive = FALSE;
  627.                     break;
  628.                 case TELEPORT:
  629.                     j = whichteleport(frag[which][i].x, frag[which][i].y);
  630.                     if (blocked(j, frag[which][i].deltax, frag[which][i].deltay))
  631.                         frag[which][i].alive = FALSE;
  632.                     else
  633.                     {   effect(FXUSETELEPORT);
  634.                         frag[which][i].x = xwrap(teleport[level][partner(j)].x + frag[which][i].deltax);
  635.                         frag[which][i].y = ywrap(teleport[level][partner(j)].y + frag[which][i].deltay);
  636.                         frag[which][i].last = SILVER;
  637.                     }
  638.                     break;
  639.                 case BOMB:
  640.                     j = whichtimebomb(frag[which][i].x, frag[which][i].y);
  641.                     if (j != -1)
  642.                     {   frag[which][i].alive = FALSE;
  643.                         timebomb[j].alive = FALSE;
  644.                         field[timebomb[j].x][timebomb[j].y] = EMPTY;
  645.                         draw(timebomb[j].x, timebomb[j].y, EMPTY);
  646.                         bombblast(BOMB, 0, timebomb[j].x, timebomb[j].y);
  647.                     }
  648.                     break;
  649.                 case FRAGMENT:
  650.                     effect(FXTHUD);
  651.                     draw(frag[which][i].x, frag[which][i].y, EMPTY);
  652.                     frag[which][i].alive = FALSE;
  653.                     whichfrag(frag[which][i].x, frag[which][i].y, &j, &k);
  654.                     frag[j][k].alive = FALSE;
  655.                     break;
  656.                 default:
  657.                     break;
  658.                 }
  659.                 if (frag[which][i].alive)
  660.                 {   field[frag[which][i].x][frag[which][i].y] = FRAGMENT;
  661.                     draw(frag[which][i].x, frag[which][i].y, FRAGMENT);
  662.         }    }    }
  663. }
  664.  
  665. void gameloop(void)
  666. {    SBYTE player, which;
  667.  
  668.     fastloop();
  669.     gameinput();
  670.     for (player = lo; player <= hi; player++)
  671.         if (worm[player].lives && !(r % worm[player].speed) && (ice == -1 || ice == player))
  672.             wormloop(player);
  673.     if (ice == -1)
  674.     {    for (which = 0; which <= ORBS; which++)
  675.             if (orb[which].alive && !(r % orb[which].speed))
  676.                 if (orb[which].explode)
  677.                     orbexplosion(which);
  678.                 else orbloop(which);
  679.         if (!(r % killerspeed))
  680.             killerloop();
  681.         if (!(r % dripspeed))
  682.             driploop();
  683.         if (!(r % fragspeed))
  684.             fragloop();
  685.         if (!(r % MISSILESPEED))
  686.             missileloop();
  687.     }
  688.     if (a == PLAYGAME)
  689.     {    death();
  690.         if (!(r % VERYSLOW))
  691.             slowloop();
  692.     }
  693.     timing();
  694. }
  695.  
  696. void killall(void)
  697. {    SBYTE iwhich, which;
  698.  
  699.     for (which = 0; which <= ORBS; which++)
  700.         orb[which].alive = FALSE;
  701.     for (which = 0; which <= KILLERS; which++)
  702.         killer[which].alive = FALSE;
  703.     for (which = 0; which <= ORBS + 1; which++)
  704.         for (iwhich = 0; iwhich <= 7; iwhich++)
  705.             frag[which][iwhich].alive = FALSE;
  706.     for (which = 0; which <= 3; which++)
  707.         if (missile[which].alive)
  708.             missile[which].alive = FALSE;
  709.     for (which = 0; which <= TIMEBOMBS; which++)
  710.         timebomb[which].alive = FALSE;
  711.     teleport[level][2].alive = FALSE;
  712.     teleport[level][3].alive = FALSE;
  713. }
  714.  
  715. void killerloop(void)
  716. {    ABOOL    happy;
  717.     UBYTE    count;
  718.     SBYTE    which, x, xx, y, yy;
  719.  
  720.     for (which = 0; which <= KILLERS; which++)
  721.         if (killer[which].alive)
  722.         {    happy = FALSE;
  723.             for (x = killer[which].x - 1; x <= killer[which].x + 1; x++)
  724.                 for (y = killer[which].y - 1; y <= killer[which].y + 1; y++)
  725.                     if (field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  726.                         happy = TRUE;
  727.             if ((!happy) || (!(rand() % RESTFULNESS)))
  728.             {    x = (rand() % 3) - 1;
  729.                 y = (rand() % 3) - 1;
  730.                 if (valid(killer[which].x + x, killer[which].y + y) && (x || y)
  731.                 && field[killer[which].x + x][killer[which].y + y] >= FIRSTKILLER && field[killer[which].x + x][killer[which].y + y] <= LASTKILLER && field[killer[which].x + x][killer[which].y + y] != KILLER)
  732.                 {    field[killer[which].x][killer[which].y] = killer[which].last;
  733.                     draw(killer[which].x, killer[which].y, killer[which].last);
  734.                     killer[which].x += x;
  735.                     killer[which].y += y;
  736.                     killer[which].last = field[killer[which].x][killer[which].y];
  737.                     field[killer[which].x][killer[which].y] = KILLER;
  738.                     draw(killer[which].x, killer[which].y, KILLER);
  739.             }    }
  740.             if (!frag[ORBS + 1][which].alive && !(rand() % KILLERFIREFREQ))
  741.             {    count = 0;
  742.                 do
  743.                 {    x = (rand() % 3) - 1;
  744.                     y = (rand() % 3) - 1;
  745.                     xx = killer[which].x + x;
  746.                     yy = killer[which].y + y;
  747.                 } while (((!x && !y) || xx < 0 || xx > FIELDX || yy < 0 || yy > FIELDY || field[xx][yy] > LASTKILLERFIRE) && ++count < PATIENCE);
  748.                 if (count < PATIENCE)
  749.                 {    effect(FXKILLERFIRE);
  750.                     frag[ORBS + 1][which].alive = TRUE;
  751.                     frag[ORBS + 1][which].x = killer[which].x;
  752.                     frag[ORBS + 1][which].y = killer[which].y;
  753.                     frag[ORBS + 1][which].deltax = x;
  754.                     frag[ORBS + 1][which].deltay = y;
  755.                     frag[ORBS + 1][which].moved = FALSE;
  756.                     frag[ORBS + 1][which].last = EMPTY;
  757. }        }    }    }
  758.  
  759. void levelappend(void)
  760. {    UBYTE oldlevel;
  761.  
  762.     if (levels < MAXLEVELS)
  763.     {    oldlevel = level;
  764.         level = ++levels;
  765.         newfield();
  766.         level = oldlevel;
  767.         saylevel(WHITE);
  768. }    }
  769.  
  770. void leveldelete(void)
  771. {    SBYTE i;
  772.  
  773.     // pull boards
  774.  
  775.     if (levels > 1)
  776.     {    if (level < levels)
  777.             for (i = level; i < levels; i++)
  778.                 copyfield(i + 1, i);
  779.         else
  780.             level--;
  781.         levels--;
  782.         saylevel(WHITE);
  783.         renderboard();
  784. }    }
  785.  
  786. void levelerase(void)
  787. {    newfield();
  788.     renderboard();
  789. }
  790.  
  791. void levelinsert(void)
  792. {    SBYTE i;
  793.  
  794.     // push boards
  795.  
  796.     if (levels < MAXLEVELS)
  797.     {    for (i = levels; i >= level; i--)
  798.             copyfield(i, i + 1);
  799.         levels++;
  800.         saylevel(WHITE);
  801.         newfield();
  802.         renderboard();
  803. }    }
  804.  
  805. ABOOL loadfields(STRPTR fieldname)
  806. {    SBYTE                i, j, x, y;
  807.     TEXT                IOBuffer[NAMELENGTH + 1];
  808.     UBYTE                ver;
  809.  
  810.     /* This routine is not entirely robust, especially regarding
  811.     failures part way through reading. Also, field data values must be
  812.     those supported by the field editor (ie. objects, and the squares
  813.     represented by F1-F8), or undefined behaviour may result. None of
  814.     this is currently checked for. Provided that the fieldset was
  815.     created with the field editor (4.1+), and the file is not corrupt,
  816.     these failures should never happen anyway.
  817.  
  818.     open file */
  819.  
  820.     if (!ZOpen(fieldname, FALSE))
  821.         return FALSE; // fail point 1: no harm done
  822.  
  823.     // read header
  824.  
  825.     if (!ZRead(IOBuffer, 10))
  826.     {    ZClose();
  827.         return FALSE; // fail point 2: no harm done
  828.     }
  829.     if (!strcmp(IOBuffer, "FSET 4.4"))
  830.         ver = 44;
  831.     elif (!strcmp(IOBuffer, "FSET 4.3"))
  832.         ver = 43;
  833.     elif (!strcmp(IOBuffer, "FSET 4.2"))
  834.         ver = 42;
  835.     elif (!stricmp(IOBuffer, "FSET 4.1"))
  836.         ver = 41;
  837.     else
  838.     {    ZClose();
  839.         return FALSE; // fail point 3: no harm done
  840.     }
  841.     levels                            = IOBuffer[9];
  842.  
  843.     // read high score table
  844.  
  845.     for (i = 0; i <= HISCORES; i++)
  846.     {    if (!ZRead(IOBuffer, 6))
  847.         {    ZClose();
  848.             return FALSE; // fail point 4: incorrect levels
  849.         }
  850.         hiscore[i].fresh            =  FALSE;
  851.         hiscore[i].player            =  IOBuffer[0];
  852.         hiscore[i].level            =  IOBuffer[1];
  853.         hiscore[i].score            = (IOBuffer[3] * 65536)
  854.                                     + (IOBuffer[4] * 256)
  855.                                     +  IOBuffer[5];
  856.  
  857.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  858.         {    ZClose();
  859.             return FALSE;
  860.             // fail point 5: incorrect levels, corrupted high scores
  861.         }
  862.         for (j = 0; j <= NAMELENGTH; j++)
  863.             hiscore[i].name[j]        = IOBuffer[j];
  864.     }
  865.  
  866.     // read level data
  867.  
  868.     for (i = 0; i <= levels; i++)
  869.     {   if (!ZRead(IOBuffer, 8))
  870.         {    ZClose();
  871.             return FALSE;
  872.             /* fail point 6: incorrect levels, corrupted high scores,
  873.             incorrect startx, teleports, field data */
  874.         }
  875.         startx[i]                    =  IOBuffer[0];
  876.         starty[i]                    =  IOBuffer[1];
  877.         teleport[i][0].alive        =  IOBuffer[2];
  878.         teleport[i][0].x            =  IOBuffer[3];
  879.         teleport[i][0].y            =  IOBuffer[4];
  880.         teleport[i][1].alive        =  IOBuffer[5];
  881.         teleport[i][1].x            =  IOBuffer[6];
  882.         teleport[i][1].y            =  IOBuffer[7];
  883.  
  884.         if (!ZRead((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
  885.         {    ZClose();
  886.             return FALSE;
  887.             /* fail point 7: incorrect levels, corrupted high scores,
  888.             incorrect startx, teleports, field data */
  889.         } else
  890.         {    if (ver == 41)
  891.             {    // convert from FSET 4.1 to FSET 4.2 format
  892.  
  893.                 for (x = 0; x <= FIELDX; x++)
  894.                     for (y = 0; y <= FIELDY; y++)
  895.                         if (board[i][x][y] == 18) // old HEALER
  896.                             board[i][x][y] = 7; // new HEALER
  897.                         elif (board[i][x][y] >= 7)
  898.                             board[i][x][y]++;
  899.             }
  900.             if (ver == 41 || ver == 42)
  901.             {    // convert from FSET 4.2 to FSET 4.3 format
  902.  
  903.                 for (x = 0; x <= FIELDX; x++)
  904.                     for (y = 0; y <= FIELDY; y++)
  905.                         if (board[i][x][y] >= CLOCK && board[i][x][y] <= FX)
  906.                             board[i][x][y]++;
  907.             }
  908.             if (ver >= 41 && ver <= 43)
  909.             {    // convert from FSET 4.3 to FSET 4.4 format
  910.                 
  911.                 for (x = 0; x <= FIELDX; x++)
  912.                     for (y = 0; y <= FIELDY; y++)
  913.                         if (board[i][x][y] >= 17)
  914.                             board[i][x][y]++;
  915.     }    }    }
  916.  
  917.     // no need to read version string
  918.  
  919.     ZClose();
  920.     modified = FALSE;
  921.     return TRUE;
  922. }
  923.  
  924. void matchteleports(void)
  925. {    SBYTE which;
  926.  
  927.     for (which = 0; which <= levels; which++)
  928.         if (teleport[which][0].alive == TRUE && teleport[which][1].alive == FALSE)
  929.         {    board[which][teleport[which][0].x][teleport[which][0].y] = EMPTY;
  930.             teleport[which][0].alive = FALSE;
  931.             if (level == which && a == FIELDEDIT)
  932.                 draw(teleport[which][0].x, teleport[which][0].y, EMPTY);
  933.         } elif (teleport[which][0].alive == FALSE && teleport[which][1].alive == TRUE)
  934.         {    board[which][teleport[which][1].x][teleport[which][1].y] = EMPTY;
  935.             teleport[which][1].alive = FALSE;
  936.             if (level == which && a == FIELDEDIT)
  937.                 draw(teleport[which][1].x, teleport[which][1].y, EMPTY);
  938. }        }
  939.  
  940. /* NAME     missileloop -- controls missiles
  941. SYNOPSIS    missileloop(void);
  942. FUNCTION    Controls all killers.
  943. MODULE      engine.c */
  944.  
  945. void missileloop(void)
  946. {    SBYTE    distx, disty, distance, iwhich, player, thissy, which;
  947.     UBYTE   bestdistance;
  948.     
  949.     for (player = lo; player <= hi; player++)
  950.     {   if (missile[player].alive && (ice == -1 || ice == player))
  951.         {   bestdistance = (UBYTE) -1;
  952.             for (which = lo; which <= hi; which++)
  953.                 if (which != player && worm[which].lives > 0 && !worm[which].bias)
  954.                 {   distx = abs(worm[which].x - missile[player].x);
  955.                     disty = abs(worm[which].y - missile[player].y);
  956.                     if (distx < disty)
  957.                         distance = distx;
  958.                     else distance = disty;
  959.                     if (distance <= bestdistance)
  960.                     {   bestdistance = distance;
  961.                         missile[player].deltax = bsign(worm[which].x - missile[player].x);
  962.                         missile[player].deltay = bsign(worm[which].y - missile[player].y);
  963.                 }    }
  964.             for (which = lo; which <= hi; which++)
  965.                 if (which != player && missile[which].alive)
  966.                 {   distx = abs(missile[which].x - missile[player].x);
  967.                     disty = abs(missile[which].y - missile[player].y);
  968.                     if (distx < disty)
  969.                         distance = distx;
  970.                     else distance = disty;
  971.                     if (distance <= bestdistance)
  972.                     {   bestdistance = distance;
  973.                         missile[player].deltax = bsign(missile[which].x - missile[player].x);
  974.                         missile[player].deltay = bsign(missile[which].y - missile[player].y);
  975.                 }    }
  976.             for (which = 0; which <= ORBS; which++)
  977.                 if (orb[which].alive)
  978.                 {   distx = abs(orb[which].x - missile[player].x) * 2;
  979.                     disty = abs(orb[which].y - missile[player].y) * 2;
  980.                     if (distx < disty)
  981.                         distance = distx;
  982.                     else distance = disty;
  983.                     if (distance <= bestdistance)
  984.                     {   bestdistance = distance;
  985.                         missile[player].deltax = bsign(orb[which].x - missile[player].x);
  986.                         missile[player].deltay = bsign(orb[which].y - missile[player].y);
  987.                 }    }
  988.             for (which = 0; which <= KILLERS; which++)
  989.                 if (killer[which].alive)
  990.                 {    distx = abs(killer[which].x - missile[player].x) * 2;
  991.                     disty = abs(killer[which].y - missile[player].y) * 2;
  992.                     if (distx < disty)
  993.                         distance = distx;
  994.                     else distance = disty;
  995.                     if (distance <= bestdistance)
  996.                     {   bestdistance = distance;
  997.                         missile[player].deltax = bsign(killer[which].x - missile[player].x);
  998.                         missile[player].deltay = bsign(killer[which].y - missile[player].y);
  999.                 }    }
  1000.             if (missile[player].moved)
  1001.             {   draw(missile[player].x, missile[player].y, EMPTY);
  1002.                 field[missile[player].x][missile[player].y] = EMPTY;
  1003.             } else missile[player].moved = TRUE;
  1004.             if (bestdistance == (UBYTE) -1)
  1005.                 missile[player].alive = FALSE;
  1006.             else
  1007.             {   missile[player].x += missile[player].deltax;
  1008.                 missile[player].y += missile[player].deltay;
  1009.                 thissy = field[missile[player].x][missile[player].y];
  1010.                 if (thissy >= FIRSTLETTER && thissy <= WOOD)
  1011.                 {   missile[player].alive = FALSE;
  1012.                     if (thissy == KILLER)
  1013.                     {   effect(FXKILLERDEATH);
  1014.                         which = whichkiller(missile[player].x, missile[player].y);
  1015.                         killer[which].alive = FALSE;
  1016.                         field[killer[which].x][killer[which].y] = BONUS;
  1017.                         draw(killer[which].x, killer[which].y, BONUS);
  1018.                         wormscore(player, KILLKILLER);
  1019.                         if (worm[player].bias)
  1020.                         {   worm[player].lives += KILLERBLOOD;
  1021.                             stat(player, LIFE);
  1022.                 }   }   }
  1023.                 elif (thissy == FRAGMENT)
  1024.                 {   missile[player].alive = FALSE;
  1025.                     whichfrag(missile[player].x, missile[player].y, &which, &iwhich);
  1026.                     frag[which][iwhich].alive = FALSE;
  1027.                     draw(missile[player].x, missile[player].y, EMPTY);
  1028.                 } elif (thissy == ORB)
  1029.                 {    missile[player].alive = FALSE;
  1030.                     which = whichorb(missile[player].x, missile[player].y);
  1031.                     if (orb[which].mode != ARMOUR)
  1032.                     {   effect(FXORBDEATH);
  1033.                         orb[which].alive = FALSE;
  1034.                         draw(orb[which].x, orb[which].y, BONUS);
  1035.                         field[orb[which].x][orb[which].y] = BONUS;
  1036.                         wormscore(player, orb[which].score);
  1037.                         if (worm[player].bias)
  1038.                         {   worm[player].lives += ORBBLOOD;
  1039.                             stat(player, LIFE);
  1040.                         }
  1041.                     } else effect(FXUSEARMOUR);
  1042.                 } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  1043.                 {   if (player != thissy - FIRSTPROTECTOR)
  1044.                     {    effect(FXUSEPROTECTOR);
  1045.                         missile[player].alive = FALSE;
  1046.                 }   }
  1047.                 elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  1048.                     missile[player].alive = FALSE;
  1049.                 elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  1050.                 {   missile[player].alive = FALSE;
  1051.                     if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  1052.                     {    worm[thissy - FIRSTHEAD].cause = FIRSTMISSILE + player;
  1053.                         worm[thissy - FIRSTHEAD].victor = player;
  1054.                         worm[thissy - FIRSTHEAD].alive = FALSE;
  1055.                     } else effect(FXUSEARMOUR);
  1056.                 } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  1057.                 {    missile[player].alive = FALSE;
  1058.                     missile[thissy - FIRSTMISSILE].alive = FALSE;
  1059.                     field[missile[which].x][missile[which].y] = BONUS;
  1060.                     draw(missile[which].x, missile[which].y, BONUS);
  1061.                 } elif (thissy == TELEPORT)
  1062.                 {   which = whichteleport(missile[player].x, missile[player].y);
  1063.                     if (blocked(which, missile[player].deltax, missile[player].deltay))
  1064.                         missile[player].alive = FALSE;
  1065.                     else
  1066.                     {   effect(FXUSETELEPORT);
  1067.                         missile[player].x = xwrap(teleport[level][partner(which)].x + missile[player].deltax);
  1068.                         missile[player].y = ywrap(teleport[level][partner(which)].y + missile[player].deltay);
  1069.                 }   }
  1070.                 elif (thissy == BOMB)
  1071.                 {   which = whichtimebomb(missile[player].x, missile[player].y);
  1072.                     if (which != -1)
  1073.                     {    missile[player].alive = FALSE;
  1074.                         timebomb[which].alive = FALSE;
  1075.                         field[timebomb[which].x][timebomb[which].y] = EMPTY;
  1076.                         draw(timebomb[which].x, timebomb[which].y, EMPTY);
  1077.                         bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
  1078.                 }   }
  1079.                 elif (thissy == SKULL || thissy == METAL)
  1080.                     missile[player].alive = FALSE;
  1081.                 if (missile[player].alive)
  1082.                 {    draw(missile[player].x, missile[player].y, FIRSTMISSILE + player);
  1083.                     field[missile[player].x][missile[player].y] = FIRSTMISSILE + player;
  1084. }   }   }   }   }
  1085.  
  1086. void newfield(void)
  1087. {    int x, y;
  1088.  
  1089.     teleport[level][0].alive = FALSE;
  1090.     teleport[level][1].alive = FALSE;
  1091.     startx[level] = FIELDX / 2;
  1092.     starty[level] = FIELDY / 2;
  1093.  
  1094.     if (level)
  1095.         for (x = 0; x <= FIELDX; x++)
  1096.             for (y = 0; y <= FIELDY; y++)
  1097.                 board[level][x][y] = EMPTY;
  1098.     else for (x = 0; x <= FIELDX; x++)
  1099.         for (y = 0; y <= FIELDY; y++)
  1100.             board[0][x][y] = SILVER;
  1101. }
  1102.  
  1103. void newfields(void)
  1104. {    if (verify())
  1105.     {   pathname = (STRPTR) DEFAULTSET;
  1106.         levels = DEFAULTLEVELS;
  1107.         modified = FALSE;
  1108.         for (level = 0; level <= levels; level++)
  1109.             newfield();
  1110.         clearhiscores();
  1111.         level = 1;
  1112.         if (a == FIELDEDIT)
  1113.         {    renderboard();
  1114.             saylevel(WHITE);
  1115.         } else
  1116.             hiscores();
  1117. }    }
  1118.  
  1119. void newgame(void)
  1120. {    SBYTE player;
  1121.  
  1122.     if (worm[0].control != NONE)
  1123.         lo = 0;
  1124.     elif (worm[1].control != NONE)
  1125.         lo = 1;
  1126.     elif (worm[2].control != NONE)
  1127.         lo = 2;
  1128.     else lo = 3;
  1129.     if (worm[3].control != NONE)
  1130.         hi = 3;
  1131.     elif (worm[2].control != NONE)
  1132.         hi = 2;
  1133.     elif (worm[1].control != NONE)
  1134.         hi = 1;
  1135.     else hi = 0;
  1136.  
  1137.     for (player = 0; player <= 3; player++)
  1138.         worm[player].lives = 0;
  1139.  
  1140.     r            = -1;
  1141.     trainer        = FALSE;
  1142.     ice            = -1;
  1143.     reallevel    = 0;
  1144.     level        = 1;
  1145.     a            = PLAYGAME;
  1146.     clearstats();
  1147.     newlevel(rand() % 4);
  1148.     timing();
  1149. }
  1150.  
  1151. void newhiscores(void)
  1152. {
  1153. PERSIST    TEXT    amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R.J. Mical", "Dave Morse"};
  1154.         SBYTE    iwhich, player, which;
  1155.  
  1156. for (player = lo; player <= hi; player++)
  1157.     for (which = 0; which <= HISCORES; which++)
  1158.         if (worm[player].control != NONE && worm[player].score >= hiscore[which].score)
  1159.         {    // push all worse hiscores down
  1160.  
  1161.             if (which < HISCORES)
  1162.                 for (iwhich = HISCORES; iwhich >= which + 1; iwhich--)
  1163.                 {    hiscore[iwhich].player    = hiscore[iwhich - 1].player;
  1164.                     hiscore[iwhich].score    = hiscore[iwhich - 1].score;
  1165.                     hiscore[iwhich].level    = hiscore[iwhich - 1].level;
  1166.                     hiscore[iwhich].fresh    = hiscore[iwhich - 1].fresh;
  1167.                     strcpy(hiscore[iwhich].name, hiscore[iwhich - 1].name);
  1168.                 }
  1169.  
  1170.             modified = TRUE;
  1171.             hiscore[which].player = player;
  1172.             hiscore[which].score = worm[player].score;
  1173.             hiscore[which].level = worm[player].levelreached;
  1174.             if (worm[player].control == AMIGA)
  1175.             {    strcpy(hiscore[which].name, amiganame[player]);
  1176.                 hiscore[which].fresh = FALSE;
  1177.             } else
  1178.             {    strcpy(hiscore[which].name, "(New)");
  1179.                 hiscore[which].fresh = TRUE;
  1180.             }
  1181.             break;
  1182. }        }
  1183.  
  1184. void newlevel(SBYTE player)
  1185. {    SBYTE    iwhich, which;
  1186.  
  1187.     if (level >= 2 && worm[player].lives)
  1188.         rundown(player);
  1189.     if (a == PLAYGAME)
  1190.     {    if (level > levels)
  1191.         {    for (which = lo; which <= hi; which++)
  1192.                 if (worm[which].lives)
  1193.                     worm[which].levelreached = -1;
  1194.             celebrate();
  1195.             newhiscores();
  1196.             titlescreen();
  1197.         } else
  1198.         {    saylevel(WHITE);
  1199.             for (which = lo; which <= hi; which++)
  1200.                 worm[which].multi = (SBYTE) atleast(worm[which].multi / 2, 1);
  1201.             killall();
  1202.             clearletters();
  1203.             orientworms();
  1204.             changefield();
  1205.             renderboard();
  1206.               dripspeed = (SBYTE) atleast(  DRIPSPEED_MAX - (level /   DRIPSPEED_DIV), VERYFAST);
  1207.               fragspeed = (SBYTE) atleast(  FRAGSPEED_MAX - (level /   FRAGSPEED_DIV), VERYFAST);
  1208.             killerspeed = (SBYTE) atleast(KILLERSPEED_MAX - (level / KILLERSPEED_DIV), VERYFAST);
  1209.                orbspeed = (SBYTE) atleast(   ORBSPEED_MAX - (level /    ORBSPEED_DIV), VERYFAST);
  1210.                dripfreq =         atleast(   DRIPFREQ_MAX - (level *    DRIPFREQ_DEC),   DRIPFREQ_MIN);
  1211.              killerfreq =         atleast( KILLERFREQ_MAX - (level *  KILLERFREQ_DEC), KILLERFREQ_MIN);
  1212.                 orbfreq =         atleast(    ORBFREQ_MAX - (level *     ORBFREQ_DEC),    ORBFREQ_MIN);
  1213.               slimefreq =         atleast(  SLIMEFREQ_MAX - (level *   SLIMEFREQ_DEC),  SLIMEFREQ_MIN);
  1214.                   delay =         atleast(      DELAY_MAX - (level *       DELAY_DEC),      DELAY_MIN);
  1215.  
  1216.             if (level)
  1217.             {    secondsperlevel = SECONDSPERLEVEL;
  1218.                 putletter(-1);
  1219.                 for (which = 0; which <= 3; which++)
  1220.                 {   if (!worm[which].lives && worm[which].control != NONE)
  1221.                     {   // create (or resurrect) a worm
  1222.  
  1223.                         worm[which].lives      = STARTLIVES;
  1224.                         worm[which].score      = 0;
  1225.                         worm[which].alive      = TRUE;
  1226.                         worm[which].oldscore   = 0;
  1227.                         worm[which].armour     = 0;
  1228.                         worm[which].tongue     = 0;
  1229.                         worm[which].nitro      = FALSE;
  1230.                         worm[which].mode       = NULL;
  1231.                         worm[which].power      = 0;
  1232.                         worm[which].bias       = 0;
  1233.                         worm[which].multi      = 1;
  1234.                         worm[which].ice        = 0;
  1235.                         worm[which].victor     = -1;
  1236.                         worm[which].ammo       = 0;
  1237.                         worm[which].affixer    = FALSE;
  1238.                         worm[which].causewait  = (ULONG) -1;
  1239.                         worm[which].last       = FIRSTTAIL + which;
  1240.                         worm[which].pos        = -1;
  1241.                         for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
  1242.                             protector[which][iwhich].alive = FALSE;
  1243.                         for (iwhich = 0; iwhich <= LASTOBJECT; iwhich++)
  1244.                                 stat(which, iwhich);
  1245.     }    }    }    }    }
  1246.     clearjoystick();
  1247.     clearkybd();
  1248.     resettime();
  1249. }
  1250.  
  1251. void orbexplosion(SBYTE which)
  1252. {    SBYTE iwhich;
  1253.  
  1254.     effect(FXEXPLODE);
  1255.     orb[which].alive = FALSE;
  1256.     for (iwhich = 0; iwhich <= 7; iwhich++)
  1257.     {    frag[which][iwhich].alive = TRUE;
  1258.         frag[which][iwhich].x = orb[which].x;
  1259.         frag[which][iwhich].y = orb[which].y;
  1260.         frag[which][iwhich].moved = TRUE;
  1261.         frag[which][iwhich].last = EMPTY;
  1262.         switch (iwhich)
  1263.         {
  1264.         case 0:
  1265.             frag[which][iwhich].deltax = 0;
  1266.             frag[which][iwhich].deltay = -1;
  1267.             break;
  1268.         case 1:
  1269.             frag[which][iwhich].deltax = 1;
  1270.             frag[which][iwhich].deltay = -1;
  1271.             break;
  1272.         case 2:
  1273.             frag[which][iwhich].deltax = 1;
  1274.             frag[which][iwhich].deltay = 0;
  1275.             break;
  1276.         case 3:
  1277.             frag[which][iwhich].deltax = 1;
  1278.             frag[which][iwhich].deltay = 1;
  1279.             break;
  1280.         case 4:
  1281.             frag[which][iwhich].deltax = 0;
  1282.             frag[which][iwhich].deltay = 1;
  1283.             break;
  1284.         case 5:
  1285.             frag[which][iwhich].deltax = -1;
  1286.             frag[which][iwhich].deltay = 1;
  1287.             break;
  1288.         case 6:
  1289.             frag[which][iwhich].deltax = -1;
  1290.             frag[which][iwhich].deltay = 0;
  1291.             break;
  1292.         case 7:
  1293.             frag[which][iwhich].deltax = -1;
  1294.             frag[which][iwhich].deltay = -1;
  1295.             break;
  1296.         default:
  1297.             break;
  1298. }    }    }
  1299.  
  1300. /* NAME     orbloop -- controls orbs
  1301. SYNOPSIS    orbloop(SBYTE);
  1302. FUNCTION    Controls an orb.
  1303. MODULE      engine.c */
  1304.  
  1305. void orbloop(SBYTE which) {
  1306. SBYTE    frontx, fronty, iiwhich, iwhich, player, newdeltax, newdeltay,
  1307.         rearx, reary, thissy, x, xx, y, yy;
  1308.  
  1309. // erase previous image
  1310.  
  1311. if (orb[which].moved)
  1312.     if (field[orb[which].x][orb[which].y] != ORB)
  1313.         orb[which].moved = FALSE;
  1314.     else
  1315.     {    draw(orb[which].x, orb[which].y, orb[which].last);
  1316.         field[orb[which].x][orb[which].y] = orb[which].last;
  1317.     }
  1318. else orb[which].moved = TRUE;
  1319.  
  1320. // bounce/move
  1321.  
  1322. frontx    = xwrap(orb[which].x + orb[which].deltax);    // look in front
  1323. fronty    = ywrap(orb[which].y + orb[which].deltay);
  1324. rearx    = xwrap(orb[which].x - orb[which].deltax);    // look behind
  1325. reary    = ywrap(orb[which].y - orb[which].deltay);
  1326. if (bounceorb(which, frontx, fronty))
  1327. {    bouncekiller(which, frontx, fronty);
  1328.     newdeltax = -orb[which].deltax;    // default bounce angle is 180°
  1329.     newdeltay = -orb[which].deltay;
  1330.     if (!bounceorb(which, frontx, reary))
  1331.     {    if (bounceorb(which, rearx, fronty))
  1332.         {    bouncekiller(which, rearx, fronty);
  1333.             newdeltax = orb[which].deltax;
  1334.     }    }
  1335.     elif (!bounceorb(which, rearx, fronty))
  1336.     {    bouncekiller(which, rearx, fronty);
  1337.         newdeltay = orb[which].deltay;
  1338.     }
  1339.     orb[which].deltax = newdeltax;
  1340.     orb[which].deltay = newdeltay;
  1341. }
  1342. orb[which].x = xwrap(orb[which].x + orb[which].deltax);
  1343. orb[which].y = ywrap(orb[which].y + orb[which].deltay);
  1344. orb[which].last = EMPTY;
  1345.  
  1346. // collision detection
  1347.  
  1348. if (orb[which].alive)
  1349. {    x = orb[which].x;
  1350.     y = orb[which].y;
  1351.     thissy = field[x][y];
  1352.     if (thissy <= LASTOBJECT)
  1353.     {    orbscore(which, object[thissy].score);
  1354.         if (thissy != SLAYER && thissy != BOMB)
  1355.             effect(FXGETOBJECT);
  1356.         if (thissy == AMMO || thissy == SLAYER)
  1357.         {    if (orb[which].mode != ARMOUR)
  1358.                 orb[which].explode = TRUE;
  1359.             else effect(FXUSEARMOUR);
  1360.         } elif (thissy == NITRO || thissy == POWER || thissy == SLOWER)
  1361.         {    effect(FXGETNITRO);
  1362.             orb[which].speed = speedup(orb[which].speed, TRUE);
  1363.         } elif (thissy == HEALER || thissy == LIFE || thissy == ICE || thissy == TREASURE || thissy == UMBRELLA)
  1364.             orbsplit(which);
  1365.         else switch(thissy) {
  1366.         case ARMOUR:
  1367.             orb[which].armour += MODEADD + (rand() % MODERAND);
  1368.             orb[which].mode = ARMOUR;
  1369.             break;
  1370.         case TONGUE:
  1371.             orb[which].tongue += MODEADD + (rand() % MODERAND);
  1372.             orb[which].mode = TONGUE;
  1373.             break;
  1374.         case BOMB:
  1375.             iwhich = whichtimebomb(x, y);
  1376.             timebomb[iwhich].alive = FALSE;
  1377.             draw(x, y, ORB); /* so the user understands what is happening
  1378.             *before* the s-l-o-w bombblast() occurs */
  1379.             bombblast(ORB, which, x, y);
  1380.             break;
  1381.         case PROTECTOR:
  1382.             for (player = lo; player <= hi; player++)
  1383.                 if (worm[player].lives)
  1384.                     for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
  1385.                         if (protector[player][iwhich].alive)
  1386.                         {    protector[player][iwhich].alive = FALSE;    
  1387.                             if (protector[player][iwhich].visible)
  1388.                             {    draw(protector[player][iwhich].x, protector[player][iwhich].y, EMPTY);
  1389.                                 field[protector[player][iwhich].x][protector[player][iwhich].y] = EMPTY;
  1390.                         }    }
  1391.             break;
  1392.         case MISSILE:
  1393.             for (player = lo; player <= hi; player++)
  1394.                 if (missile[player].alive)
  1395.                 {    missile[player].alive = FALSE;
  1396.                     draw(missile[player].x, missile[player].y, EMPTY);
  1397.                     field[missile[player].x][missile[player].y] = EMPTY;
  1398.                 }
  1399.             break;
  1400.         case MULTIPLIER:
  1401.             orb[which].multi *= 2;
  1402.             if (orb[which].multi > MULTILIMIT)
  1403.                 orb[which].multi = MULTILIMIT;
  1404.             break;
  1405.         case BIAS:
  1406.             for (player = lo; player <= hi; player++)
  1407.                    if (worm[player].lives && worm[player].bias)
  1408.                 {    worm[player].bias = 0;
  1409.                     stat(player, BIAS);
  1410.                 }
  1411.             break;
  1412.         case AFFIXER:
  1413.             for (player = lo; player <= hi; player++)
  1414.                 if (worm[player].lives)
  1415.                     worm[player].affixer = FALSE;
  1416.             break;
  1417.         case SWITCHER:
  1418.             for (x = 0; x <= FIELDX; x++)
  1419.                 for (y = 0; y <= FIELDY; y++)
  1420.                     if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  1421.                     {   field[x][y] = WOOD;
  1422.                         draw(x, y, WOOD);
  1423.                     }
  1424.             break;
  1425.         case GROWER:
  1426.             effect(FXGETGROWER);
  1427.             for (x = 0; x <= FIELDX; x++)
  1428.                 for (y = 0; y <= FIELDY; y++)
  1429.                     if (field[x][y] == WOOD)
  1430.                         for (xx = x - 1; xx <= x + 1; xx++)
  1431.                             for (yy = y - 1; yy <= y + 1; yy++)
  1432.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY)
  1433.                                     field[xx][yy] = TEMPWOOD;
  1434.             for (x = 0; x <= FIELDX; x++)
  1435.                 for (y = 0; y <= FIELDY; y++)
  1436.                     if (field[x][y] == TEMPWOOD)
  1437.                     {    field[x][y] = WOOD;
  1438.                         draw(x, y, WOOD);
  1439.                     }
  1440.             break;
  1441.         case CLOCK:
  1442.             secondsperlevel -= rand() % CLOCKRAND;
  1443.             break;
  1444.         default:
  1445.             break;
  1446.     }   }
  1447.     elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  1448.     {   effect(FXUSEPROTECTOR);
  1449.         effect(FXORBDEATH);
  1450.         orb[which].alive = FALSE;
  1451.         wormscore(thissy - FIRSTPROTECTOR, orb[which].score);
  1452.         if (worm[thissy - FIRSTPROTECTOR].bias)
  1453.         {   worm[thissy - FIRSTPROTECTOR].lives += ORBBLOOD;
  1454.             stat(thissy - FIRSTPROTECTOR, LIFE);
  1455.     }   }
  1456.     elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  1457.     {   if (orb[which].mode == TONGUE)
  1458.            effect(FXUSETONGUE);
  1459.         else
  1460.         {   if (worm[thissy - FIRSTTAIL].alive)
  1461.             {   effect(FXORBDEATH);
  1462.                 wormscore(thissy - FIRSTTAIL, orb[which].score);
  1463.                 if (worm[thissy - FIRSTTAIL].bias)
  1464.                 {   worm[thissy - FIRSTTAIL].lives += ORBBLOOD;
  1465.                     stat(thissy - FIRSTTAIL, LIFE);
  1466.             }   }
  1467.             orb[which].alive = FALSE;
  1468.             field[x][y] = BONUS;
  1469.             draw(x, y, BONUS);
  1470.     }   }
  1471.     elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  1472.     {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  1473.         {    worm[thissy - FIRSTHEAD].cause = ORB;
  1474.             worm[thissy - FIRSTHEAD].victor = -1;
  1475.             worm[thissy - FIRSTHEAD].alive = FALSE;
  1476.             if (orb[which].mode == ARMOUR)
  1477.             {    effect(FXUSEARMOUR);
  1478.                 orbscore(which, KILLWORM);
  1479.             } else
  1480.             {   effect(FXORBDEATH);
  1481.                 orb[which].alive = FALSE;
  1482.                 wormscore(thissy - FIRSTHEAD, orb[which].score);
  1483.                 if (worm[thissy - FIRSTHEAD].bias)
  1484.                 {   worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
  1485.                     stat(thissy - FIRSTHEAD, LIFE);
  1486.         }   }   }
  1487.         else
  1488.         {    effect(FXUSEARMOUR);
  1489.             effect(FXORBDEATH);
  1490.             orb[which].alive = FALSE;
  1491.             wormscore(thissy - FIRSTHEAD, orb[which].score);
  1492.             if (worm[thissy - FIRSTHEAD].bias)
  1493.             {   worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
  1494.                 stat(thissy - FIRSTHEAD, LIFE);
  1495.         }   }
  1496.         orb[which].last = thissy - FIRSTHEAD + FIRSTTAIL; // note sign issues
  1497.     } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  1498.     {    iwhich = whichdrip(x, y);
  1499.         drip[iwhich].alive = FALSE;
  1500.         if (orb[which].mode != ARMOUR)
  1501.         {    orb[which].explode = TRUE;
  1502.             draw(x, y, EMPTY);
  1503.     }    }
  1504.     elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  1505.     {    for (player = lo; player <= hi; player++)
  1506.         {    letters[player][thissy - FIRSTLETTER] = FALSE;
  1507.             drawletter(player, thissy, BLACK);
  1508.         }
  1509.         putletter(-1);
  1510.     } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  1511.     {    missile[thissy - FIRSTMISSILE].alive = FALSE;
  1512.         if (orb[which].mode != ARMOUR)
  1513.         {   effect(FXORBDEATH);
  1514.             wormscore(thissy - FIRSTMISSILE, orb[which].score);
  1515.             if (worm[thissy - FIRSTMISSILE].bias)
  1516.             {   worm[thissy - FIRSTMISSILE].lives += ORBBLOOD;
  1517.                 stat(thissy - FIRSTMISSILE, LIFE);
  1518.             }
  1519.             orb[which].alive = FALSE;
  1520.             draw(x, y, BONUS);
  1521.             field[x][y] = BONUS;
  1522.         } else effect(FXUSEARMOUR);
  1523.     } else switch (thissy) {
  1524.     case EMPTY:
  1525.         orbscore(which, EMPTYPOINT);
  1526.         break;
  1527.     case SILVER:
  1528.         orbscore(which, SILVERPOINT);
  1529.         break;
  1530.     case GOLD:
  1531.         orbscore(which, GOLDPOINT);
  1532.         break;
  1533.     case TELEPORT:
  1534.         iwhich = whichteleport(x, y);
  1535.         if (blocked(iwhich, orb[which].deltax, orb[which].deltay))
  1536.             orb[which].alive = FALSE;
  1537.         else
  1538.         {   effect(FXUSETELEPORT);
  1539.             orbscore(which, TELPOINT);
  1540.             orb[which].x = xwrap(teleport[level][partner(iwhich)].x + orb[which].deltax);
  1541.             orb[which].y = ywrap(teleport[level][partner(iwhich)].y + orb[which].deltay);
  1542.         }
  1543.         break;
  1544.     case ORB:
  1545.         for (iwhich = 0; iwhich <= ORBS; iwhich++)
  1546.             if (iwhich != which && orb[iwhich].alive && x == orb[iwhich].x && y == orb[iwhich].y)
  1547.             {   effect(FXORBDEATH);
  1548.                 if (orb[iwhich].mode != ARMOUR)
  1549.                 {    orb[iwhich].alive = FALSE;
  1550.                     if (orb[which].mode != ARMOUR)
  1551.                         orb[which].alive = FALSE;
  1552.                     else effect(FXUSEARMOUR);
  1553.                 } else
  1554.                 {   orb[which].alive = FALSE;
  1555.                     if (orb[which].mode == ARMOUR)
  1556.                         orb[iwhich].alive = FALSE;
  1557.                     else effect(FXUSEARMOUR);
  1558.                 }
  1559.                 if (orb[which].alive && !orb[iwhich].alive)
  1560.                     orbscore(which, orb[iwhich].score);
  1561.                 elif (!orb[which].alive && orb[iwhich].alive)
  1562.                     orbscore(iwhich, orb[which].score);
  1563.                 elif (!orb[which].alive && !orb[iwhich].alive)
  1564.                 {    draw(x, y, BONUS);
  1565.                     field[x][y] = BONUS;
  1566.             }    }
  1567.         break;
  1568.     case FRAGMENT:
  1569.         whichfrag(x, y, &iwhich, &iiwhich);
  1570.         frag[iwhich][iiwhich].alive = FALSE;
  1571.         if (orb[which].mode != ARMOUR)
  1572.             orb[which].explode = TRUE;
  1573.         else effect(FXUSEARMOUR);
  1574.         break;
  1575.     case SKULL:
  1576.         effect(FXGETSKULL);
  1577.         orbscore(which, SKULLPOINT);
  1578.         break;
  1579.     case SLIME:
  1580.         if (orb[which].mode != TONGUE)
  1581.             orb[which].alive = FALSE;
  1582.         break;
  1583.     default:
  1584.         break;
  1585. }    }
  1586.  
  1587. // update field
  1588.  
  1589. if (orb[which].alive)
  1590. {    if (orb[which].mode == TONGUE)
  1591.         draw(orb[which].x, orb[which].y, ORBTONGUE);
  1592.     elif (orb[which].mode == ARMOUR)
  1593.         draw(orb[which].x, orb[which].y, ORBARMOUR);
  1594.     else
  1595.         draw(orb[which].x, orb[which].y, ORB);
  1596.     field[orb[which].x][orb[which].y] = ORB;
  1597. }
  1598. }
  1599.  
  1600. void orbsplit(SBYTE which)
  1601. {    ABOOL    available;
  1602.     SBYTE    copy = 0, iwhich, iiwhich;
  1603.  
  1604.     effect(FXORBSPLIT);
  1605.     for (iwhich = 0; iwhich <= ORBS; iwhich++)
  1606.     {    available = TRUE;
  1607.         for (iiwhich = 0; iiwhich <= 7; iiwhich++)
  1608.             if (frag[iwhich][iiwhich].alive)
  1609.                 available = FALSE;
  1610.         if (!orb[iwhich].alive && copy <= 3 && available)
  1611.         {    orb[iwhich].x        = orb[which].x;
  1612.             orb[iwhich].y        = orb[which].y;
  1613.             orb[iwhich].score    = orb[which].score;
  1614.             orb[iwhich].armour    = orb[which].armour;
  1615.             orb[iwhich].tongue    = orb[which].tongue;
  1616.             orb[iwhich].mode    = orb[which].mode;
  1617.             orb[iwhich].speed    = orb[which].speed;
  1618.             orb[iwhich].explode    = FALSE;
  1619.             orb[iwhich].multi    = orb[which].multi;
  1620.             orb[iwhich].moved    = FALSE;
  1621.             switch (copy)
  1622.             {
  1623.             case 0:
  1624.                 if (orb[which].deltax != -1 || orb[which].deltay != -1)
  1625.                 {    orb[iwhich].deltax = -1;
  1626.                     orb[iwhich].deltay = -1;
  1627.                     orb[iwhich].alive = TRUE;
  1628.                 }
  1629.                 break;
  1630.             case 1:
  1631.                 if (orb[which].deltax != 1 || orb[which].deltay != 1)
  1632.                 {    orb[iwhich].deltax = 1;
  1633.                     orb[iwhich].deltay = 1;
  1634.                     orb[iwhich].alive = TRUE;
  1635.                 }
  1636.                 break;
  1637.             case 2:
  1638.                 if (orb[which].deltax != 1 || orb[which].deltay != -1)
  1639.                 {    orb[iwhich].deltax = 1;
  1640.                     orb[iwhich].deltay = -1;
  1641.                     orb[iwhich].alive = TRUE;
  1642.                 }
  1643.                 break;
  1644.             case 3:
  1645.                 if (orb[which].deltax != -1 || orb[which].deltay != 1)
  1646.                 {    orb[iwhich].deltax = -1;
  1647.                     orb[iwhich].deltay = 1;
  1648.                     orb[iwhich].alive = TRUE;
  1649.                 }
  1650.                 break;
  1651.             default:
  1652.                 break;
  1653.             }
  1654.             copy++;
  1655. }    }    }
  1656.  
  1657. void orientworms(void)
  1658. {    SBYTE    player;
  1659.  
  1660.     for (player = lo; player <= hi; player++)
  1661.     {    worm[player].speed = NORMAL;
  1662.         if (worm[player].lives)
  1663.             stat(player, NITRO);
  1664.         worm[player].moved = FALSE;
  1665.         worm[player].x = startx[level];
  1666.         worm[player].y = starty[level];
  1667.         switch (player)
  1668.         {
  1669.         case 0:
  1670.             worm[0].deltax = -1;
  1671.             worm[0].deltay = 0;
  1672.             break;
  1673.         case 1:
  1674.             worm[1].deltax = 1;
  1675.             worm[1].deltay = 0;
  1676.             break;
  1677.         case 2:
  1678.             worm[2].deltax = 0;
  1679.             worm[2].deltay = -1;
  1680.             break;
  1681.         case 3:
  1682.             worm[3].deltax = 0;
  1683.             worm[3].deltay = 1;
  1684.             break;
  1685.         default:
  1686.             break;
  1687. }   }   }
  1688.  
  1689. SBYTE partner(SBYTE which)
  1690. {    if (which % 2 == 0)
  1691.         return((SBYTE) (which + 1));
  1692.     else return((SBYTE) (which - 1));
  1693. }
  1694.  
  1695. /* NAME        putletter -- Put a letter onto the field
  1696. SYNOPSIS    void putletter(SBYTE player);
  1697. INPUTS        SBYTE player -
  1698.             0-3: player on whose behalf the letter is put on for
  1699.             -1: any letter
  1700. RESULT        none
  1701. NOTES        noletter -
  1702.             -2: if we found somewhere to put the letter
  1703.             player: if we didn't */
  1704.  
  1705. void putletter(SBYTE player)
  1706. {    SBYTE    count = 0, letter;
  1707.     SBYTE    i, x, y;
  1708.  
  1709.     do
  1710.     {    x = rand() % (FIELDX + 1);
  1711.         y = rand() % (FIELDY + 1);
  1712.     } while ((field[x][y] < FIRSTEMPTY || field[x][y] > LASTEMPTY) && (++count < PATIENCE));
  1713.     if (count < PATIENCE)
  1714.     {    noletter = -2;
  1715.         if (player != -1)
  1716.         {    for (i = 0; i <= LETTERS; i++)
  1717.                 if (!(letters[player][i]))
  1718.                 {    break;
  1719.                 }
  1720.             if (i > LETTERS)
  1721.                 letter = rand() % (LETTERS + 1);
  1722.             else
  1723.             {    do
  1724.                     letter = rand() % (LETTERS + 1);
  1725.                 while (letters[player][letter]);
  1726.             }
  1727.         } else
  1728.             letter = rand() % (LETTERS + 1);
  1729.         field[x][y] = letter + FIRSTLETTER;
  1730.         draw(x, y, letter + FIRSTLETTER);
  1731.     } else noletter = player;
  1732. }
  1733.  
  1734. /* NAME     queue -- adds a keystroke to the key queue
  1735. SYNOPSIS    name(SBYTE, SBYTE, SBYTE);
  1736. FUNCTION    Adds a keystroke to the in-game key queue.
  1737. INPUTS      player - player that pressed the key
  1738.             deltax - the deltax of the key
  1739.             deltay - the deltay of the key
  1740. IMPLEMENTATION
  1741.             thequeue[] is an array, with QUEUELIMIT as its last index.
  1742.             It is implemented as a FIFO stack rather than LIFO so that
  1743.             the keystrokes are processed in the correct order (that is,
  1744.             the order in which they were pressed). The oldest keystroke
  1745.             is always at index [0], the next oldest at [1], and so on
  1746.             upwards to the newest keystroke, at [worm[player].pos].
  1747.             Keystrokes are removed from the bottom of the array ([0]),
  1748.             and the rest of the array is shuffled down to fill the gap,
  1749.             so that the contents of [1] go to [0], the contents of [2]
  1750.             go to [1], etc. worm[player].pos is adjusted to always point
  1751.             to the newest entry, which is the 'end' of the queue.
  1752. MODULE      engine.c */
  1753.  
  1754. void queue(SBYTE player, SBYTE deltax, SBYTE deltay)
  1755. {   if (worm[player].pos < QUEUELIMIT)
  1756.     {    worm[player].pos++;
  1757.         thequeue[player][worm[player].pos].deltax = deltax;
  1758.         thequeue[player][worm[player].pos].deltay = deltay;
  1759. }    }
  1760.  
  1761. void reflect(SBYTE which, SBYTE iwhich)
  1762. {    frag[which][iwhich].deltax     = -frag[which][iwhich].deltax;
  1763.     frag[which][iwhich].deltay     = -frag[which][iwhich].deltay;
  1764.     frag[which][iwhich].x        +=  frag[which][iwhich].deltax * 2;
  1765.     frag[which][iwhich].y        +=  frag[which][iwhich].deltay * 2;
  1766. }
  1767.  
  1768. void renderboard(void)
  1769. {    SBYTE x, y;
  1770.  
  1771.     switch(rand() % 3) {
  1772.     case 0:
  1773.         // chequered
  1774.         for (y = 0; y <= FIELDY; y += 2)
  1775.             for (x = 0; x <= FIELDX; x += 2)
  1776.                 draw(x, y, board[level][x][y]);
  1777.         for (x = 1; x <= FIELDX; x += 2)
  1778.             for (y = 1; y <= FIELDY; y += 2)
  1779.                 draw(x, y, board[level][x][y]);
  1780.         for (y = 0; y <= FIELDY; y += 2)
  1781.             for (x = 1; x <= FIELDX; x += 2)
  1782.                 draw(x, y, board[level][x][y]);
  1783.         for (x = 0; x <= FIELDX; x += 2)
  1784.             for (y = 1; y <= FIELDY; y += 2)
  1785.                 draw(x, y, board[level][x][y]);
  1786.         break;
  1787.     case 1:
  1788.         // `closing sliding doors'
  1789.         for (x = 0; x <= FIELDX / 2; x++)
  1790.             for (y = 0; y <= FIELDY; y++)
  1791.             {    draw(x, y, board[level][x][y]);
  1792.                 draw(FIELDX - x, y, board[level][FIELDX - x][y]);
  1793.             }
  1794.         break;
  1795.     case 2:
  1796.         // `opening sliding doors'
  1797.         for (x = FIELDX / 2; x >= 0; x--)
  1798.             for (y = 0; y <= FIELDY; y++)
  1799.             {    draw(x, y, board[level][x][y]);
  1800.                 draw(FIELDX - x, y, board[level][FIELDX - x][y]);
  1801.             }
  1802.         break;
  1803.     default:
  1804.         break;
  1805.     }
  1806.  
  1807.     if (a == FIELDEDIT)
  1808.     {    draw(startx[level], starty[level], START);
  1809.         if (teleport[level][0].alive)
  1810.         {    draw(teleport[level][0].x, teleport[level][0].y, ONE);
  1811.             draw(teleport[level][1].x, teleport[level][1].y, TWO);
  1812. }    }    }
  1813.  
  1814. ABOOL savefields(STRPTR fieldname)
  1815. {    SBYTE    i, j;
  1816.     TEXT    IOBuffer[NAMELENGTH + 1];
  1817.  
  1818.     matchteleports();
  1819.  
  1820.     if (!ZOpen(fieldname, TRUE))
  1821.         return FALSE;
  1822.  
  1823.     // write header
  1824.  
  1825.     strcpy(IOBuffer,                    "FSET 4.4");
  1826.     IOBuffer[9]                            = levels;
  1827.     if (!ZWrite(IOBuffer, 10))
  1828.     {   ZClose();
  1829.         return FALSE;
  1830.     }
  1831.  
  1832.     // write high score table
  1833.  
  1834.     for (i = 0; i <= HISCORES; i++)
  1835.     {    IOBuffer[0]                        =  hiscore[i].player;
  1836.         IOBuffer[1]                        =  hiscore[i].level;
  1837.         IOBuffer[2]                        =  0;
  1838.         IOBuffer[3]                        =  hiscore[i].score / 65536;
  1839.         IOBuffer[4]                        = (hiscore[i].score % 65536) / 256;
  1840.         IOBuffer[5]                        = (hiscore[i].score % 65536) % 256;
  1841.         if (!ZWrite(IOBuffer, 6))
  1842.         {   ZClose();
  1843.             return FALSE;
  1844.         }
  1845.  
  1846.         for (j = 0; j <= NAMELENGTH; j++)
  1847.             IOBuffer[j]                    = hiscore[i].name[j];
  1848.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  1849.         {   ZClose();
  1850.             return FALSE;
  1851.     }    }
  1852.  
  1853.     // write level data
  1854.  
  1855.     for (i = 0; i <= levels; i++)
  1856.     {   IOBuffer[0]                        = startx[i];
  1857.         IOBuffer[1]                        = starty[i];
  1858.         IOBuffer[2]                        = teleport[i][0].alive;
  1859.         IOBuffer[3]                        = teleport[i][0].x;
  1860.         IOBuffer[4]                        = teleport[i][0].y;
  1861.         IOBuffer[5]                        = teleport[i][1].alive;
  1862.         IOBuffer[6]                        = teleport[i][1].x;
  1863.         IOBuffer[7]                        = teleport[i][1].y;
  1864.         if (!ZWrite(IOBuffer, 8))
  1865.         {   ZClose();
  1866.             return FALSE;
  1867.         }
  1868.  
  1869.         if (!ZWrite((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
  1870.         {   ZClose();
  1871.             return FALSE;
  1872.     }    }
  1873.  
  1874.     // write version string
  1875.  
  1876.     if (!ZWrite(VERSION, strlen(VERSION)))
  1877.     {   ZClose();
  1878.         return FALSE;
  1879.     }
  1880.  
  1881.     ZClose();
  1882.  
  1883.     if (clearthem)
  1884.         clearhiscores();
  1885.     modified = FALSE;
  1886.     return TRUE;
  1887. }
  1888.  
  1889. void saylevel(COLOUR colour)
  1890. {    TEXT mainstring[15] = "Level ", tempstring[4];
  1891.  
  1892.     if (level > 0)
  1893.     {    stci_d(&mainstring[6], level);
  1894.         strcat((char*) mainstring, " of ");
  1895.         stci_d(tempstring, levels);
  1896.         strcat((char*) mainstring, (char*) tempstring);
  1897.         say(mainstring, colour);
  1898.     } else say((STRPTR) "Treasury", colour);
  1899. }
  1900.  
  1901. void setbrush(SBYTE newbrush)
  1902. {    brush = newbrush;
  1903.     setpointer(brush);
  1904.     underline(brush);
  1905. }
  1906.  
  1907. SBYTE slowdown(SBYTE speed)
  1908. {    speed *= 2;
  1909.     if (speed > SLOW)
  1910.         speed = SLOW;
  1911.     return(speed);
  1912. }
  1913.  
  1914. /* NAME     slowloop -- things done rarely
  1915. SYNOPSIS    slowloop(void);
  1916. FUNCTION    Decrements strength; creates killers, orbs, objects,
  1917.             teleports, slime; controls timebombs; puts letters if
  1918.             neccessary; blanks out old causes.
  1919. MODULE      engine.c */
  1920.  
  1921. void slowloop(void)
  1922. {        ABOOL    available, done;
  1923.         SBYTE    i, iwhich, player, which, x, xx, y, yy;
  1924. PERSIST    SBYTE    type = FIRSTDRIP;
  1925.  
  1926. // decrement strength
  1927.  
  1928. for (player = lo; player <= hi; player++)
  1929.     if (worm[player].lives > 0 && ice == -1 || ice == player)
  1930.     {    if (worm[player].bias > 0)
  1931.         {    worm[player].bias--;
  1932.             stat(player, BIAS);
  1933.         }
  1934.         if (worm[player].ice > 0 && --worm[player].ice == 0)
  1935.         {    for (which = lo; which <= hi; which++)
  1936.                 if (player != which)
  1937.                     worm[player].pos = -1;
  1938.             ice = -1;
  1939.         }
  1940.         if (worm[player].mode == ARMOUR)
  1941.         {    if (--worm[player].armour == 0)
  1942.             {    if (worm[player].tongue > 0)
  1943.                     worm[player].mode = TONGUE;
  1944.                 else worm[player].mode = NULL;
  1945.             }
  1946.             stat(player, ARMOUR);
  1947.         } elif (worm[player].mode == TONGUE)
  1948.         {    if (--worm[player].tongue == 0)
  1949.             {    if (worm[player].armour > 0)
  1950.                     worm[player].mode = ARMOUR;
  1951.                 else worm[player].mode = NULL;
  1952.             }
  1953.             stat(player, TONGUE);
  1954.     }    }
  1955.  
  1956. if (ice == -1)
  1957. {    for (which = 0; which <= ORBS; which++)
  1958.         if (orb[which].alive)
  1959.             if (orb[which].mode == ARMOUR)
  1960.             {    if (--orb[which].armour == 0)
  1961.                     if (orb[which].tongue > 0)
  1962.                         orb[which].mode = TONGUE;
  1963.                     else orb[which].mode = NULL;
  1964.             } elif (orb[which].mode == TONGUE)
  1965.             {    if (--orb[which].tongue == 0)
  1966.                     if (orb[which].armour > 0)
  1967.                         orb[which].mode = ARMOUR;
  1968.                     else orb[which].mode = NULL;
  1969.             }
  1970.  
  1971.     // create killers
  1972.  
  1973.     for (which = 0; which <= KILLERS; which++)
  1974.         if (!killer[which].alive && !(rand() % killerfreq) && findempty(&x, &y, FIRSTKILLER, LASTKILLER) && field[x][y] != KILLER)
  1975.         {    effect(FXKILLERBORN);
  1976.             killer[which].x = x;
  1977.             killer[which].y = y;
  1978.             killer[which].alive = TRUE;
  1979.             killer[which].last = field[killer[which].x][killer[which].y];
  1980.             field[killer[which].x][killer[which].y] = KILLER;
  1981.             draw(killer[which].x, killer[which].y, KILLER);
  1982.         }
  1983.  
  1984.     // create orbs
  1985.  
  1986.     for (which = 0; which <= ORBS; which++)
  1987.         if (!orb[which].alive && !(rand() % orbfreq))
  1988.         {    orb[which].x = rand() % (FIELDX + 1);
  1989.             orb[which].y = rand() % (FIELDY + 1);
  1990.             available = TRUE;
  1991.             for (iwhich = 0; iwhich <= 7; iwhich++)
  1992.                 if (frag[which][iwhich].alive)
  1993.                     available = FALSE;
  1994.             if (available && field[orb[which].x][orb[which].y] >= FIRSTEMPTY && field[orb[which].x][orb[which].y] <= LASTEMPTY)
  1995.             {    orb[which].deltax = (rand() % 2) * 2 - 1;
  1996.                 orb[which].deltay = (rand() % 2) * 2 - 1;
  1997.                 if (field[orb[which].x + orb[which].deltay][orb[which].y + orb[which].deltay] >= FIRSTEMPTY && field[orb[which].x + orb[which].deltax][orb[which].y + orb[which].deltay] <= LASTEMPTY)
  1998.                 {    effect(FXORBBORN);
  1999.                     orb[which].score = 0;
  2000.                     orb[which].alive = TRUE;
  2001.                     orb[which].armour = 0;
  2002.                     orb[which].tongue = 0;
  2003.                     orb[which].mode = NULL;
  2004.                     orb[which].speed = orbspeed;
  2005.                     orb[which].explode = FALSE;
  2006.                     orb[which].multi = 1;
  2007.                     orb[which].moved = FALSE;
  2008.         }    }    }
  2009.  
  2010.     // create drips
  2011.  
  2012.     for (which = 0; which <= DRIPS; which++)
  2013.         if (!drip[which].alive && !(rand() % dripfreq))
  2014.         {    drip[which].x = rand() % (FIELDX + 1);
  2015.             drip[which].y = rand() % 3;
  2016.             if (field[drip[which].x][drip[which].y] >= FIRSTEMPTY && field[drip[which].x][drip[which].y] <= LASTEMPTY
  2017.             && field[drip[which].x][drip[which].y + 1] >= FIRSTEMPTY && field[drip[which].x][drip[which].y + 1] <= LASTEMPTY)
  2018.             {    effect(FXDRIPBORN);
  2019.                 drip[which].alive = TRUE;
  2020.                 drip[which].moved = FALSE;
  2021.                 drip[which].type = type;
  2022.                 if (++type > LASTDRIP)
  2023.                     type = FIRSTDRIP;
  2024.         }    }
  2025.  
  2026.     // create objects
  2027.  
  2028.     for (which = 0; which <= LASTOBJECT; which++)
  2029.         if (!(rand() % object[which].frequency) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2030.         {    field[x][y] = which;
  2031.             draw(x, y, which);
  2032.         }
  2033.  
  2034.     // create teleports
  2035.  
  2036.     if (!(rand() % TELFREQ)
  2037.     && !teleport[level][2].alive
  2038.     && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FIRSTEMPTY, LASTEMPTY)
  2039.     && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FIRSTEMPTY, LASTEMPTY)
  2040.     && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
  2041.     {    teleport[level][2].alive = TRUE;
  2042.         field[teleport[level][2].x][teleport[level][2].y] = TELEPORT;
  2043.         draw(teleport[level][2].x, teleport[level][2].y, TELEPORT);
  2044.         teleport[level][3].alive = TRUE;
  2045.         field[teleport[level][3].x][teleport[level][3].y] = TELEPORT;
  2046.         draw(teleport[level][3].x, teleport[level][3].y, TELEPORT);
  2047.     }
  2048.  
  2049.     // create timebombs
  2050.  
  2051.     for (i = 0; i <= level; i++)
  2052.     {    x = rand() % (FIELDX + 1);
  2053.         y = rand() % (FIELDY + 1);
  2054.         if (field[x][y] == BOMB)
  2055.         {    done = FALSE;
  2056.             for (which = 0; which <= TIMEBOMBS; which++)
  2057.                 if (timebomb[which].alive == FALSE && !done)
  2058.                 {    timebomb[which].alive = TRUE;
  2059.                     timebomb[which].x = x;
  2060.                     timebomb[which].y = y;
  2061.                     timebomb[which].time = 10;
  2062.                     done = TRUE;
  2063.     }    }        }
  2064.  
  2065.     // decrement and explode timebombs
  2066.  
  2067.     if (!(r % (VERYSLOW * TIMEBOMBSPEED)))
  2068.         for (which = 0; which <= TIMEBOMBS; which++)
  2069.             if (timebomb[which].alive)
  2070.             {    if (field[timebomb[which].x][timebomb[which].y] != BOMB)
  2071.                     timebomb[which].alive = FALSE;
  2072.                 else
  2073.                 {    effect(FXTIMEBOMBTICK);
  2074.                     timebomb[which].time--;
  2075.                     if (timebomb[which].time < 0)
  2076.                     {    timebomb[which].alive = FALSE;
  2077.                         field[timebomb[which].x][timebomb[which].y] = EMPTY;
  2078.                         draw(timebomb[which].x, timebomb[which].y, EMPTY);
  2079.                         bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
  2080.                     } else draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
  2081.             }    }
  2082.  
  2083.     // create slime
  2084.     
  2085.     if (!(rand() % slimefreq))
  2086.     {    if (findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2087.         {    field[x][y] = SLIME;
  2088.             draw(x, y, SLIME);
  2089.     }    }
  2090.  
  2091.     // grow slime
  2092.  
  2093.     if (!(rand() % slimefreq))
  2094.     {    for (x = 0; x <= FIELDX; x++)
  2095.             for (y = 0; y <= FIELDY; y++)
  2096.                 if (field[x][y] == SLIME)
  2097.                     for (xx = x - 1; xx <= x + 1; xx++)
  2098.                         for (yy = y - 1; yy <= y + 1; yy++)
  2099.                             if (valid(xx, yy) && field[xx][yy] == EMPTY && !(rand() % 2))
  2100.                                 field[xx][yy] = TEMPSLIME;
  2101.         for (x = 0; x <= FIELDX; x++)
  2102.             for (y = 0; y <= FIELDY; y++)
  2103.                 if (field[x][y] == TEMPSLIME)
  2104.                 {    field[x][y] = SLIME;
  2105.                     draw(x, y, SLIME);
  2106.     }            }
  2107.             
  2108.     // retry putting letters if necessary
  2109.  
  2110.     if (noletter != -2)
  2111.         putletter(noletter);
  2112. }
  2113.  
  2114. // blank out old causes
  2115.  
  2116. for (player = lo; player <= hi; player++)
  2117. {    if (worm[player].lives > 0 && r > worm[player].causewait)
  2118.     {    drawcause(player, BLACK);
  2119.         worm[player].causewait = (ULONG) -1; // most future time possible
  2120. }    }
  2121. }
  2122.  
  2123. SBYTE speedup(SBYTE speed, ABOOL nitro)
  2124. {    speed /= 2;
  2125.     if (speed < FAST)
  2126.         speed = FAST;
  2127.     return(speed);
  2128. }
  2129.  
  2130. LONG squareblast(SBYTE type, SBYTE player, SBYTE thissy, SBYTE x, SBYTE y)
  2131. {    SBYTE    iwhich, which;
  2132.     LONG    score = 0L;
  2133.     SBYTE    filler;
  2134.  
  2135.     if (type == HEAD && worm[player].bias)
  2136.         filler = SILVER;
  2137.     else filler = EMPTY;
  2138.  
  2139.     if (thissy <= LASTOBJECT)
  2140.     {    field[x][y] = filler;
  2141.         draw(x, y, filler);
  2142.         if (thissy == BOMB)
  2143.             for (which = 0; which <= TIMEBOMBS; which++)
  2144.                 if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
  2145.                     timebomb[which].alive = FALSE;
  2146.     } elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2147.     {    draw(x, y, filler);
  2148.         field[x][y] = filler;
  2149.     } elif (thissy == ORB)
  2150.     {    which = whichorb(x, y);
  2151.         if (orb[which].mode != ARMOUR)
  2152.         {   effect(FXORBDEATH);
  2153.             orb[which].alive = FALSE;
  2154.             score = orb[which].score;
  2155.             if (type == HEAD && worm[player].bias)
  2156.                  worm[player].lives += ORBBLOOD;
  2157.             draw(x, y, BONUS);
  2158.             field[x][y] = BONUS;
  2159.         } else effect(FXUSEARMOUR);
  2160.     } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2161.     {    which = whichdrip(x, y);
  2162.         drip[which].alive = FALSE;
  2163.         draw(x, y, filler);
  2164.         field[x][y] = filler;
  2165.     } elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2166.     {    if (type != HEAD || player != thissy - FIRSTHEAD)
  2167.             if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2168.             {    worm[thissy - FIRSTHEAD].cause = BOMB;
  2169.                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2170.                 stat(thissy - FIRSTHEAD, LIFE);
  2171.                 if (type == HEAD)
  2172.                     worm[thissy - FIRSTHEAD].victor = player;
  2173.                 else
  2174.                 {    worm[thissy - FIRSTHEAD].victor = -1;
  2175.                     score = KILLWORM; // worms will get thissy bonus from death(), so it is not given for them here.
  2176.                 }
  2177.             } else effect(FXUSEARMOUR);
  2178.     } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2179.     {    if (type != HEAD || player != thissy - FIRSTMISSILE)
  2180.         {   missile[thissy - FIRSTMISSILE].alive = FALSE;
  2181.             draw(x, y, filler);
  2182.             field[x][y] = filler;
  2183.     }    }
  2184.     elif (thissy == FRAGMENT)
  2185.     {    whichfrag(x, y, &which, &iwhich);
  2186.         frag[which][iwhich].alive = FALSE;
  2187.         draw(x, y, filler);
  2188.         field[x][y] = filler;
  2189.     } elif (thissy == KILLER)
  2190.     {    which = whichkiller(x, y);
  2191.         killer[which].alive = FALSE;
  2192.         draw(x, y, BONUS);
  2193.         field[x][y] = BONUS;
  2194.     }
  2195.     return(score);
  2196. }
  2197.  
  2198. void timeloop(void)
  2199. {            TEXT    timedisplay[5] = {"#:##"};
  2200.     PERSIST    ABOOL    outoftime        = FALSE;
  2201.  
  2202.     secondsleft = atleast(secondsleft, 0);
  2203.     timedisplay[0] = 48 +  (secondsleft / 60);
  2204.     timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  2205.     timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  2206.  
  2207.     if (!level)
  2208.     {    say(timedisplay, worm[treasurer].colour);
  2209.         if (!secondsleft)
  2210.         {    level = reallevel + 1;
  2211.             secondsleft = SECONDSPERLEVEL;
  2212.             newlevel(treasurer);
  2213.     }    }
  2214.     elif (!secondsleft)
  2215.     {    say("Out of time!", WHITE);
  2216.         if (!outoftime)
  2217.         {    effect(FXTIMEALERT);
  2218.             outoftime = TRUE;
  2219.               dripspeed    = speedup(dripspeed,      TRUE);
  2220.               fragspeed    = speedup(fragspeed,      TRUE);
  2221.                orbspeed    = speedup(orbspeed,          TRUE);
  2222.             killerspeed    = speedup(killerspeed,      TRUE);
  2223.               dripfreq  = atleast(  dripfreq / 2,   DRIPFREQ_MIN);
  2224.             killerfreq  = atleast(killerfreq / 2, KILLERFREQ_MIN);
  2225.                orbfreq  = atleast(   orbfreq / 2,    ORBFREQ_MIN);
  2226.              slimefreq  = atleast( slimefreq / 2,  SLIMEFREQ_MIN);
  2227.     }    }
  2228.     else
  2229.     {    outoftime = FALSE;
  2230.         say(timedisplay, WHITE);
  2231. }    }
  2232.  
  2233. void train(SCANCODE scancode)
  2234. {    SBYTE i, x, y;
  2235.  
  2236.     switch(scancode) {
  2237.     case HELP:
  2238.         trainer = !trainer;
  2239.         break;
  2240.     case NUMERICSLASH:
  2241.         // Complete the level.
  2242.         if (trainer)
  2243.         {    trainer = FALSE;
  2244.             if (worm[1].lives > 0)
  2245.                 for (i = 0; i <= LETTERS; i++)
  2246.                     letters[1][i] = TRUE;
  2247.                     drawletter(1, FIRSTLETTER + i, NORMAL);
  2248.         }
  2249.         break;
  2250.     case NUMERICASTERISK:
  2251.         // Change most squares to gold.
  2252.         if (trainer)
  2253.         {    trainer = FALSE;
  2254.             for (x = 0; x <= FIELDX; x++)
  2255.                 for (y = 0; y <= FIELDY; y++)
  2256.                     if (field[x][y] == FIRSTTAIL + 1)
  2257.                     {    draw(x, y, METAL);
  2258.                         field[x][y] = METAL;
  2259.                     } elif (field[x][y] != STONE && field[x][y] != KILLER && field[x][y] != ORB && field[x][y] != SKULL && (field[x][y] < FIRSTHEAD || field[x][y] > LASTHEAD) && (field[x][y] < FIRSTLETTER || field[x][y] > LASTLETTER))
  2260.                     {    draw(x, y, GOLD);
  2261.                         field[x][y] = GOLD;
  2262.         }            }
  2263.         break;
  2264.     case NUMERICPLUS:
  2265.         // Full lives, tongue, bias, ammo, power, nitro and affixer.
  2266.         if (trainer)
  2267.         {    trainer = FALSE;
  2268.             if (worm[1].lives > 0)
  2269.             {    worm[1].lives = LIVESLIMIT;
  2270.                 stat(1, LIFE);
  2271.                 worm[1].tongue = MODELIMIT;
  2272.                 worm[1].mode = TONGUE;
  2273.                 stat(1, TONGUE);
  2274.                 worm[1].bias = BIASLIMIT;
  2275.                 stat(1, BIAS);
  2276.                 worm[1].ammo = AMMOLIMIT;
  2277.                 stat(1, AMMO);
  2278.                 worm[1].power = POWERLIMIT;
  2279.                 stat(1, POWER);
  2280.                 worm[1].nitro = TRUE;
  2281.                 stat(1, NITRO);
  2282.                 worm[1].affixer = TRUE;
  2283.                 trainer = FALSE;
  2284.         }    }
  2285.         break;
  2286.     default:
  2287.         break;
  2288. }    }
  2289.  
  2290. void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  2291. {
  2292. if (worm[player].nitro || !deltax || !deltay)
  2293. {    if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  2294.     {    worm[player].speed = speedup(worm[player].speed, worm[player].nitro);
  2295.         stat(player, NITRO);
  2296.     } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  2297.     {    worm[player].speed = slowdown(worm[player].speed);
  2298.         stat(player, NITRO);
  2299.     } else
  2300.     {    worm[player].deltax = deltax;
  2301.         worm[player].deltay = deltay;
  2302. }    }
  2303. }
  2304.  
  2305. void updatesquare(SBYTE x, SBYTE y)
  2306. {    SBYTE    which;
  2307.  
  2308.     if (startx[level] == x && starty[level] == y)
  2309.         draw(x, y, START);
  2310.     elif (board[level][x][y] == TELEPORT)
  2311.     {    for (which = 0; which <= 1; which++)
  2312.             if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2313.                 draw(x, y, ONE + which);
  2314.     } else draw(x, y, board[level][x][y]);
  2315. }
  2316.  
  2317. SBYTE valid(SBYTE x, SBYTE y)
  2318. {    if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
  2319.         return(TRUE);
  2320.     else
  2321.         return(FALSE);
  2322. }
  2323.  
  2324. SBYTE whichdrip(SBYTE x, SBYTE y)
  2325. {   SBYTE which;
  2326.  
  2327.     for (which = 0; which <= DRIPS; which++)
  2328.         if (drip[which].alive && drip[which].x == x && drip[which].y == y)
  2329.             return(which);
  2330.     return(-1); // error code
  2331. }
  2332. void whichfrag(SBYTE x, SBYTE y, SBYTE* whichptr, SBYTE* iwhichptr)
  2333. {    SBYTE which, iwhich;
  2334.  
  2335.     for (which = 0; which <= ORBS + 1; which++)
  2336.         for (iwhich = 0; iwhich <= 7; iwhich++)
  2337.             if (frag[which][iwhich].alive && frag[which][iwhich].x == x && frag[which][iwhich].y == y)
  2338.             {    *whichptr = which;
  2339.                 *iwhichptr = iwhich;
  2340.                 return;
  2341. }            }
  2342. SBYTE whichkiller(SBYTE x, SBYTE y)
  2343. {   SBYTE which;
  2344.  
  2345.     for (which = 0; which <= KILLERS; which++)
  2346.         if (killer[which].alive && killer[which].x == x && killer[which].y == y)
  2347.             return(which);
  2348.     return(-1); // error code
  2349. }
  2350. SBYTE whichorb(SBYTE x, SBYTE y)
  2351. {   SBYTE which;
  2352.  
  2353.     for (which = 0; which <= ORBS; which++)
  2354.         if (orb[which].alive && orb[which].x == x && orb[which].y == y)
  2355.             return(which);
  2356.     return(-1); // error code
  2357. }
  2358. SBYTE whichteleport(SBYTE x, SBYTE y)
  2359. {   SBYTE which;
  2360.  
  2361.     for (which = 0; which <= TIMEBOMBS; which++)
  2362.         if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2363.             return((SBYTE) which);
  2364.     return((SBYTE) -1); // error code
  2365. }
  2366. SBYTE whichtimebomb(SBYTE x, SBYTE y)
  2367. {   SBYTE which;
  2368.  
  2369.     for (which = 0; which <= TIMEBOMBS; which++)
  2370.         if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
  2371.             return(which);
  2372.     return(-1); // error code
  2373. }
  2374.  
  2375. void wormbullet(SBYTE player)
  2376. {    ABOOL    finished,
  2377.             flag        = FALSE,
  2378.             ok            = FALSE,
  2379.             lettered    = FALSE;
  2380.     LONG    score;
  2381.     SBYTE    distance,
  2382.             thissy,
  2383.             i, j, k,
  2384.             x, y;
  2385.  
  2386.     if (!worm[player].ammo)
  2387.     {    stat(player, BONUS);
  2388.         if (worm[player].speed == FAST)
  2389.             distance = FASTDISTANCE;
  2390.         elif (worm[player].speed == NORMAL)
  2391.             distance = NORMALDISTANCE;
  2392.         else
  2393.         {    // assert(worm[player].speed == SLOW);
  2394.             distance = SLOWDISTANCE;
  2395.         }
  2396.  
  2397.         // check for metal
  2398.  
  2399.         for (i = 1; i < distance; i++)
  2400.         {    x = xwrap(worm[player].x + (i * worm[player].deltax));
  2401.             y = ywrap(worm[player].y + (i * worm[player].deltay));
  2402.             if (field[x][y] == METAL)
  2403.                 flag = TRUE;
  2404.         }
  2405.  
  2406.         if (!flag)
  2407.         {    // assert(abs(worm[player].deltax) == 1 && abs(worm[player].deltay) == 1);
  2408.             x = xwrap(worm[player].x + worm[player].deltax * distance);
  2409.             y = ywrap(worm[player].y + worm[player].deltay * distance);
  2410.             thissy = field[x][y];
  2411.             if (thissy == TELEPORT)
  2412.             {   i = whichteleport(x, y);
  2413.                 if (!blocked(i, worm[player].deltax, worm[player].deltay))
  2414.                     ok = TRUE;
  2415.             }
  2416.             if (ok || ((thissy < STONE || thissy > KILLER) && thissy != METAL))
  2417.             {    // Amiga-worms only make jumping sounds in demo mode
  2418.                 flag = FALSE;
  2419.                 for (i = lo; i <= hi; i++)
  2420.                     if (worm[i].control == HUMAN)
  2421.                         flag = TRUE;
  2422.                 if (!flag || worm[player].control == HUMAN)
  2423.                     effect(FXJUMP);
  2424.                 worm[player].deltax *= distance;
  2425.                 worm[player].deltay *= distance;
  2426.     }    }    }
  2427.     else
  2428.     {    effect(FXSHOOT);
  2429.         worm[player].ammo--;
  2430.         stat(player, AMMO);
  2431.         if (!missile[player].alive && worm[player].bias)
  2432.         {   missile[player].alive    = TRUE;
  2433.             missile[player].x        = worm[player].x;
  2434.             missile[player].y        = worm[player].y;
  2435.             missile[player].moved    = FALSE;
  2436.         }
  2437.         for (i = 0; i <= worm[player].power; i++)
  2438.         {    bullet[i].alive            = TRUE;
  2439.             bullet[i].teleported    = 0;
  2440.             bullet[i].visible        = TRUE;
  2441.             bullet[i].reflected        = FALSE;
  2442.             if (i % 2 == 0)
  2443.                 distance = i / 2;
  2444.             else
  2445.                 distance = -((i + 1) / 2);
  2446.             if (worm[player].deltax == 0)
  2447.             {    bullet[i].x = worm[player].x + distance;
  2448.                 bullet[i].y = worm[player].y + worm[player].deltay + 1;
  2449.             } elif (worm[player].deltay == 0)
  2450.             {    bullet[i].x = worm[player].x + worm[player].deltax + 1;
  2451.                 bullet[i].y = worm[player].y + distance;
  2452.             } else
  2453.             {    switch (i) {
  2454.                 case 0:
  2455.                    bullet[i].x = worm[player].x + worm[player].deltax;
  2456.                    bullet[i].y = worm[player].y + worm[player].deltay;
  2457.                    break;
  2458.                 case 1:
  2459.                    bullet[i].x = worm[player].x + worm[player].deltax;
  2460.                    bullet[i].y = worm[player].y;
  2461.                    break;
  2462.                 case 2:
  2463.                    bullet[i].x = worm[player].x;
  2464.                    bullet[i].y = worm[player].y + worm[player].deltay;
  2465.                    break;
  2466.                 case 3:
  2467.                    bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2468.                    bullet[i].y = worm[player].y;
  2469.                    break;
  2470.                 case 4:
  2471.                    bullet[i].x = worm[player].x;
  2472.                    bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2473.                    break;
  2474.                 case 5:
  2475.                    bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2476.                    bullet[i].y = worm[player].y - worm[player].deltay;
  2477.                    break;
  2478.                 case 6:
  2479.                    bullet[i].x = worm[player].x - worm[player].deltax;
  2480.                    bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2481.                    break;
  2482.                 default:
  2483.                    break;
  2484.             }    }
  2485.                if (!(valid(bullet[i].x, bullet[i].y)))
  2486.                    bullet[i].alive = FALSE;
  2487.         }
  2488.         score = 0L;
  2489.         finished = FALSE;
  2490.         while (!finished)
  2491.         {    finished = TRUE;
  2492.             for (i = 0; i <= worm[player].power; i++)
  2493.             {   if (bullet[i].alive)
  2494.                 {    finished = FALSE;
  2495.                     if (bullet[i].visible)
  2496.                         if (bullet[i].teleported)
  2497.                         {   if (worm[player].bias)
  2498.                             {    draw(bullet[i].x, bullet[i].y, GOLD);
  2499.                                 field[bullet[i].x][bullet[i].y] = GOLD;
  2500.                             } else
  2501.                             {    draw(bullet[i].x, bullet[i].y, SILVER);
  2502.                                 field[bullet[i].x][bullet[i].y] = SILVER;
  2503.                         }    }
  2504.                         else
  2505.                         {    draw(bullet[i].x, bullet[i].y, EMPTY);
  2506.                             field[bullet[i].x][bullet[i].y] = EMPTY;
  2507.                         }
  2508.                     else bullet[i].visible = TRUE;
  2509.                     if (bullet[i].reflected)
  2510.                     {    bullet[i].x -= worm[player].deltax;
  2511.                         bullet[i].y -= worm[player].deltay;
  2512.                     } else
  2513.                     {    bullet[i].x += worm[player].deltax;
  2514.                         bullet[i].y += worm[player].deltay;
  2515.                     }
  2516.                     if (!(valid(bullet[i].x, bullet[i].y)))
  2517.                         bullet[i].alive = FALSE;
  2518.                     else if (bullet[i].x == worm[player].x && bullet[i].y == worm[player].y)
  2519.                     {    // hit by own bullet
  2520.                         bullet[i].alive = FALSE;
  2521.                         if (worm[player].mode != ARMOUR)
  2522.                         {    worm[player].cause = FIRSTFIRE + player;
  2523.                             worm[player].victor = -1;
  2524.                             worm[player].alive = FALSE;
  2525.                     }    }
  2526.                     else
  2527.                     {    thissy = field[bullet[i].x][bullet[i].y];
  2528.                         if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2529.                         {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2530.                             {    worm[thissy - FIRSTHEAD].cause = FIRSTFIRE + player;
  2531.                                 worm[thissy - FIRSTHEAD].victor = player;
  2532.                                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2533.                                 if (player != thissy - FIRSTHEAD)
  2534.                                     score += KILLWORM + HITSHOT;
  2535.                             } else effect(FXUSEARMOUR);
  2536.                             bullet[i].alive = FALSE;
  2537.                         } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2538.                         {    if (player != thissy - FIRSTPROTECTOR)
  2539.                             {    effect(FXUSEPROTECTOR);
  2540.                                 bullet[i].alive = FALSE;
  2541.                             } else
  2542.                                 bullet[i].visible = FALSE;
  2543.                         } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2544.                         {    if (player != thissy - FIRSTMISSILE)
  2545.                                 missile[thissy - FIRSTMISSILE].alive = FALSE;
  2546.                             else bullet[i].visible = FALSE;
  2547.                         } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2548.                         {    j = whichdrip(bullet[i].x, bullet[i].y);
  2549.                             drip[j].alive = FALSE;
  2550.                         } elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2551.                         {    wormletter(player, thissy);
  2552.                             lettered = TRUE;
  2553.                         } else
  2554.                         {    switch(thissy) {
  2555.                             case METAL:
  2556.                                 if (bullet[i].reflected)
  2557.                                     bullet[i].alive = FALSE;
  2558.                                 else
  2559.                                 {    bullet[i].reflected = TRUE;
  2560.                                     bullet[i].x -= worm[player].deltax;
  2561.                                     bullet[i].y -= worm[player].deltay;
  2562.                                 }
  2563.                                 break;
  2564.                             case STONE:
  2565.                                 bullet[i].alive = FALSE;
  2566.                                 break;
  2567.                             case ORB:
  2568.                                 bullet[i].alive = FALSE;
  2569.                                 j = whichorb(bullet[i].x, bullet[i].y);
  2570.                                 if (orb[j].mode != ARMOUR)
  2571.                                 {   orb[j].explode = TRUE;
  2572.                                     score += orb[j].score + HITSHOT;
  2573.                                     if (worm[player].bias)
  2574.                                         worm[player].lives += ORBBLOOD;
  2575.                                 } else effect(FXUSEARMOUR);
  2576.                                 break;
  2577.                             case TELEPORT:
  2578.                                 j = whichteleport(bullet[i].x, bullet[i].y);
  2579.                                 if (bullet[i].teleported == 2)
  2580.                                     bullet[i].alive = FALSE;
  2581.                                 else
  2582.                                 {   effect(FXUSETELEPORT);
  2583.                                     bullet[i].visible = FALSE;
  2584.                                     bullet[i].teleported++;
  2585.                                     bullet[i].x = teleport[level][partner(j)].x;
  2586.                                     bullet[i].y = teleport[level][partner(j)].y;
  2587.                                     score += TELPOINT;
  2588.                                 }
  2589.                                 break;
  2590.                             case WOOD:
  2591.                                 if (!worm[player].bias)
  2592.                                     bullet[i].alive = FALSE;
  2593.                                 break;
  2594.                             case KILLER:
  2595.                                 for (j = 0; j <= KILLERS; j++)
  2596.                                     if (killer[j].alive && killer[j].x == bullet[i].x && killer[j].y == bullet[i].y)
  2597.                                     {   killer[j].alive = FALSE;
  2598.                                         draw(bullet[i].x, bullet[i].y, BONUS);
  2599.                                         field[bullet[i].x][bullet[i].y] = BONUS;
  2600.                                         score += KILLKILLER + HITSHOT;
  2601.                                         if (worm[player].bias)
  2602.                                             worm[player].lives += KILLERBLOOD;
  2603.                                        }
  2604.                                    bullet[i].alive = FALSE;
  2605.                                    break;
  2606.                                case SKULL:
  2607.                                    bullet[i].alive = FALSE;
  2608.                                    break;
  2609.                                case FRAGMENT:
  2610.                                    bullet[i].alive = FALSE;
  2611.                                    whichfrag(bullet[i].x, bullet[i].y, &j, &k);
  2612.                                    frag[j][k].alive = FALSE;
  2613.                                    field[bullet[i].x][bullet[i].y] = EMPTY;
  2614.                                    draw(bullet[i].x, bullet[i].y, EMPTY);
  2615.                                    break;
  2616.                                case BOMB:
  2617.                                    j = whichtimebomb(bullet[i].x, bullet[i].y);
  2618.                                    if (j != -1)
  2619.                                    {   bullet[i].alive = FALSE;
  2620.                                        timebomb[j].alive = FALSE;
  2621.                                        field[timebomb[j].x][timebomb[j].y] = EMPTY;
  2622.                                        draw(timebomb[j].x, timebomb[j].y, EMPTY);
  2623.                                        bombblast(HEAD, player, timebomb[j].x, timebomb[j].y);
  2624.                                    }
  2625.                                    break;
  2626.                                default:
  2627.                                    break;
  2628.                             }
  2629.                                if (bullet[i].alive && bullet[i].visible)
  2630.                                 draw(bullet[i].x, bullet[i].y, FIRSTFIRE + player);
  2631.         }    }    }    }    }
  2632.         if (lettered)
  2633.             putletter(player);
  2634.         wormscore(player, score);
  2635.         if (worm[player].bias)
  2636.             stat(player, LIFE);
  2637.         clearkybd();
  2638. }    }
  2639.  
  2640. void wormletter(SBYTE player, SBYTE thissy)
  2641. {    if (thissy == GREEN_C)
  2642.         effect(FX_C);
  2643.     elif (thissy == RED_O)
  2644.         effect(FX_O);
  2645.     elif (thissy == BLUE_M)
  2646.         effect(FX_M);
  2647.     elif (thissy == YELLOW_P)
  2648.         effect(FX_P);
  2649.     elif (thissy == GREEN_L)
  2650.         effect(FX_L);
  2651.     elif (thissy == BLUE_T)
  2652.         effect(FX_T);
  2653.     else // assumes RED_E or YELLOW_E
  2654.         effect(FX_E);
  2655.     letters[player][thissy - FIRSTLETTER] = TRUE;
  2656.        drawletter(player, thissy, NORMAL);
  2657.     if (player == (thissy - FIRSTLETTER) % 4)
  2658.         wormscore(player, MYLETTER);
  2659.     else wormscore(player, YOURLETTER);
  2660. }
  2661.  
  2662. /* NAME     wormloop -- controls worms and protectors
  2663. SYNOPSIS    wormloop(SBYTE);
  2664. FUNCTION    Amiga-worm thinking, processing one keystroke from the
  2665.             worm's queue, all the worm's protectors' control, the
  2666.             worm's control.
  2667. MODULE      engine.c */
  2668.  
  2669. void wormloop(SBYTE player)
  2670. {
  2671. ABOOL    complete, done, flag;
  2672. SBYTE    bestgood, bestx, besty, creature, dirx, diry, good, i, ithis,
  2673.         iwhich, thissy, thisletter, thisprot = -1, which, x, xx, y, yy;
  2674. LONG    score = 0L;
  2675.  
  2676.     /* AI: Amiga worm control
  2677.  
  2678.     Worm checks ahead, left and right one square. Assigns opinions to those
  2679.     three choices and then takes the appropriate one.
  2680.     
  2681.     Possible enhancements:
  2682.         recognition of possession of objects
  2683.             (esp. ammo, nitro, tongue, armour)
  2684.         finer gradients of decision
  2685.             (eg. certain objects better than others)
  2686.         longer lookahead */
  2687.  
  2688.     if (worm[player].control == AMIGA)
  2689.     {    if (!(rand() % 200))
  2690.             queue(player, (rand() % 3) - 1, (rand() % 3) - 1);
  2691.         else
  2692.         {    bestgood = -128;
  2693.  
  2694.             for (i = 0; i <= 2; i++)
  2695.             {    switch(i) {
  2696.                 case 0:
  2697.                     dirx = worm[player].deltax;
  2698.                     diry = worm[player].deltay;
  2699.                     break;
  2700.                 case 1:
  2701.                     if (worm[player].deltax == 0)    // if going north or south
  2702.                     {    dirx = -1;                    // then look west
  2703.                         diry = 0;
  2704.                     } else                            // if going east or west
  2705.                     {    dirx = 0;                    // then look north
  2706.                         diry = -1;
  2707.                     }
  2708.                     break;
  2709.                 case 2:
  2710.                     if (worm[player].deltax == 0)    // if going north or south
  2711.                     {    dirx = 1;                    // then look east
  2712.                         diry = 0;
  2713.                     } else                            // if going east or west
  2714.                     {    dirx = 0;                    // then look south
  2715.                         diry = 1;
  2716.                     }
  2717.                     break;
  2718.                 default:
  2719.                     break;
  2720.                 }
  2721.                 thissy = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
  2722.                 if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2723.                     good = 100;
  2724.                 elif (thissy <= LASTOBJECT)
  2725.                     good = 80;
  2726.                 elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2727.                 {    if (player == thissy - FIRSTTAIL)
  2728.                         good = -30;
  2729.                     else good = -60;
  2730.                 } else switch(thissy) {
  2731.                 case SKULL:
  2732.                     good = 70;
  2733.                     break;
  2734.                 case GOLD:
  2735.                     good = 50;
  2736.                     break;
  2737.                 case SILVER:
  2738.                     good = 40;
  2739.                     break;
  2740.                 case EMPTY:
  2741.                     good = 10;
  2742.                     break;
  2743.                 case WOOD:
  2744.                     good = -80;
  2745.                     break;
  2746.                 case STONE:
  2747.                     good = -90;
  2748.                     break;
  2749.                 case METAL:
  2750.                     good = -90;
  2751.                     break;
  2752.                 case KILLER:
  2753.                     good = -100;
  2754.                     break;
  2755.                 default:
  2756.                     good = -50; // slime, heads, orbs, etc.
  2757.                     break;
  2758.                 }
  2759.                 if (good > bestgood)
  2760.                 {    bestx = dirx;
  2761.                     besty = diry;
  2762.                     bestgood = good;
  2763.             }    }
  2764.  
  2765.             if (bestgood <= -60)
  2766.                 queue(player, 0, 0);
  2767.             elif (bestgood < 0 && (!(rand() % 2)))
  2768.                 queue(player, 0, 0);
  2769.             elif (bestx != worm[player].deltax || besty != worm[player].deltay)
  2770.                 queue(player, bestx, besty);
  2771.     }    }
  2772.  
  2773. // remove a keystroke from the queue
  2774.  
  2775. if (worm[player].pos != -1)
  2776. {   if (thequeue[player][0].deltax == 0 && thequeue[player][0].deltay == 0)
  2777.         wormbullet(player);
  2778.     else turnworm(player, thequeue[player][0].deltax, thequeue[player][0].deltay);
  2779.     if (--worm[player].pos != -1)
  2780.         for (i = 0; i <= worm[player].pos; i++)
  2781.         {   thequeue[player][i].deltax = thequeue[player][i + 1].deltax;
  2782.             thequeue[player][i].deltay = thequeue[player][i + 1].deltay;
  2783. }       }
  2784.  
  2785. // move worm
  2786.  
  2787. field[worm[player].x][worm[player].y] = worm[player].last;
  2788. draw(worm[player].x, worm[player].y, worm[player].last);
  2789. worm[player].x = xwrap(worm[player].x + worm[player].deltax);
  2790. worm[player].y = ywrap(worm[player].y + worm[player].deltay);
  2791. worm[player].deltax = bsign(worm[player].deltax);
  2792. worm[player].deltay = bsign(worm[player].deltay);
  2793. worm[player].last = FIRSTTAIL + player;
  2794.  
  2795. // move protectors
  2796.  
  2797. for (which = 0; which <= PROTECTORS; which++)
  2798. {   if (protector[player][which].alive)
  2799.     {   if (protector[player][which].visible)
  2800.         {   draw(protector[player][which].x, protector[player][which].y, protector[player][which].last);
  2801.             field[protector[player][which].x][protector[player][which].y] = protector[player][which].last;
  2802.         } else protector[player][which].visible = TRUE;
  2803.         protector[player][which].last = EMPTY;
  2804.  
  2805.         if (which == NOSE)
  2806.         {    protector[player][which].relx = worm[player].deltax * NOSEDISTANCE;
  2807.             protector[player][which].rely = worm[player].deltay * NOSEDISTANCE;
  2808.             if (!worm[player].affixer)
  2809.             {    if (worm[player].position == -1)
  2810.                     worm[player].posidir = 1;
  2811.                 elif (worm[player].position == 1)
  2812.                     worm[player].posidir = -1;
  2813.                 worm[player].position += worm[player].posidir;
  2814.                 if (worm[player].deltax == 0)
  2815.                     protector[player][which].relx = worm[player].position;
  2816.                 elif (worm[player].deltay == 0)
  2817.                     protector[player][which].rely = worm[player].position;
  2818.                 elif (worm[player].position == -1)
  2819.                     protector[player][which].relx = worm[player].deltax * (NOSEDISTANCE - 1);
  2820.                 elif (worm[player].position == 1)
  2821.                     protector[player][which].rely = worm[player].deltay * (NOSEDISTANCE - 1);
  2822.         }    }
  2823.         elif (!worm[player].affixer)
  2824.         {    if (protector[player][which].relx == 1 && protector[player][which].rely == -1)
  2825.             {    protector[player][which].deltax = 0;
  2826.                 protector[player][which].deltay = 1;
  2827.             } elif (protector[player][which].relx == 1 && protector[player][which].rely == 1)
  2828.             {    protector[player][which].deltax = -1;
  2829.                 protector[player][which].deltay = 0;
  2830.             } elif (protector[player][which].relx == -1 && protector[player][which].rely == 1)
  2831.             {    protector[player][which].deltax = 0;
  2832.                 protector[player][which].deltay = -1;
  2833.             } elif (protector[player][which].relx == -1 && protector[player][which].rely == -1)
  2834.             {    protector[player][which].deltax = 1;
  2835.                 protector[player][which].deltay = 0;
  2836.             }
  2837.             protector[player][which].relx += protector[player][which].deltax;
  2838.             protector[player][which].rely += protector[player][which].deltay;
  2839.         }
  2840.         protector[player][which].x = worm[player].x + protector[player][which].relx;
  2841.         protector[player][which].y = worm[player].y + protector[player][which].rely;
  2842.         if (!valid(protector[player][which].x, protector[player][which].y))
  2843.             protector[player][which].visible = FALSE;
  2844. }    }
  2845.  
  2846. // collision detection
  2847.  
  2848. creature = HEAD;
  2849. while (creature != NULL)
  2850. {    if (creature == HEAD)
  2851.     {   x = worm[player].x;
  2852.         y = worm[player].y;
  2853.     } else
  2854.     {    x = protector[player][thisprot].x;
  2855.         y = protector[player][thisprot].y;
  2856.     }
  2857.     thissy = field[x][y];
  2858.     if (creature == HEAD)
  2859.     {   if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2860.         {   if (worm[player].mode != TONGUE)
  2861.                 if (worm[thissy - FIRSTHEAD].mode != TONGUE)
  2862.                 {    // both worms die
  2863.                     worm[player].cause                = thissy;
  2864.                     worm[player].alive                = FALSE;
  2865.                     worm[player].victor                = -1;
  2866.                     worm[thissy - FIRSTHEAD].cause    = FIRSTHEAD + player;
  2867.                     worm[thissy - FIRSTHEAD].alive    = FALSE;
  2868.                     worm[thissy - FIRSTHEAD].victor    = -1;
  2869.                 } else
  2870.                 {    // this worm dies
  2871.                     worm[player].cause                = thissy;
  2872.                     worm[player].alive                = FALSE;
  2873.                     worm[player].victor                = thissy - FIRSTHEAD;
  2874.                 }
  2875.             elif (worm[thissy - FIRSTHEAD].mode != TONGUE)
  2876.             {    // other worm dies
  2877.                 worm[thissy - FIRSTHEAD].cause        = FIRSTHEAD + player;
  2878.                 worm[thissy - FIRSTHEAD].alive        = FALSE;
  2879.                 worm[thissy - FIRSTHEAD].victor        = player;
  2880.         }    }
  2881.         elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2882.         {   if (worm[player].mode == TONGUE)
  2883.             {    effect(FXUSETONGUE);
  2884.                 if (lo != hi)
  2885.                     if (player == thissy - FIRSTTAIL)
  2886.                     {   score += TURNTOSILVER;
  2887.                         worm[player].last = SILVER;
  2888.                     } else
  2889.                     {   score += TURNTOGOLD;
  2890.                         worm[player].last = GOLD;
  2891.             }       }
  2892.             else
  2893.             {   worm[player].cause = thissy;
  2894.                 worm[player].alive = FALSE;
  2895.                 worm[player].victor = thissy - FIRSTTAIL;
  2896.         }   }
  2897.         elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2898.             if (worm[player].mode != ARMOUR)
  2899.             {   worm[player].cause = thissy;
  2900.                 worm[player].victor = thissy - FIRSTPROTECTOR;
  2901.                 worm[player].alive = FALSE;
  2902.             } else effect(FXUSEARMOUR);
  2903.         elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2904.         {   if (player != thissy - FIRSTMISSILE)
  2905.             {   missile[thissy - FIRSTMISSILE].alive = FALSE;
  2906.                 if (worm[player].mode != ARMOUR)
  2907.                 {   worm[player].alive = FALSE;
  2908.                     worm[player].cause = thissy;
  2909.                     worm[player].victor = thissy - FIRSTMISSILE;
  2910.                 } else effect(FXUSEARMOUR);
  2911.         }   }
  2912.         elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2913.         {    which = whichdrip(x, y);
  2914.             drip[which].alive = FALSE;
  2915.             if (player == thissy - FIRSTDRIP || worm[player].bias)
  2916.             {    effect(FXDRIP);
  2917.                 wormscore(player, DRIPBONUS);
  2918.             } else
  2919.             {    worm[player].alive = FALSE;
  2920.                 worm[player].cause = thissy;
  2921.                 worm[player].victor = -1;
  2922.             }
  2923.         } elif (thissy == STONE || thissy == KILLER || thissy == METAL)
  2924.         {   worm[player].cause = thissy;
  2925.             worm[player].victor = -1;
  2926.             worm[player].alive = FALSE;
  2927.             ramming(player);
  2928.         } elif (thissy == WOOD)
  2929.         {   if (worm[player].mode != TONGUE)
  2930.             {   worm[player].cause = WOOD;
  2931.                 worm[player].alive = FALSE;
  2932.                 worm[player].victor = -1;
  2933.         }   }
  2934.         elif (thissy == SLIME)
  2935.         {    if (worm[player].mode != ARMOUR)
  2936.             {    worm[player].cause = SLIME;
  2937.                 worm[player].alive = FALSE;
  2938.                 worm[player].victor = -1;
  2939.         }    }
  2940.         elif (thissy == TELEPORT)
  2941.         {   which = whichteleport(x, y);
  2942.             if (blocked(which, worm[player].deltax, worm[player].deltay))
  2943.             {   worm[player].cause = TELEPORT;
  2944.                 worm[player].victor = -1;
  2945.                 worm[player].alive = FALSE;
  2946.                 ramming(player);
  2947.             } else
  2948.             {   effect(FXUSETELEPORT);
  2949.                 score += TELPOINT;
  2950.                 worm[player].x = xwrap(teleport[level][partner(which)].x + worm[player].deltax);
  2951.                 worm[player].y = ywrap(teleport[level][partner(which)].y + worm[player].deltay);
  2952.     }   }   }
  2953.     else // creature == PROTECTOR
  2954.     {   if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2955.         {   if (player != thissy - FIRSTHEAD)
  2956.             {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2957.                 {   effect(FXUSEPROTECTOR);
  2958.                     worm[thissy - FIRSTHEAD].cause = FIRSTPROTECTOR + player;
  2959.                     worm[thissy - FIRSTHEAD].alive = FALSE;
  2960.                     worm[thissy - FIRSTHEAD].victor = player;
  2961.                 } else
  2962.                 {   effect(FXUSEARMOUR);
  2963.                     protector[player][thisprot].visible = FALSE;
  2964.             }    }
  2965.             else // protector is over worm's own head; caused by ramming
  2966.                 protector[player][thisprot].visible = FALSE;
  2967.         } elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2968.         {   if (player == thissy - FIRSTTAIL || worm[player].mode == TONGUE)
  2969.                 protector[player][thisprot].visible = FALSE;
  2970.         } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2971.         {   protector[player][thisprot].alive = FALSE;
  2972.             for (which = 0; which <= PROTECTORS; which++)
  2973.             if (protector[thissy - FIRSTPROTECTOR][which].alive && protector[thissy - FIRSTPROTECTOR][which].x == x && protector[thissy - FIRSTPROTECTOR][which].y == y)
  2974.             {   protector[thissy - FIRSTPROTECTOR][which].alive = FALSE;
  2975.                 break;
  2976.             }
  2977.             draw(x, y, EMPTY);
  2978.             field[x][y] = EMPTY;
  2979.         } elif (thissy == STONE || thissy == WOOD || thissy == METAL)
  2980.             protector[player][thisprot].visible = FALSE;
  2981.         elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2982.         {   if (player != thissy - FIRSTMISSILE)
  2983.             {   effect(FXUSEPROTECTOR);
  2984.                 missile[thissy - FIRSTMISSILE].alive = FALSE;
  2985.             } else protector[player][thisprot].visible = FALSE;
  2986.         } elif (thissy == TELEPORT)
  2987.         {   protector[player][thisprot].visible = FALSE;
  2988.             score += TELPOINT;
  2989.         } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2990.         {    which = whichdrip(x, y);
  2991.             drip[which].alive = FALSE;
  2992.             if (player == thissy - FIRSTDRIP || worm[player].bias)
  2993.             {    score += DRIPBONUS;
  2994.                 effect(FXDRIP);
  2995.         }    }
  2996.         elif (thissy == KILLER)
  2997.         {   effect(FXUSEPROTECTOR);
  2998.             effect(FXKILLERDEATH);
  2999.             which = whichkiller(x, y);
  3000.             protector[player][thisprot].last = BONUS;
  3001.             killer[which].alive = FALSE;
  3002.             score += KILLKILLER;
  3003.             if (worm[player].bias)
  3004.             {   worm[player].lives += KILLERBLOOD;
  3005.                 stat(player, LIFE);
  3006.     }   }   }
  3007.     if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  3008.     {    wormletter(player, thissy);
  3009.         putletter(player);
  3010.     } elif (thissy <= LASTOBJECT)
  3011.     {   score += object[thissy].score;
  3012.         if (thissy != SLAYER
  3013.          && thissy != BOMB
  3014.          && thissy != MISSILE
  3015.          && thissy != NITRO
  3016.          && thissy != POWER
  3017.          && thissy != AMMO)
  3018.             effect(FXGETOBJECT);
  3019.         switch(thissy)
  3020.         {
  3021.         case BONUS:
  3022.             if (!worm[player].bias)
  3023.                 thisletter = rand() % (LETTERS + 1);
  3024.             else
  3025.             {    complete = TRUE;
  3026.                 for (which = 0; which <= LETTERS; which++)
  3027.                     if (!letters[player][which])
  3028.                     {    complete = FALSE;
  3029.                         do thisletter = rand() % (LETTERS + 1);
  3030.                         while (letters[player][thisletter]);
  3031.                         break;
  3032.                     }
  3033.                 if (complete)
  3034.                     thisletter = rand() % (LETTERS + 1);
  3035.             }
  3036.             letters[player][thisletter] = TRUE;
  3037.             drawletter(player, FIRSTLETTER + thisletter, NORMAL);
  3038.             break;
  3039.         case AMMO:
  3040.             effect(FXGETAMMO);
  3041.             worm[player].ammo += (rand() % 5) + 2; // 2-6 bullets
  3042.             stat(player, AMMO);
  3043.             break;
  3044.         case ARMOUR:
  3045.             /* FXUSEDRILL sample will automatically stop, because
  3046.             a square with ARMOUR is not a square with TAIL. */
  3047.  
  3048.             worm[player].armour += MODEADD + (rand() % MODERAND);
  3049.             worm[player].mode = ARMOUR;
  3050.             stat(player, ARMOUR);
  3051.             break;
  3052.         case TONGUE:
  3053.             worm[player].tongue += MODEADD + (rand() % MODERAND);
  3054.             worm[player].mode = TONGUE;
  3055.             stat(player, TONGUE);
  3056.             worm[player].last = FIRSTTAIL + player;
  3057.             break;
  3058.         case NITRO:
  3059.             effect(FXGETNITRO);
  3060.             worm[player].nitro = TRUE;
  3061.             stat(player, NITRO);
  3062.             break;
  3063.         case BOMB:
  3064.             flag = FALSE;
  3065.             which = whichtimebomb(x, y);
  3066.             if (which != -1)
  3067.             {   flag = TRUE;
  3068.                 if (creature == HEAD)
  3069.                 {   // push timebomb
  3070.  
  3071.                     if (valid(x + worm[player].deltax, y + worm[player].deltay))
  3072.                     {   ithis = field[x + worm[player].deltax][y + worm[player].deltay];
  3073.                         if (ithis == TELEPORT)
  3074.                             score += BOMBOVEREDGE;
  3075.                         elif (ithis == SKULL)
  3076.                         {    effect(FXGETSKULL);
  3077.                             score += SKULLPOINT;
  3078.                         } elif (ithis <= LASTEMPTY)
  3079.                         {   if (ithis <= LASTOBJECT)
  3080.                             {   score += object[thissy].score;
  3081.                                 if (ithis == BOMB)
  3082.                                 {   iwhich = whichtimebomb(x + worm[player].deltax, y + worm[player].deltay);
  3083.                                     if (iwhich != -1)
  3084.                                         timebomb[iwhich].alive = FALSE;
  3085.                             }   }                                        
  3086.                             timebomb[which].x += worm[player].deltax;
  3087.                             timebomb[which].y += worm[player].deltay;
  3088.                             field[timebomb[which].x][timebomb[which].y] = BOMB;
  3089.                             draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
  3090.                         } else flag = FALSE;
  3091.                     } else score += BOMBOVEREDGE;
  3092.                 } else protector[player][thisprot].visible = FALSE;
  3093.             }
  3094.             if (!flag)
  3095.             {   if (worm[player].mode == NULL)
  3096.                     draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3097.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3098.                 bombblast(HEAD, player, worm[player].x, worm[player].y);
  3099.             }
  3100.             break;
  3101.         case POWER:
  3102.             effect(FXGETPOWERUP);
  3103.             if (worm[player].power < POWERLIMIT)
  3104.             {    worm[player].power += 2;
  3105.                 stat(player, POWER);
  3106.             }
  3107.             break;
  3108.         case SLAYER:
  3109.             for (which = 0; which <= ORBS; which++)
  3110.                 if (orb[which].alive)
  3111.                 {   score += orb[which].score;
  3112.                     orb[which].explode = TRUE;
  3113.                     if (worm[player].bias)
  3114.                         worm[player].lives += ORBBLOOD;
  3115.                 }
  3116.             for (which = 0; which <= KILLERS; which++)
  3117.                 if (killer[which].alive)
  3118.                 {    effect(FXKILLERDEATH);
  3119.                     killer[which].alive = FALSE;
  3120.                     score += KILLKILLER;
  3121.                     if (worm[player].bias)
  3122.                         worm[player].lives += KILLERBLOOD;
  3123.                     field[killer[which].x][killer[which].y] = BONUS;
  3124.                     draw(killer[which].x, killer[which].y, BONUS);
  3125.                 }
  3126.             for (which = 0; which <= DRIPS; which++)
  3127.             {    drip[which].alive = FALSE;
  3128.                 field[drip[which].x][drip[which].y] = EMPTY;
  3129.                 draw(drip[which].x, drip[which].y, EMPTY);
  3130.             }
  3131.             for (which = lo; which <= hi; which++)
  3132.                 if (player != which && worm[which].mode != ARMOUR)
  3133.                 {    worm[which].alive = FALSE;
  3134.                     worm[which].cause = SLAYER;
  3135.                     worm[which].victor = player;
  3136.                 }
  3137.             for (x = 0; x <= FIELDX; x++)
  3138.                 for (y = 0; y <= FIELDY; y++)
  3139.                     if (field[x][y] == SLIME)
  3140.                     {    draw(x, y, EMPTY);
  3141.                         field[x][y] = EMPTY;
  3142.                     }
  3143.             if (worm[player].bias)
  3144.                 stat(player, LIFE);
  3145.             break;
  3146.         case PROTECTOR:
  3147.             done = FALSE;
  3148.             for (which = 0; which <= PROTECTORS; which++)
  3149.                 if (!protector[player][which].alive && !done)
  3150.                 {    do
  3151.                     {    protector[player][which].relx = ((rand() % 2) * 2) - 1;
  3152.                         protector[player][which].rely = ((rand() % 2) * 2) - 1;
  3153.                         for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
  3154.                             if (which == NOSE || !protector[player][iwhich].alive || protector[player][iwhich].x != xwrap(worm[player].x + protector[player][which].relx) || protector[player][iwhich].y != ywrap(worm[player].y + protector[player][which].rely))
  3155.                             {    effect(FXPROTECTORBORN);
  3156.                                 done = TRUE;
  3157.                                 protector[player][which].alive = TRUE;
  3158.                                 protector[player][which].visible = FALSE;
  3159.                                 protector[player][which].last = EMPTY;
  3160.                                 if (which == NOSE)
  3161.                                     worm[player].position = -1;
  3162.                             }
  3163.                     } while (!done);
  3164.                 }
  3165.             break;
  3166.         case MISSILE:
  3167.             if (!missile[player].alive)
  3168.             {    missile[player].alive = TRUE;
  3169.                 missile[player].x = worm[player].x;
  3170.                 missile[player].y = worm[player].y;
  3171.                 missile[player].moved = FALSE;
  3172.             }
  3173.             break;
  3174.         case LIFE:
  3175.             worm[player].lives += (rand() % 5) + 2; // 2-6 lives
  3176.             stat(player, LIFE);
  3177.             break;
  3178.         case MULTIPLIER:
  3179.             if (worm[player].multi < MULTILIMIT)
  3180.                 worm[player].multi *= 2;
  3181.             break;
  3182.         case BIAS:
  3183.             worm[player].bias += MODEADD + (rand() % MODERAND);
  3184.             stat(player, BIAS);
  3185.             break;
  3186.         case ICE:
  3187.             worm[player].ice += ICEADD + (rand() % ICERAND);
  3188.             ice = player;
  3189.             break;
  3190.         case GROWER:
  3191.             effect(FXGETGROWER);
  3192.  
  3193.             // grow tail
  3194.  
  3195.             if (worm[player].bias)
  3196.             {    for (x = 0; x <= FIELDX; x++)
  3197.                     for (y = 0; y <= FIELDY; y++)
  3198.                         if (field[x][y] == FIRSTTAIL + player)
  3199.                             for (xx = x - 1; xx <= x + 1; xx++)
  3200.                                 for (yy = y - 1; yy <= y + 1; yy++)
  3201.                                     if (valid(xx, yy))
  3202.                             if (field[xx][yy] == EMPTY)
  3203.                                 field[xx][yy] = TEMPTAIL;
  3204.             }
  3205.  
  3206.             // grow silver
  3207.  
  3208.             for (x = 0; x <= FIELDX; x++)
  3209.                 for (y = 0; y <= FIELDY; y++)
  3210.                     if (field[x][y] == SILVER)
  3211.                         for (xx = x - 1; xx <= x + 1; xx++)
  3212.                             for (yy = y - 1; yy <= y + 1; yy++)
  3213.                                 if (valid(xx, yy))
  3214.                         if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPTAIL)
  3215.                             field[xx][yy] = TEMPSILVER;
  3216.  
  3217.             // grow gold
  3218.  
  3219.             for (x = 0; x <= FIELDX; x++)
  3220.                 for (y = 0; y <= FIELDY; y++)
  3221.                     if (field[x][y] == GOLD)
  3222.                         for (xx = x - 1; xx <= x + 1; xx++)
  3223.                             for (yy = y - 1; yy <= y + 1; yy++)
  3224.                                 if (valid(xx, yy))
  3225.                         if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPTAIL || field[xx][yy] == TEMPSILVER)
  3226.                             field[xx][yy] = TEMPGOLD;
  3227.  
  3228.             // update
  3229.  
  3230.             for (x = 0; x <= FIELDX; x++)
  3231.                 for (y = 0; y <= FIELDY; y++)
  3232.                     switch (field[x][y])
  3233.                     {
  3234.                     case TEMPGOLD:
  3235.                         field[x][y] = GOLD;
  3236.                         draw(x, y, GOLD);
  3237.                         break;
  3238.                     case TEMPSILVER:
  3239.                         field[x][y] = SILVER;
  3240.                         draw(x, y, SILVER);
  3241.                         break;
  3242.                     case TEMPTAIL:
  3243.                         field[x][y] = FIRSTTAIL + player;
  3244.                         draw(x, y, FIRSTTAIL + player);
  3245.                         break;
  3246.                     default:
  3247.                         break;
  3248.                     }
  3249.             break;
  3250.         case TREASURE:
  3251.             treasurer = player;
  3252.             if (level)
  3253.             {    say((STRPTR) "Treasure!", worm[treasurer].colour);
  3254.                 secondsperlevel = 0;
  3255.             }
  3256.             secondsperlevel += TREASUREADD + (rand() % TREASURERAND);
  3257.             if (level)
  3258.             {    stat(player, BONUS);
  3259.                 reallevel = level;
  3260.                 level = 0;
  3261.                 newlevel(player);
  3262.             }
  3263.             break;
  3264.         case AFFIXER:
  3265.             worm[player].affixer = TRUE;
  3266.             break;
  3267.         case SWITCHER:
  3268.             if (lo != hi)
  3269.                 for (x = 0; x <= FIELDX; x++)
  3270.                     for (y = 0; y <= FIELDY; y++)
  3271.                         if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL && field[x][y] != FIRSTTAIL + player)
  3272.                         {    field[x][y] = FIRSTTAIL + player;
  3273.                             draw(x, y, FIRSTTAIL + player);
  3274.                         }
  3275.             break;
  3276.         case HEALER:
  3277.             if (worm[player].lives < 100)
  3278.                 worm[player].lives = 100;
  3279.             else worm[player].lives = LIVESLIMIT;
  3280.             stat(player, LIFE);
  3281.             break;
  3282.         case UMBRELLA:
  3283.             level += (rand() % 3);
  3284.             if (level >= levels)
  3285.                 level = level - 1;
  3286.             for (i = 0; i <= LETTERS; i++)
  3287.                 letters[player][i] = TRUE;
  3288.             break;
  3289.         case CLOCK:
  3290.             if (secondsleft)
  3291.                 secondsperlevel += (rand() % CLOCKRAND) + CLOCKADD;
  3292.             break;
  3293.         case SLOWER:
  3294.               dripspeed = (SBYTE) atleast(  dripspeed * 2, VERYFAST);
  3295.               fragspeed = (SBYTE) atleast(  fragspeed * 2, VERYFAST);
  3296.             killerspeed = (SBYTE) atleast(killerspeed * 2, VERYFAST);
  3297.                orbspeed = (SBYTE) atleast(   orbspeed * 2, VERYFAST);
  3298.             for (i = 0; i <= ORBS; i++)
  3299.                 if (orb[i].alive)
  3300.                     orb[i].speed = (SBYTE) atleast(orb[i].speed * 2, VERYFAST);
  3301.             break;
  3302.         default:
  3303.             break;
  3304.     }    }
  3305.     else
  3306.     {   switch (thissy)
  3307.         {
  3308.         case EMPTY:
  3309.             score += EMPTYPOINT;
  3310.             break;
  3311.         case SILVER:
  3312.             score += SILVERPOINT;
  3313.             break;
  3314.         case GOLD:
  3315.             score += GOLDPOINT;
  3316.             break;
  3317.         case ORB:
  3318.             iwhich = whichorb(x, y);
  3319.             if (worm[player].mode == ARMOUR || creature == PROTECTOR)
  3320.             {   if (creature == HEAD)
  3321.                     effect(FXUSEARMOUR);
  3322.                 else effect(FXUSEPROTECTOR);
  3323.                 effect(FXORBDEATH);
  3324.                 score += orb[iwhich].score;
  3325.                 orb[iwhich].alive = FALSE;
  3326.                 if (worm[player].bias)
  3327.                 {   worm[player].lives += ORBBLOOD;
  3328.                     stat(player, LIFE);
  3329.             }   }
  3330.             else
  3331.             {   if (orb[iwhich].mode == ARMOUR)
  3332.                 {   effect(FXUSEARMOUR);
  3333.                     orbscore(iwhich, KILLWORM);
  3334.                 } else orb[iwhich].alive = FALSE;
  3335.                 worm[player].cause = ORB;
  3336.                 worm[player].victor = -1;
  3337.                 worm[player].alive = FALSE;
  3338.             }
  3339.             break;
  3340.         case FRAGMENT:
  3341.             whichfrag(x, y, &which, &iwhich);
  3342.             if (creature == HEAD)
  3343.             {    if (worm[player].mode != ARMOUR)
  3344.                 {   worm[player].cause = FRAGMENT;
  3345.                     worm[player].victor = -1;
  3346.                     worm[player].alive = FALSE;
  3347.                     frag[which][iwhich].alive = FALSE;
  3348.                 } else
  3349.                 {    effect(FXUSEARMOUR);
  3350.                     reflect(which, iwhich);
  3351.             }    }
  3352.             else
  3353.             {    effect(FXUSEPROTECTOR);
  3354.                 reflect(which, iwhich);
  3355.             }
  3356.             break;
  3357.         case SKULL:
  3358.             effect(FXGETSKULL);
  3359.             score += SKULLPOINT;
  3360.             for (which = lo; which <= hi; which++)
  3361.             {    if (worm[which].alive == FALSE && worm[which].x == worm[player].x && worm[which].y == worm[player].y)
  3362.                     iwhich = which;
  3363.             }
  3364.             worm[player].bias    += worm[iwhich].bias;
  3365.             if (worm[player].bias > 0)
  3366.             {    stat(player, BIAS);
  3367.                 worm[iwhich].bias = 0;
  3368.                 stat(iwhich, BIAS);
  3369.             }
  3370.             worm[player].multi    *= worm[iwhich].multi;
  3371.             if (worm[player].multi > 1)
  3372.             {    if (worm[player].multi > MULTILIMIT)
  3373.                     worm[player].multi = MULTILIMIT;
  3374.             }
  3375.             worm[player].power    += worm[iwhich].power;
  3376.             if (worm[player].power > 1)
  3377.             {    if (worm[player].power > POWERLIMIT)
  3378.                     worm[player].power = POWERLIMIT;
  3379.                 stat(player, POWER);
  3380.                 worm[iwhich].power = 0;
  3381.                 stat(iwhich, POWER);
  3382.             }
  3383.             worm[player].ammo    += worm[iwhich].ammo;
  3384.             if (worm[player].ammo > 0)
  3385.             {    stat(player, AMMO);
  3386.                 worm[iwhich].ammo = 0;
  3387.                 stat(iwhich, AMMO);
  3388.             }
  3389.             worm[player].armour    += worm[iwhich].armour;
  3390.             if (worm[player].armour > 0)
  3391.             {    stat(player, ARMOUR);
  3392.                 worm[iwhich].armour = 0;
  3393.                 stat(iwhich, ARMOUR);
  3394.             }
  3395.             worm[player].tongue    += worm[iwhich].tongue;
  3396.             if (worm[player].tongue > 0)
  3397.             {    stat(player, TONGUE);
  3398.                 worm[iwhich].tongue = 0;
  3399.                 stat(iwhich, TONGUE);
  3400.             }
  3401.             if (worm[player].armour > 0 || worm[player].tongue > 0)
  3402.             {    if (worm[player].armour >= worm[player].tongue)
  3403.                     worm[player].mode = ARMOUR;
  3404.                 else worm[player].mode = TONGUE;
  3405.             }
  3406.             if (worm[iwhich].nitro)
  3407.             {    worm[player].nitro = TRUE;
  3408.                 stat(player, NITRO);
  3409.                 worm[iwhich].nitro = FALSE;
  3410.                 worm[iwhich].speed = NORMAL;
  3411.                 stat(iwhich, NITRO);
  3412.             }
  3413.             for (which = 0; which <= LETTERS; which++)
  3414.                 if (letters[iwhich][which])
  3415.                 {    drawletter(iwhich, FIRSTLETTER + which, BLACK);
  3416.                     if (!letters[player][which])
  3417.                     {    letters[player][which] = TRUE;
  3418.                         drawletter(player, FIRSTLETTER + which, NORMAL);
  3419.                 }    }
  3420.             break;
  3421.         default:
  3422.             break;
  3423.     }    }    
  3424.     if (creature == HEAD)
  3425.     // it is important that HEAD is done before PROTECTORs
  3426.     {   field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
  3427.         if (worm[player].alive)
  3428.         {    switch (worm[player].mode)
  3429.             {
  3430.             case NULL:
  3431.                 draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3432.                 break;
  3433.             case TONGUE:
  3434.                 if (worm[player].tongue < 10 && (r / SLOW) % 2 == 0)
  3435.                     draw(worm[player].x, worm[player].y, WHITENED);
  3436.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3437.                 break;
  3438.             case ARMOUR:
  3439.                 if (worm[player].armour < 10 && (r / SLOW) % 2 == 0)
  3440.                     draw(worm[player].x, worm[player].y, WHITENED);
  3441.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3442.                 break;
  3443.             default:
  3444.                 break;
  3445.         }    }
  3446.         else draw(worm[player].x, worm[player].y, SKULL);
  3447.     } else // assumes creature == PROTECTOR
  3448.         if (protector[player][thisprot].alive && protector[player][thisprot].visible)
  3449.         {   field[x][y] = FIRSTPROTECTOR + player;
  3450.             draw(x, y, FIRSTPROTECTOR + player);
  3451.         }
  3452.     while (++thisprot <= PROTECTORS)
  3453.         if (protector[player][thisprot].alive && valid(protector[player][thisprot].x, protector[player][thisprot].y))
  3454.             break;
  3455.     if (thisprot > PROTECTORS)
  3456.         creature = NULL;
  3457.     else creature = PROTECTOR;
  3458. }
  3459. wormscore(player, score);
  3460. }
  3461.  
  3462. void wormscore(SBYTE player, LONG score)
  3463. {   worm[player].score += score * worm[player].multi;
  3464.     stat(player, BONUS);
  3465. }
  3466.  
  3467. SWORD wsign(SWORD value)
  3468. {    if (value < 0)
  3469.         return (-1);
  3470.     elif (value > 0)
  3471.         return (1);
  3472.     else
  3473.         return (0);
  3474. }
  3475.  
  3476. SWORD xpixeltosquare(SWORD x)
  3477. {    x = (x - STARTXPIXEL) / SQUAREX;
  3478.     if (x < 0)
  3479.         x--;
  3480.     return (x);
  3481. }
  3482. SWORD ypixeltosquare(SWORD y)
  3483. {    y = (y - STARTYPIXEL) / SQUAREY;
  3484.     if (y < 0)
  3485.         y--;
  3486.     return (y);
  3487. }
  3488.  
  3489. SBYTE xwrap(SBYTE x)
  3490. {    if (x < 0)
  3491.         x += FIELDX + 1;
  3492.     elif (x > FIELDX)
  3493.         x -= FIELDX + 1;
  3494.     return(x);
  3495. }
  3496. SBYTE ywrap(SBYTE y)
  3497. {    if (y < 0)
  3498.         y += FIELDY + 1;
  3499.     elif (y > FIELDY)
  3500.         y -= FIELDY + 1;
  3501.     return(y);
  3502. }
  3503. void ramming(SBYTE player)
  3504. {    SBYTE i;
  3505.  
  3506.     worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  3507.     worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  3508.     for (i = 0; i <= PROTECTORS; i++)
  3509.     {    // no point checking whether the protectors are alive or dead
  3510.         protector[player][i].x -= worm[player].deltax;
  3511.         protector[player][i].y -= worm[player].deltay;
  3512. }    }
  3513.  
  3514. void driploop(void)
  3515. {    SBYTE i, j, k, thissy;
  3516.  
  3517.     for (i = 0; i <= DRIPS; i++)
  3518.         if (drip[i].alive)
  3519.         {    if (drip[i].moved)
  3520.             {    field[drip[i].x][drip[i].y] = EMPTY;
  3521.                 draw(drip[i].x, drip[i].y, EMPTY);
  3522.             } else drip[i].moved = TRUE;
  3523.             drip[i].y++;
  3524.             if (!valid(drip[i].x, drip[i].y))
  3525.                 drip[i].alive = FALSE;
  3526.             else
  3527.             {    thissy = field[drip[i].x][drip[i].y];
  3528.                 if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  3529.                 {    drip[i].alive = FALSE;
  3530.                     if (drip[i].type - FIRSTDRIP == thissy - FIRSTHEAD || worm[thissy - FIRSTHEAD].bias)
  3531.                     {    effect(FXDRIP);
  3532.                         wormscore(thissy - FIRSTHEAD, DRIPBONUS);
  3533.                     } else
  3534.                     {    worm[thissy - FIRSTHEAD].alive = FALSE;
  3535.                         worm[thissy - FIRSTHEAD].cause = drip[i].type;
  3536.                         worm[thissy - FIRSTHEAD].victor = -1;
  3537.                 }    }
  3538.                 elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  3539.                 {    drip[i].alive = FALSE;
  3540.                     if (drip[i].type == thissy - FIRSTPROTECTOR + FIRSTDRIP || worm[thissy - FIRSTPROTECTOR].bias)
  3541.                     {    wormscore(thissy - FIRSTPROTECTOR, DRIPBONUS);
  3542.                         effect(FXDRIP);
  3543.                 }    }
  3544.                 elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  3545.                     drip[i].alive = FALSE;
  3546.                 elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  3547.                     missile[thissy - FIRSTMISSILE].alive = FALSE;
  3548.                 else switch(thissy)
  3549.                 {
  3550.                 case FRAGMENT:
  3551.                     drip[i].alive = FALSE;
  3552.                     whichfrag(drip[i].x, drip[i].y, &j, &k);
  3553.                     frag[j][k].alive = BONUS;
  3554.                     draw(drip[i].x, drip[i].y, BONUS);
  3555.                 case ORB:
  3556.                     drip[i].alive = FALSE;
  3557.                     j = whichorb(drip[i].x, drip[i].y);
  3558.                     if (orb[j].mode != ARMOUR)
  3559.                     {    orb[j].explode = TRUE;
  3560.                         draw(drip[i].x, drip[i].y, EMPTY);
  3561.                     }
  3562.                     break;
  3563.                 case KILLER:
  3564.                     drip[i].alive = FALSE;
  3565.                     j = whichkiller(drip[i].x, drip[i].y);
  3566.                     killer[j].alive = FALSE;
  3567.                     field[drip[i].x][drip[i].y] = BONUS;
  3568.                     draw(drip[i].x, drip[i].y, BONUS);
  3569.                     break;
  3570.                 case SLIME:
  3571.                     drip[i].alive = FALSE;
  3572.                     field[drip[i].x][drip[i].y] = EMPTY;
  3573.                     draw(drip[i].x, drip[i].y, EMPTY);
  3574.                     break;
  3575.                 case STONE:
  3576.                     drip[i].alive = FALSE;
  3577.                     break;
  3578.                 case METAL:
  3579.                     drip[i].alive = FALSE;
  3580.                     break;
  3581.                 case TELEPORT:
  3582.                     j = whichteleport(drip[i].x, drip[i].y);
  3583.                     if (blocked(j, 0, 1))
  3584.                         drip[i].alive = FALSE;
  3585.                     else
  3586.                     {    drip[i].x = teleport[level][partner(j)].x;
  3587.                         drip[i].y = teleport[level][partner(j)].y;
  3588.                         drip[i].moved = FALSE;
  3589.                     }
  3590.                     break;
  3591.                 default:
  3592.                     break;
  3593.                 }
  3594.                 if (drip[i].alive)
  3595.                 {    draw(drip[i].x, drip[i].y, drip[i].type);
  3596.                     field[drip[i].x][drip[i].y] = drip[i].type;
  3597. }        }    }    }
  3598.     
  3599. SWORD atleast(SWORD value, SWORD minimum)
  3600. {    if (value < minimum)
  3601.         return(minimum);
  3602.     else return(value);
  3603. }
  3604.  
  3605. void orbscore(SBYTE which, ULONG score)
  3606. {    orb[which].score += score * orb[which].multi;
  3607. }
  3608.  
  3609. // Must have blank line at EOF.
  3610.