home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Games / WormWars / Source / engine.c < prev    next >
C/C++ Source or Header  |  2000-10-07  |  175KB  |  4,778 lines

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