home *** CD-ROM | disk | FTP | other *** search
/ The Amiga Game Guide / AmigaGameGuide_CD.iso / Amiga / PD-Games / WormWars / source / engine.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  155KB  |  4,167 lines

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