home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / giochi / wormwars / source / engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-22  |  166.4 KB  |  4,645 lines

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