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

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