home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Games / wormwars / source / engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-10  |  167.0 KB  |  4,761 lines

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