home *** CD-ROM | disk | FTP | other *** search
- /* $Filename: WormWars/Source/engine.c(pp) $
- * $VER: WormWars 4.4 $
- * $Description: Game engine $
- *
- * © Copyright 1999 James R. Jacobs. Freely distributable.
- */
-
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
-
- #include "stdafx.h"
- #include "diff.h"
- #include "same.h"
- #include "engine.h"
-
- // PRIVATE STRUCTURES -----------------------------------------------------
-
- struct
- { SBYTE x, y, oldx, oldy;
- ABOOL alive, moved, teleported, visible, reflected;
- } bullet[POWERLIMIT + 1];
- struct
- { SBYTE x, y, type;
- ABOOL alive, moved;
- } drip[DRIPS + 1];
- struct
- { SBYTE x, y, deltax, deltay, last;
- ABOOL alive, moved;
- } frag[ORBS + 2][8];
- struct
- { SBYTE x, y, last;
- ABOOL alive;
- } killer[KILLERS + 1];
- struct
- { SBYTE x, y, deltax, deltay;
- ABOOL alive, moved;
- } missile[4];
-
- struct
- { UWORD frequency;
- SLONG score;
- } object[LASTOBJECT + 1] =
- { {1280, 60}, // AFFIXER
- { 80, 20}, // AMMO
- { 110, 20}, // ARMOUR
- { 90, 50}, // BIAS
- { 200, 30}, // BOMB
- { 80, 10}, // BONUS
- {1020, 60}, // CLOCK
- { 360, 50}, // GROWER
- {1900, 90}, // HEALER
- {1360, 60}, // ICE
- { 150, 50}, // LIFE
- { 240, 40}, // MISSILE
- { 640, 50}, // MULTIPLIER
- { 400, 10}, // NITRO
- { 240, 30}, // POWER
- { 480, 50}, // PROTECTOR
- { 600, 40}, // SLAYER
- { 980, 40}, // SLOWER
- { 730, 70}, // SWITCHER
- { 320, 20}, // TONGUE
- {2200, 100}, // TREASURE
- {3600, 100} // UMBRELLA
- };
-
- /* -200 common
- 220-400 uncommon
- 420-980 rare
- 1000+ very rare */
-
- struct
- { SBYTE x, y, deltax, deltay, relx, rely;
- BOOL alive, last, visible;
- } protector[4][PROTECTORS + 1];
- struct
- { SBYTE x, y, time;
- BOOL alive;
- } timebomb[TIMEBOMBS + 1];
- struct
- { SBYTE deltax;
- SBYTE deltay;
- } thequeue[4][QUEUELIMIT + 1];
-
- SBYTE eachworm[4][2][9] =
- { { { GREENHEADUP, GREENHEADUP, GREENHEADUP,
- GREENHEADLEFT, ANYTHING, GREENHEADRIGHT,
- GREENHEADDOWN, GREENHEADDOWN, GREENHEADDOWN
- },
- { GREENMODEUP, GREENMODEUP, GREENMODEUP,
- GREENMODELEFT, ANYTHING, GREENMODERIGHT,
- GREENMODEDOWN, GREENMODEDOWN, GREENMODEDOWN
- } },
- { { REDHEADUP, REDHEADUP, REDHEADUP,
- REDHEADLEFT, ANYTHING, REDHEADRIGHT,
- REDHEADDOWN, REDHEADDOWN, REDHEADDOWN
- },
- { REDMODEUP, REDMODEUP, REDMODEUP,
- REDMODELEFT, ANYTHING, REDMODERIGHT,
- REDMODEDOWN, REDMODEDOWN, REDMODEDOWN
- } },
- { { BLUEHEADUP, BLUEHEADUP, BLUEHEADUP,
- BLUEHEADLEFT, ANYTHING, BLUEHEADRIGHT,
- BLUEHEADDOWN, BLUEHEADDOWN, BLUEHEADDOWN
- },
- { BLUEMODEUP, BLUEMODEUP, BLUEMODEUP,
- BLUEMODELEFT, ANYTHING, BLUEMODERIGHT,
- BLUEMODEDOWN, BLUEMODEDOWN, BLUEMODEDOWN
- } },
- { { YELLOWHEADUP, YELLOWHEADUP, YELLOWHEADUP,
- YELLOWHEADLEFT, ANYTHING, YELLOWHEADRIGHT,
- YELLOWHEADDOWN, YELLOWHEADDOWN, YELLOWHEADDOWN
- },
- { YELLOWMODEUP, YELLOWMODEUP, YELLOWMODEUP,
- YELLOWMODELEFT, ANYTHING, YELLOWMODERIGHT,
- YELLOWMODEDOWN, YELLOWMODEDOWN, YELLOWMODEDOWN
- } } };
-
- // MODULE VARIABLES (used only within engine.c(pp)) -----------------------
-
- MODULE ABOOL letters[4][LETTERS + 1], trainer;
- MODULE SBYTE dripspeed, fragspeed, killerspeed, orbspeed,
- ice, noletter, treasurer;
- MODULE SWORD dripfreq, killerfreq, orbfreq, slimefreq;
-
- // GLOBAL VARIABLES (owned by engine.c(pp), imported by system.c(pp)) -----
-
- AGLOBAL ABOOL clearthem = FALSE,
- modified = FALSE;
- AGLOBAL SBYTE a = GAMEOVER,
- board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
- brush = STONE,
- field[FIELDX + 1][FIELDY + 1], hi = 3,
- level = 1, levels, lo = 0, reallevel,
- startx[MAXLEVELS + 1],
- starty[MAXLEVELS + 1];
- AGLOBAL SWORD secondsleft, secondsperlevel;
- AGLOBAL STRPTR pathname = (STRPTR) DEFAULTSET;
- AGLOBAL ULONG delay, r;
- AGLOBAL struct HiScoreStruct hiscore[HISCORES + 1];
- AGLOBAL struct OrbStruct orb[ORBS + 1];
- AGLOBAL struct TeleportStruct teleport[MAXLEVELS + 1][4];
- AGLOBAL struct WormStruct worm[4];
-
- /* FUNCTIONS --------------------------------------------------------------
-
- NAME align -- right-justify a string within another string
- SYNOPSIS align(STRPTR, SBYTE, TEXT);
- FUNCTION Moves all text in a string to the right, padding with
- spaces. Does not itself add a null terminator.
- INPUTS string - pointer to the string of text
- size - size in characters of the containing string
- filler - what to pad the left of the string with
- NOTE Null terminators are written over by thissy function, but that
- does not matter, because calling functions use Text() with an
- explicit length. This function only works with monospaced
- fonts.
- MODULE engine.c */
-
- void align(STRPTR string, SBYTE size, TEXT filler)
- { SBYTE i, shift, length;
-
- length = strlen((const char*) string);
- shift = size - length;
- for (i = 1; i <= length; i++)
- *(string + size - i) = *(string + size - i - shift);
- for (i = 0; i <= shift - 1; i++)
- *(string + i) = filler;
- }
-
- ABOOL blocked(SBYTE which, SBYTE deltax, SBYTE deltay)
- { SBYTE thissy;
-
- thissy = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
- if ((thissy < STONE || thissy > KILLER) && thissy != METAL)
- return(FALSE);
- else return(TRUE);
- }
-
- void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
- { SBYTE counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
- SLONG score = 0L;
-
- effect(FXBOMBBLAST);
-
- strength = BOMBADD + (rand() % BOMBRAND);
-
- leftxmax = centrex - strength;
- if (leftxmax < 0)
- leftxmax = 0;
- rightxmax = centrex + strength;
- if (rightxmax > FIELDX)
- rightxmax = FIELDX;
- uppymax = centrey - strength;
- if (uppymax < 0)
- uppymax = 0;
- downymax = centrey + strength;
- if (downymax > FIELDY)
- downymax = FIELDY;
-
- leftx = centrex;
- rightx = centrex;
- uppy = centrey;
- downy = centrey;
- for (counter = 1; counter <= strength; counter++)
- { if (leftx > leftxmax)
- { leftx--;
- for (y = uppy; y <= downy; y++)
- score += squareblast(triggerer, player, field[leftx][y], leftx, y);
- }
- if (rightx < rightxmax)
- { rightx++;
- for (y = uppy; y <= downy; y++)
- score += squareblast(triggerer, player, field[rightx][y], rightx, y);
- }
- if (uppy > uppymax)
- { uppy--;
- for (x = leftx; x <= rightx; x++)
- score += squareblast(triggerer, player, field[x][uppy], x, uppy);
- }
- if (downy < downymax)
- { downy++;
- for (x = leftx; x <= rightx; x++)
- score += squareblast(triggerer, player, field[x][downy], x, downy);
- } }
-
- if (triggerer == HEAD)
- { wormscore(player, score);
- if (worm[player].bias)
- stat(player, LIFE);
- } else
- orbscore(player, score);
- }
-
- void bouncekiller(SBYTE which, SBYTE x, SBYTE y)
- { SBYTE i;
-
- if (field[x][y] == KILLER)
- for (i = 0; i <= KILLERS; i++)
- if (killer[i].alive && x == killer[i].x && y == killer[i].y)
- { killer[i].alive = FALSE;
- draw(x, y, BONUS);
- field[x][y] = BONUS;
- orbscore(which, KILLKILLER);
- } }
-
- ABOOL bounceorb(SBYTE which, SBYTE x, SBYTE y)
- { if (field[x][y] == METAL)
- return TRUE;
- elif (orb[which].mode == NONE)
- { if (field[x][y] >= FIRSTNONE && field[x][y] <= LASTNONE)
- return TRUE;
- else return FALSE;
- } elif (orb[which].mode == TONGUE)
- { if (field[x][y] >= FIRSTTONGUE && field[x][y] <= LASTTONGUE)
- return TRUE;
- else return FALSE;
- } else // assumes orb[which].mode == ARMOUR
- { if (field[x][y] >= FIRSTARMOUR && field[x][y] <= LASTARMOUR)
- return TRUE;
- else return FALSE;
- } }
-
- SBYTE bsign(SBYTE value)
- { if (value < 0)
- return (-1);
- elif (value > 0)
- return (1);
- else
- return (0);
- }
-
- void changefield(void)
- { SBYTE x, y;
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- field[x][y] = board[level][x][y];
- }
-
- void clearhiscores(void)
- { SBYTE i;
-
- clearthem = FALSE;
- for (i = 0; i <= HISCORES; i++)
- { hiscore[i].player = -1;
- hiscore[i].level = 0;
- hiscore[i].score = 0L;
- hiscore[i].name[0] = 0;
- hiscore[i].fresh = FALSE;
- } }
-
- void clearletters(void)
- { SBYTE player, which;
-
- for (player = 0; player <= 3; player++)
- for (which = 0; which <= LETTERS; which++)
- { letters[player][which] = FALSE;
- drawletter(player, FIRSTLETTER + which, BLACK);
- } }
-
- void copyfield(SBYTE source, SBYTE destination)
- { SBYTE which, x, y;
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- board[destination][x][y] = board[source][x][y];
- startx[destination] = startx[source];
- starty[destination] = starty[source];
- for (which = 0; which <= 1; which++)
- { teleport[destination][which].alive = teleport[source][which].alive;
- teleport[destination][which].x = teleport[source][which].x;
- teleport[destination][which].y = teleport[source][which].y;
- } }
-
- void death(void)
- { SBYTE counter, i, pain, player, survivor, which;
- ABOOL flag, slow;
-
- for (player = lo; player <= hi; player++)
- { if (worm[player].lives)
- { if (!worm[player].alive)
- { slow = FALSE;
- pain = 0;
- if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
- { if (player == worm[player].cause - FIRSTTAIL)
- pain = TAILPAIN;
- else pain = OTHERTAILPAIN;
- slow = TRUE;
- } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
- pain = WORMFIREPAIN;
- elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
- pain = HEADPAIN;
- elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
- pain = PROTECTORPAIN;
- elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
- pain = MISSILEPAIN;
- elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
- pain = DRIPPAIN;
- else switch (worm[player].cause)
- {
- case BOMB:
- pain = BOMBPAIN;
- break;
- case WOOD:
- pain = WOODPAIN;
- slow = TRUE;
- break;
- case FRAGMENT:
- pain = FRAGMENTPAIN;
- break;
- case KILLER:
- pain = KILLERPAIN;
- slow = TRUE;
- break;
- case SLAYER:
- pain = SLAYERPAIN;
- break;
- case STONE:
- pain = STONEPAIN;
- slow = TRUE;
- break;
- case TELEPORT:
- pain = TELEPORTPAIN;
- slow = TRUE;
- break;
- case SLIME:
- pain = SLIMEPAIN;
- slow = TRUE;
- break;
- case METAL:
- pain = METALPAIN;
- slow = TRUE;
- break;
- default:
- break;
- }
- if (worm[player].victor >= 0 && worm[player].victor != player)
- { wormscore(worm[player].victor, KILLWORM);
- if (worm[worm[player].victor].bias)
- { worm[worm[player].victor].lives += pain;
- stat(worm[player].victor, LIFE);
- } }
- if (slow)
- { worm[player].speed = slowdown(worm[player].speed);
- stat(player, NITRO);
- }
- if (pain > worm[player].lives)
- worm[player].lives = 0;
- else worm[player].lives -= pain;
- draw(worm[player].x, worm[player].y, SKULL);
- drawcause(player, NORMAL);
- stat(player, LIFE);
- if (level)
- worm[player].levelreached = level;
- else worm[player].levelreached = reallevel;
- if (worm[player].lives)
- { flag = FALSE;
- for (i = lo; i <= hi; i++)
- if (worm[i].control == HUMAN)
- flag = TRUE;
- if (!flag || worm[player].control == HUMAN)
- effect(FXPAIN + player);
- // Amiga-worms only make pain sounds in demo mode
- worm[player].alive = TRUE;
- worm[player].causewait = r + CAUSEWAIT;
- } else
- { // kill worm
-
- effect(FXWORMDEATH);
- if (ice == player)
- ice = -1;
- field[worm[player].x][worm[player].y] = SKULL;
- for (which = 0; which <= PROTECTORS; which++)
- { if (protector[player][which].alive && protector[player][which].visible)
- { draw(protector[player][which].x, protector[player][which].y, EMPTY);
- field[protector[player][which].x][protector[player][which].y] = EMPTY;
- } }
- counter = 0;
- for (which = lo; which <= hi; which++)
- if (worm[which].lives)
- { survivor = which;
- counter++;
- }
- if (counter == 1)
- wormscore(survivor, SURVIVOR);
- } } } }
- if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
- { // End of game
- newhiscores();
- effect(FXDEFEAT);
- a = GAMEOVER;
- if (lo == hi)
- say((STRPTR) "Game over!", worm[lo].colour);
- 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))
- say((STRPTR) "Green wins!", GREEN);
- 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))
- say((STRPTR) "Red wins!", RED);
- 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))
- say((STRPTR) "Blue wins!", BLUE);
- 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))
- say((STRPTR) "Yellow wins!", YELLOW);
- else say((STRPTR) "A draw!", WHITE);
- waitasec();
- anykey(FALSE);
- } }
-
- void drawcause(SBYTE player, SBYTE state)
- { if (state == BLACK)
- draw(-2 + ((FIELDX + 4) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), BLACKENED);
- else draw(-2 + ((FIELDX + 4) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), worm[player].cause);
- }
-
- void drawletter(SBYTE player, SBYTE letter, SBYTE state)
- { SBYTE thissy;
-
- if (state == BLACK)
- thissy = BLACKENED;
- else thissy = letter;
- if (!worm[player].statx)
- if (!worm[player].staty)
- draw(-7 + ((letter - FIRSTLETTER) % 4),
- (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
- thissy);
- else
- draw(-7 + ((letter - FIRSTLETTER) % 4),
- (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
- thissy);
- else
- if (!worm[player].staty)
- draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
- (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
- thissy);
- else
- draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
- (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
- thissy);
- }
-
- /* NAME enginesetup -- once-only initialization of engine variables
- SYNOPSIS enginesetup(void);
- FUNCTION Sets up the unchanging worm variables.
- MODULE engine.c */
-
- void enginesetup(void)
- { worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
- worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
- worm[0].colour = GREEN;
- worm[1].colour = RED;
- worm[2].colour = BLUE;
- worm[3].colour = YELLOW;
- worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
-
- systemsetup();
- }
-
- /* NAME fastloop -- things done often
- SYNOPSIS fastloop(void);
- FUNCTION Checks for and handles level completion.
- MODULE engine.c */
-
- void fastloop(void)
- { ABOOL complete;
- SBYTE advancer = -1, player, which;
-
- // handle level completion
-
- for (player = lo; player <= hi; player++)
- { complete = TRUE;
- for (which = 0; which <= LETTERS; which++)
- if (!letters[player][which])
- complete = FALSE;
- if (complete)
- advancer = player;
- }
- if (advancer != -1)
- { if (level++ == 0)
- { level = reallevel + 1;
- reallevel = 0;
- }
- stopfx(0L);
- if (level > levels)
- effect(FXVICTORY);
- newlevel(advancer);
- } }
-
- void fillfield(SBYTE which)
- { SBYTE x, y;
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- { board[level][x][y] = which;
- draw(x, y, which);
- }
- board[level][startx[level]][starty[level]] = EMPTY;
- draw(startx[level], starty[level], START);
- if (teleport[level][0].alive)
- { board[level][teleport[level][0].x][teleport[level][0].y] = TELEPORT;
- draw(teleport[level][0].x, teleport[level][0].y, ONE);
- }
- if (teleport[level][1].alive)
- { board[level][teleport[level][1].x][teleport[level][1].y] = TELEPORT;
- draw(teleport[level][1].x, teleport[level][1].y, TWO);
- } }
-
- ABOOL findempty(SBYTE* x, SBYTE* y, SBYTE first, SBYTE last)
- { SBYTE count = 0, xx, yy;
-
- do
- { xx = rand() % (FIELDX + 1);
- yy = rand() % (FIELDY + 1);
- } while ((field[xx][yy] < first || field[xx][yy] > last) && ++count < PATIENCE);
- if (count < PATIENCE)
- { *x = xx;
- *y = yy;
- return(TRUE);
- } else return(FALSE);
- }
-
- /* NAME fragloop -- controls fragments
- SYNOPSIS fragloop(void);
- FUNCTION Controls all fragments.
- MODULE engine.c */
-
- void fragloop(void)
- { SBYTE i, j, k, thissy, which;
-
- for (which = 0; which <= ORBS + 1; which++)
- for (i = 0; i <= 7; i++)
- if (frag[which][i].alive)
- { if (frag[which][i].moved)
- { draw(frag[which][i].x, frag[which][i].y, frag[which][i].last);
- field[frag[which][i].x][frag[which][i].y] = frag[which][i].last;
- } else frag[which][i].moved = TRUE;
- frag[which][i].x += frag[which][i].deltax;
- frag[which][i].y += frag[which][i].deltay;
- if (!(valid(frag[which][i].x, frag[which][i].y)))
- frag[which][i].alive = FALSE;
- else
- { thissy = field[frag[which][i].x][frag[which][i].y];
- if (thissy >= FIRSTFRAGDEATH && thissy <= LASTFRAGDEATH)
- { effect(FXTHUD);
- frag[which][i].alive = FALSE;
- if (thissy == KILLER)
- { effect(FXKILLERDEATH);
- j = whichkiller(frag[which][i].x, frag[which][i].y);
- killer[j].alive = FALSE;
- field[killer[j].x][killer[j].y] = BONUS;
- draw(killer[j].x, killer[j].y, BONUS);
- } }
- elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { effect(FXUSEPROTECTOR);
- reflect(which, i);
- } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { frag[which][i].alive = FALSE;
- missile[thissy - FIRSTMISSILE].alive = FALSE;
- field[missile[thissy - FIRSTMISSILE].x][missile[thissy - FIRSTMISSILE].y] = EMPTY;
- draw(missile[thissy - FIRSTMISSILE].x, missile[thissy - FIRSTMISSILE].y, EMPTY);
- } elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { worm[thissy - FIRSTHEAD].cause = FRAGMENT;
- worm[thissy - FIRSTHEAD].victor = -1;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- } else
- { effect(FXUSEARMOUR);
- reflect(which, i);
- } }
- elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { j = whichdrip(frag[which][i].x, frag[which][i].y);
- drip[j].alive = FALSE;
- frag[which][i].alive = FALSE;
- field[frag[which][i].x][frag[which][i].y] = BONUS;
- draw(frag[which][i].x, frag[which][i].y, BONUS);
- } else switch(thissy)
- {
- case METAL:
- reflect(which, i);
- break;
- case ORB:
- j = whichorb(frag[which][i].x, frag[which][i].y);
- if (orb[j].mode != ARMOUR)
- orb[j].explode = TRUE;
- else effect(FXUSEARMOUR);
- frag[which][i].alive = FALSE;
- break;
- case TELEPORT:
- j = whichteleport(frag[which][i].x, frag[which][i].y);
- if (blocked(j, frag[which][i].deltax, frag[which][i].deltay))
- frag[which][i].alive = FALSE;
- else
- { effect(FXUSETELEPORT);
- frag[which][i].x = xwrap(teleport[level][partner(j)].x + frag[which][i].deltax);
- frag[which][i].y = ywrap(teleport[level][partner(j)].y + frag[which][i].deltay);
- frag[which][i].last = SILVER;
- }
- break;
- case BOMB:
- j = whichtimebomb(frag[which][i].x, frag[which][i].y);
- if (j != -1)
- { frag[which][i].alive = FALSE;
- timebomb[j].alive = FALSE;
- field[timebomb[j].x][timebomb[j].y] = EMPTY;
- draw(timebomb[j].x, timebomb[j].y, EMPTY);
- bombblast(BOMB, 0, timebomb[j].x, timebomb[j].y);
- }
- break;
- case FRAGMENT:
- effect(FXTHUD);
- draw(frag[which][i].x, frag[which][i].y, EMPTY);
- frag[which][i].alive = FALSE;
- whichfrag(frag[which][i].x, frag[which][i].y, &j, &k);
- frag[j][k].alive = FALSE;
- break;
- default:
- break;
- }
- if (frag[which][i].alive)
- { field[frag[which][i].x][frag[which][i].y] = FRAGMENT;
- draw(frag[which][i].x, frag[which][i].y, FRAGMENT);
- } } }
- }
-
- void gameloop(void)
- { SBYTE player, which;
-
- fastloop();
- gameinput();
- for (player = lo; player <= hi; player++)
- if (worm[player].lives && !(r % worm[player].speed) && (ice == -1 || ice == player))
- wormloop(player);
- if (ice == -1)
- { for (which = 0; which <= ORBS; which++)
- if (orb[which].alive && !(r % orb[which].speed))
- if (orb[which].explode)
- orbexplosion(which);
- else orbloop(which);
- if (!(r % killerspeed))
- killerloop();
- if (!(r % dripspeed))
- driploop();
- if (!(r % fragspeed))
- fragloop();
- if (!(r % MISSILESPEED))
- missileloop();
- }
- if (a == PLAYGAME)
- { death();
- if (!(r % VERYSLOW))
- slowloop();
- }
- timing();
- }
-
- void killall(void)
- { SBYTE iwhich, which;
-
- for (which = 0; which <= ORBS; which++)
- orb[which].alive = FALSE;
- for (which = 0; which <= KILLERS; which++)
- killer[which].alive = FALSE;
- for (which = 0; which <= ORBS + 1; which++)
- for (iwhich = 0; iwhich <= 7; iwhich++)
- frag[which][iwhich].alive = FALSE;
- for (which = 0; which <= 3; which++)
- if (missile[which].alive)
- missile[which].alive = FALSE;
- for (which = 0; which <= TIMEBOMBS; which++)
- timebomb[which].alive = FALSE;
- teleport[level][2].alive = FALSE;
- teleport[level][3].alive = FALSE;
- }
-
- void killerloop(void)
- { ABOOL happy;
- UBYTE count;
- SBYTE which, x, xx, y, yy;
-
- for (which = 0; which <= KILLERS; which++)
- if (killer[which].alive)
- { happy = FALSE;
- for (x = killer[which].x - 1; x <= killer[which].x + 1; x++)
- for (y = killer[which].y - 1; y <= killer[which].y + 1; y++)
- if (field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
- happy = TRUE;
- if ((!happy) || (!(rand() % RESTFULNESS)))
- { x = (rand() % 3) - 1;
- y = (rand() % 3) - 1;
- if (valid(killer[which].x + x, killer[which].y + y) && (x || y)
- && field[killer[which].x + x][killer[which].y + y] >= FIRSTKILLER && field[killer[which].x + x][killer[which].y + y] <= LASTKILLER && field[killer[which].x + x][killer[which].y + y] != KILLER)
- { field[killer[which].x][killer[which].y] = killer[which].last;
- draw(killer[which].x, killer[which].y, killer[which].last);
- killer[which].x += x;
- killer[which].y += y;
- killer[which].last = field[killer[which].x][killer[which].y];
- field[killer[which].x][killer[which].y] = KILLER;
- draw(killer[which].x, killer[which].y, KILLER);
- } }
- if (!frag[ORBS + 1][which].alive && !(rand() % KILLERFIREFREQ))
- { count = 0;
- do
- { x = (rand() % 3) - 1;
- y = (rand() % 3) - 1;
- xx = killer[which].x + x;
- yy = killer[which].y + y;
- } while (((!x && !y) || xx < 0 || xx > FIELDX || yy < 0 || yy > FIELDY || field[xx][yy] > LASTKILLERFIRE) && ++count < PATIENCE);
- if (count < PATIENCE)
- { effect(FXKILLERFIRE);
- frag[ORBS + 1][which].alive = TRUE;
- frag[ORBS + 1][which].x = killer[which].x;
- frag[ORBS + 1][which].y = killer[which].y;
- frag[ORBS + 1][which].deltax = x;
- frag[ORBS + 1][which].deltay = y;
- frag[ORBS + 1][which].moved = FALSE;
- frag[ORBS + 1][which].last = EMPTY;
- } } } }
-
- void levelappend(void)
- { UBYTE oldlevel;
-
- if (levels < MAXLEVELS)
- { oldlevel = level;
- level = ++levels;
- newfield();
- level = oldlevel;
- saylevel(WHITE);
- } }
-
- void leveldelete(void)
- { SBYTE i;
-
- // pull boards
-
- if (levels > 1)
- { if (level < levels)
- for (i = level; i < levels; i++)
- copyfield(i + 1, i);
- else
- level--;
- levels--;
- saylevel(WHITE);
- renderboard();
- } }
-
- void levelerase(void)
- { newfield();
- renderboard();
- }
-
- void levelinsert(void)
- { SBYTE i;
-
- // push boards
-
- if (levels < MAXLEVELS)
- { for (i = levels; i >= level; i--)
- copyfield(i, i + 1);
- levels++;
- saylevel(WHITE);
- newfield();
- renderboard();
- } }
-
- ABOOL loadfields(STRPTR fieldname)
- { SBYTE i, j, x, y;
- TEXT IOBuffer[NAMELENGTH + 1];
- UBYTE ver;
-
- /* This routine is not entirely robust, especially regarding
- failures part way through reading. Also, field data values must be
- those supported by the field editor (ie. objects, and the squares
- represented by F1-F8), or undefined behaviour may result. None of
- this is currently checked for. Provided that the fieldset was
- created with the field editor (4.1+), and the file is not corrupt,
- these failures should never happen anyway.
-
- open file */
-
- if (!ZOpen(fieldname, FALSE))
- return FALSE; // fail point 1: no harm done
-
- // read header
-
- if (!ZRead(IOBuffer, 10))
- { ZClose();
- return FALSE; // fail point 2: no harm done
- }
- if (!strcmp(IOBuffer, "FSET 4.4"))
- ver = 44;
- elif (!strcmp(IOBuffer, "FSET 4.3"))
- ver = 43;
- elif (!strcmp(IOBuffer, "FSET 4.2"))
- ver = 42;
- elif (!stricmp(IOBuffer, "FSET 4.1"))
- ver = 41;
- else
- { ZClose();
- return FALSE; // fail point 3: no harm done
- }
- levels = IOBuffer[9];
-
- // read high score table
-
- for (i = 0; i <= HISCORES; i++)
- { if (!ZRead(IOBuffer, 6))
- { ZClose();
- return FALSE; // fail point 4: incorrect levels
- }
- hiscore[i].fresh = FALSE;
- hiscore[i].player = IOBuffer[0];
- hiscore[i].level = IOBuffer[1];
- hiscore[i].score = (IOBuffer[3] * 65536)
- + (IOBuffer[4] * 256)
- + IOBuffer[5];
-
- if (!ZRead(IOBuffer, NAMELENGTH + 1))
- { ZClose();
- return FALSE;
- // fail point 5: incorrect levels, corrupted high scores
- }
- for (j = 0; j <= NAMELENGTH; j++)
- hiscore[i].name[j] = IOBuffer[j];
- }
-
- // read level data
-
- for (i = 0; i <= levels; i++)
- { if (!ZRead(IOBuffer, 8))
- { ZClose();
- return FALSE;
- /* fail point 6: incorrect levels, corrupted high scores,
- incorrect startx, teleports, field data */
- }
- startx[i] = IOBuffer[0];
- starty[i] = IOBuffer[1];
- teleport[i][0].alive = IOBuffer[2];
- teleport[i][0].x = IOBuffer[3];
- teleport[i][0].y = IOBuffer[4];
- teleport[i][1].alive = IOBuffer[5];
- teleport[i][1].x = IOBuffer[6];
- teleport[i][1].y = IOBuffer[7];
-
- if (!ZRead((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
- { ZClose();
- return FALSE;
- /* fail point 7: incorrect levels, corrupted high scores,
- incorrect startx, teleports, field data */
- } else
- { if (ver == 41)
- { // convert from FSET 4.1 to FSET 4.2 format
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (board[i][x][y] == 18) // old HEALER
- board[i][x][y] = 7; // new HEALER
- elif (board[i][x][y] >= 7)
- board[i][x][y]++;
- }
- if (ver == 41 || ver == 42)
- { // convert from FSET 4.2 to FSET 4.3 format
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (board[i][x][y] >= CLOCK && board[i][x][y] <= FX)
- board[i][x][y]++;
- }
- if (ver >= 41 && ver <= 43)
- { // convert from FSET 4.3 to FSET 4.4 format
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (board[i][x][y] >= 17)
- board[i][x][y]++;
- } } }
-
- // no need to read version string
-
- ZClose();
- modified = FALSE;
- return TRUE;
- }
-
- void matchteleports(void)
- { SBYTE which;
-
- for (which = 0; which <= levels; which++)
- if (teleport[which][0].alive == TRUE && teleport[which][1].alive == FALSE)
- { board[which][teleport[which][0].x][teleport[which][0].y] = EMPTY;
- teleport[which][0].alive = FALSE;
- if (level == which && a == FIELDEDIT)
- draw(teleport[which][0].x, teleport[which][0].y, EMPTY);
- } elif (teleport[which][0].alive == FALSE && teleport[which][1].alive == TRUE)
- { board[which][teleport[which][1].x][teleport[which][1].y] = EMPTY;
- teleport[which][1].alive = FALSE;
- if (level == which && a == FIELDEDIT)
- draw(teleport[which][1].x, teleport[which][1].y, EMPTY);
- } }
-
- /* NAME missileloop -- controls missiles
- SYNOPSIS missileloop(void);
- FUNCTION Controls all killers.
- MODULE engine.c */
-
- void missileloop(void)
- { SBYTE distx, disty, distance, iwhich, player, thissy, which;
- UBYTE bestdistance;
-
- for (player = lo; player <= hi; player++)
- { if (missile[player].alive && (ice == -1 || ice == player))
- { bestdistance = (UBYTE) -1;
- for (which = lo; which <= hi; which++)
- if (which != player && worm[which].lives > 0 && !worm[which].bias)
- { distx = abs(worm[which].x - missile[player].x);
- disty = abs(worm[which].y - missile[player].y);
- if (distx < disty)
- distance = distx;
- else distance = disty;
- if (distance <= bestdistance)
- { bestdistance = distance;
- missile[player].deltax = bsign(worm[which].x - missile[player].x);
- missile[player].deltay = bsign(worm[which].y - missile[player].y);
- } }
- for (which = lo; which <= hi; which++)
- if (which != player && missile[which].alive)
- { distx = abs(missile[which].x - missile[player].x);
- disty = abs(missile[which].y - missile[player].y);
- if (distx < disty)
- distance = distx;
- else distance = disty;
- if (distance <= bestdistance)
- { bestdistance = distance;
- missile[player].deltax = bsign(missile[which].x - missile[player].x);
- missile[player].deltay = bsign(missile[which].y - missile[player].y);
- } }
- for (which = 0; which <= ORBS; which++)
- if (orb[which].alive)
- { distx = abs(orb[which].x - missile[player].x) * 2;
- disty = abs(orb[which].y - missile[player].y) * 2;
- if (distx < disty)
- distance = distx;
- else distance = disty;
- if (distance <= bestdistance)
- { bestdistance = distance;
- missile[player].deltax = bsign(orb[which].x - missile[player].x);
- missile[player].deltay = bsign(orb[which].y - missile[player].y);
- } }
- for (which = 0; which <= KILLERS; which++)
- if (killer[which].alive)
- { distx = abs(killer[which].x - missile[player].x) * 2;
- disty = abs(killer[which].y - missile[player].y) * 2;
- if (distx < disty)
- distance = distx;
- else distance = disty;
- if (distance <= bestdistance)
- { bestdistance = distance;
- missile[player].deltax = bsign(killer[which].x - missile[player].x);
- missile[player].deltay = bsign(killer[which].y - missile[player].y);
- } }
- if (missile[player].moved)
- { draw(missile[player].x, missile[player].y, EMPTY);
- field[missile[player].x][missile[player].y] = EMPTY;
- } else missile[player].moved = TRUE;
- if (bestdistance == (UBYTE) -1)
- missile[player].alive = FALSE;
- else
- { missile[player].x += missile[player].deltax;
- missile[player].y += missile[player].deltay;
- thissy = field[missile[player].x][missile[player].y];
- if (thissy >= FIRSTLETTER && thissy <= WOOD)
- { missile[player].alive = FALSE;
- if (thissy == KILLER)
- { effect(FXKILLERDEATH);
- which = whichkiller(missile[player].x, missile[player].y);
- killer[which].alive = FALSE;
- field[killer[which].x][killer[which].y] = BONUS;
- draw(killer[which].x, killer[which].y, BONUS);
- wormscore(player, KILLKILLER);
- if (worm[player].bias)
- { worm[player].lives += KILLERBLOOD;
- stat(player, LIFE);
- } } }
- elif (thissy == FRAGMENT)
- { missile[player].alive = FALSE;
- whichfrag(missile[player].x, missile[player].y, &which, &iwhich);
- frag[which][iwhich].alive = FALSE;
- draw(missile[player].x, missile[player].y, EMPTY);
- } elif (thissy == ORB)
- { missile[player].alive = FALSE;
- which = whichorb(missile[player].x, missile[player].y);
- if (orb[which].mode != ARMOUR)
- { effect(FXORBDEATH);
- orb[which].alive = FALSE;
- draw(orb[which].x, orb[which].y, BONUS);
- field[orb[which].x][orb[which].y] = BONUS;
- wormscore(player, orb[which].score);
- if (worm[player].bias)
- { worm[player].lives += ORBBLOOD;
- stat(player, LIFE);
- }
- } else effect(FXUSEARMOUR);
- } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { if (player != thissy - FIRSTPROTECTOR)
- { effect(FXUSEPROTECTOR);
- missile[player].alive = FALSE;
- } }
- elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- missile[player].alive = FALSE;
- elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { missile[player].alive = FALSE;
- if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { worm[thissy - FIRSTHEAD].cause = FIRSTMISSILE + player;
- worm[thissy - FIRSTHEAD].victor = player;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- } else effect(FXUSEARMOUR);
- } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { missile[player].alive = FALSE;
- missile[thissy - FIRSTMISSILE].alive = FALSE;
- field[missile[which].x][missile[which].y] = BONUS;
- draw(missile[which].x, missile[which].y, BONUS);
- } elif (thissy == TELEPORT)
- { which = whichteleport(missile[player].x, missile[player].y);
- if (blocked(which, missile[player].deltax, missile[player].deltay))
- missile[player].alive = FALSE;
- else
- { effect(FXUSETELEPORT);
- missile[player].x = xwrap(teleport[level][partner(which)].x + missile[player].deltax);
- missile[player].y = ywrap(teleport[level][partner(which)].y + missile[player].deltay);
- } }
- elif (thissy == BOMB)
- { which = whichtimebomb(missile[player].x, missile[player].y);
- if (which != -1)
- { missile[player].alive = FALSE;
- timebomb[which].alive = FALSE;
- field[timebomb[which].x][timebomb[which].y] = EMPTY;
- draw(timebomb[which].x, timebomb[which].y, EMPTY);
- bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
- } }
- elif (thissy == SKULL || thissy == METAL)
- missile[player].alive = FALSE;
- if (missile[player].alive)
- { draw(missile[player].x, missile[player].y, FIRSTMISSILE + player);
- field[missile[player].x][missile[player].y] = FIRSTMISSILE + player;
- } } } } }
-
- void newfield(void)
- { int x, y;
-
- teleport[level][0].alive = FALSE;
- teleport[level][1].alive = FALSE;
- startx[level] = FIELDX / 2;
- starty[level] = FIELDY / 2;
-
- if (level)
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- board[level][x][y] = EMPTY;
- else for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- board[0][x][y] = SILVER;
- }
-
- void newfields(void)
- { if (verify())
- { pathname = (STRPTR) DEFAULTSET;
- levels = DEFAULTLEVELS;
- modified = FALSE;
- for (level = 0; level <= levels; level++)
- newfield();
- clearhiscores();
- level = 1;
- if (a == FIELDEDIT)
- { renderboard();
- saylevel(WHITE);
- } else
- hiscores();
- } }
-
- void newgame(void)
- { SBYTE player;
-
- if (worm[0].control != NONE)
- lo = 0;
- elif (worm[1].control != NONE)
- lo = 1;
- elif (worm[2].control != NONE)
- lo = 2;
- else lo = 3;
- if (worm[3].control != NONE)
- hi = 3;
- elif (worm[2].control != NONE)
- hi = 2;
- elif (worm[1].control != NONE)
- hi = 1;
- else hi = 0;
-
- for (player = 0; player <= 3; player++)
- worm[player].lives = 0;
-
- r = -1;
- trainer = FALSE;
- ice = -1;
- reallevel = 0;
- level = 1;
- a = PLAYGAME;
- clearstats();
- newlevel(rand() % 4);
- timing();
- }
-
- void newhiscores(void)
- {
- PERSIST TEXT amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R.J. Mical", "Dave Morse"};
- SBYTE iwhich, player, which;
-
- for (player = lo; player <= hi; player++)
- for (which = 0; which <= HISCORES; which++)
- if (worm[player].control != NONE && worm[player].score >= hiscore[which].score)
- { // push all worse hiscores down
-
- if (which < HISCORES)
- for (iwhich = HISCORES; iwhich >= which + 1; iwhich--)
- { hiscore[iwhich].player = hiscore[iwhich - 1].player;
- hiscore[iwhich].score = hiscore[iwhich - 1].score;
- hiscore[iwhich].level = hiscore[iwhich - 1].level;
- hiscore[iwhich].fresh = hiscore[iwhich - 1].fresh;
- strcpy(hiscore[iwhich].name, hiscore[iwhich - 1].name);
- }
-
- modified = TRUE;
- hiscore[which].player = player;
- hiscore[which].score = worm[player].score;
- hiscore[which].level = worm[player].levelreached;
- if (worm[player].control == AMIGA)
- { strcpy(hiscore[which].name, amiganame[player]);
- hiscore[which].fresh = FALSE;
- } else
- { strcpy(hiscore[which].name, "(New)");
- hiscore[which].fresh = TRUE;
- }
- break;
- } }
-
- void newlevel(SBYTE player)
- { SBYTE iwhich, which;
-
- if (level >= 2 && worm[player].lives)
- rundown(player);
- if (a == PLAYGAME)
- { if (level > levels)
- { for (which = lo; which <= hi; which++)
- if (worm[which].lives)
- worm[which].levelreached = -1;
- celebrate();
- newhiscores();
- titlescreen();
- } else
- { saylevel(WHITE);
- for (which = lo; which <= hi; which++)
- worm[which].multi = (SBYTE) atleast(worm[which].multi / 2, 1);
- killall();
- clearletters();
- orientworms();
- changefield();
- renderboard();
- dripspeed = (SBYTE) atleast( DRIPSPEED_MAX - (level / DRIPSPEED_DIV), VERYFAST);
- fragspeed = (SBYTE) atleast( FRAGSPEED_MAX - (level / FRAGSPEED_DIV), VERYFAST);
- killerspeed = (SBYTE) atleast(KILLERSPEED_MAX - (level / KILLERSPEED_DIV), VERYFAST);
- orbspeed = (SBYTE) atleast( ORBSPEED_MAX - (level / ORBSPEED_DIV), VERYFAST);
- dripfreq = atleast( DRIPFREQ_MAX - (level * DRIPFREQ_DEC), DRIPFREQ_MIN);
- killerfreq = atleast( KILLERFREQ_MAX - (level * KILLERFREQ_DEC), KILLERFREQ_MIN);
- orbfreq = atleast( ORBFREQ_MAX - (level * ORBFREQ_DEC), ORBFREQ_MIN);
- slimefreq = atleast( SLIMEFREQ_MAX - (level * SLIMEFREQ_DEC), SLIMEFREQ_MIN);
- delay = atleast( DELAY_MAX - (level * DELAY_DEC), DELAY_MIN);
-
- if (level)
- { secondsperlevel = SECONDSPERLEVEL;
- putletter(-1);
- for (which = 0; which <= 3; which++)
- { if (!worm[which].lives && worm[which].control != NONE)
- { // create (or resurrect) a worm
-
- worm[which].lives = STARTLIVES;
- worm[which].score = 0;
- worm[which].alive = TRUE;
- worm[which].oldscore = 0;
- worm[which].armour = 0;
- worm[which].tongue = 0;
- worm[which].nitro = FALSE;
- worm[which].mode = NULL;
- worm[which].power = 0;
- worm[which].bias = 0;
- worm[which].multi = 1;
- worm[which].ice = 0;
- worm[which].victor = -1;
- worm[which].ammo = 0;
- worm[which].affixer = FALSE;
- worm[which].causewait = (ULONG) -1;
- worm[which].last = FIRSTTAIL + which;
- worm[which].pos = -1;
- for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
- protector[which][iwhich].alive = FALSE;
- for (iwhich = 0; iwhich <= LASTOBJECT; iwhich++)
- stat(which, iwhich);
- } } } } }
- clearjoystick();
- clearkybd();
- resettime();
- }
-
- void orbexplosion(SBYTE which)
- { SBYTE iwhich;
-
- effect(FXEXPLODE);
- orb[which].alive = FALSE;
- for (iwhich = 0; iwhich <= 7; iwhich++)
- { frag[which][iwhich].alive = TRUE;
- frag[which][iwhich].x = orb[which].x;
- frag[which][iwhich].y = orb[which].y;
- frag[which][iwhich].moved = TRUE;
- frag[which][iwhich].last = EMPTY;
- switch (iwhich)
- {
- case 0:
- frag[which][iwhich].deltax = 0;
- frag[which][iwhich].deltay = -1;
- break;
- case 1:
- frag[which][iwhich].deltax = 1;
- frag[which][iwhich].deltay = -1;
- break;
- case 2:
- frag[which][iwhich].deltax = 1;
- frag[which][iwhich].deltay = 0;
- break;
- case 3:
- frag[which][iwhich].deltax = 1;
- frag[which][iwhich].deltay = 1;
- break;
- case 4:
- frag[which][iwhich].deltax = 0;
- frag[which][iwhich].deltay = 1;
- break;
- case 5:
- frag[which][iwhich].deltax = -1;
- frag[which][iwhich].deltay = 1;
- break;
- case 6:
- frag[which][iwhich].deltax = -1;
- frag[which][iwhich].deltay = 0;
- break;
- case 7:
- frag[which][iwhich].deltax = -1;
- frag[which][iwhich].deltay = -1;
- break;
- default:
- break;
- } } }
-
- /* NAME orbloop -- controls orbs
- SYNOPSIS orbloop(SBYTE);
- FUNCTION Controls an orb.
- MODULE engine.c */
-
- void orbloop(SBYTE which) {
- SBYTE frontx, fronty, iiwhich, iwhich, player, newdeltax, newdeltay,
- rearx, reary, thissy, x, xx, y, yy;
-
- // erase previous image
-
- if (orb[which].moved)
- if (field[orb[which].x][orb[which].y] != ORB)
- orb[which].moved = FALSE;
- else
- { draw(orb[which].x, orb[which].y, orb[which].last);
- field[orb[which].x][orb[which].y] = orb[which].last;
- }
- else orb[which].moved = TRUE;
-
- // bounce/move
-
- frontx = xwrap(orb[which].x + orb[which].deltax); // look in front
- fronty = ywrap(orb[which].y + orb[which].deltay);
- rearx = xwrap(orb[which].x - orb[which].deltax); // look behind
- reary = ywrap(orb[which].y - orb[which].deltay);
- if (bounceorb(which, frontx, fronty))
- { bouncekiller(which, frontx, fronty);
- newdeltax = -orb[which].deltax; // default bounce angle is 180°
- newdeltay = -orb[which].deltay;
- if (!bounceorb(which, frontx, reary))
- { if (bounceorb(which, rearx, fronty))
- { bouncekiller(which, rearx, fronty);
- newdeltax = orb[which].deltax;
- } }
- elif (!bounceorb(which, rearx, fronty))
- { bouncekiller(which, rearx, fronty);
- newdeltay = orb[which].deltay;
- }
- orb[which].deltax = newdeltax;
- orb[which].deltay = newdeltay;
- }
- orb[which].x = xwrap(orb[which].x + orb[which].deltax);
- orb[which].y = ywrap(orb[which].y + orb[which].deltay);
- orb[which].last = EMPTY;
-
- // collision detection
-
- if (orb[which].alive)
- { x = orb[which].x;
- y = orb[which].y;
- thissy = field[x][y];
- if (thissy <= LASTOBJECT)
- { orbscore(which, object[thissy].score);
- if (thissy != SLAYER && thissy != BOMB)
- effect(FXGETOBJECT);
- if (thissy == AMMO || thissy == SLAYER)
- { if (orb[which].mode != ARMOUR)
- orb[which].explode = TRUE;
- else effect(FXUSEARMOUR);
- } elif (thissy == NITRO || thissy == POWER || thissy == SLOWER)
- { effect(FXGETNITRO);
- orb[which].speed = speedup(orb[which].speed, TRUE);
- } elif (thissy == HEALER || thissy == LIFE || thissy == ICE || thissy == TREASURE || thissy == UMBRELLA)
- orbsplit(which);
- else switch(thissy) {
- case ARMOUR:
- orb[which].armour += MODEADD + (rand() % MODERAND);
- orb[which].mode = ARMOUR;
- break;
- case TONGUE:
- orb[which].tongue += MODEADD + (rand() % MODERAND);
- orb[which].mode = TONGUE;
- break;
- case BOMB:
- iwhich = whichtimebomb(x, y);
- timebomb[iwhich].alive = FALSE;
- draw(x, y, ORB); /* so the user understands what is happening
- *before* the s-l-o-w bombblast() occurs */
- bombblast(ORB, which, x, y);
- break;
- case PROTECTOR:
- for (player = lo; player <= hi; player++)
- if (worm[player].lives)
- for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
- if (protector[player][iwhich].alive)
- { protector[player][iwhich].alive = FALSE;
- if (protector[player][iwhich].visible)
- { draw(protector[player][iwhich].x, protector[player][iwhich].y, EMPTY);
- field[protector[player][iwhich].x][protector[player][iwhich].y] = EMPTY;
- } }
- break;
- case MISSILE:
- for (player = lo; player <= hi; player++)
- if (missile[player].alive)
- { missile[player].alive = FALSE;
- draw(missile[player].x, missile[player].y, EMPTY);
- field[missile[player].x][missile[player].y] = EMPTY;
- }
- break;
- case MULTIPLIER:
- orb[which].multi *= 2;
- if (orb[which].multi > MULTILIMIT)
- orb[which].multi = MULTILIMIT;
- break;
- case BIAS:
- for (player = lo; player <= hi; player++)
- if (worm[player].lives && worm[player].bias)
- { worm[player].bias = 0;
- stat(player, BIAS);
- }
- break;
- case AFFIXER:
- for (player = lo; player <= hi; player++)
- if (worm[player].lives)
- worm[player].affixer = FALSE;
- break;
- case SWITCHER:
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
- { field[x][y] = WOOD;
- draw(x, y, WOOD);
- }
- break;
- case GROWER:
- effect(FXGETGROWER);
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == WOOD)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy) && field[xx][yy] == EMPTY)
- field[xx][yy] = TEMPWOOD;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == TEMPWOOD)
- { field[x][y] = WOOD;
- draw(x, y, WOOD);
- }
- break;
- case CLOCK:
- secondsperlevel -= rand() % CLOCKRAND;
- break;
- default:
- break;
- } }
- elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { effect(FXUSEPROTECTOR);
- effect(FXORBDEATH);
- orb[which].alive = FALSE;
- wormscore(thissy - FIRSTPROTECTOR, orb[which].score);
- if (worm[thissy - FIRSTPROTECTOR].bias)
- { worm[thissy - FIRSTPROTECTOR].lives += ORBBLOOD;
- stat(thissy - FIRSTPROTECTOR, LIFE);
- } }
- elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
- { if (orb[which].mode == TONGUE)
- effect(FXUSETONGUE);
- else
- { if (worm[thissy - FIRSTTAIL].alive)
- { effect(FXORBDEATH);
- wormscore(thissy - FIRSTTAIL, orb[which].score);
- if (worm[thissy - FIRSTTAIL].bias)
- { worm[thissy - FIRSTTAIL].lives += ORBBLOOD;
- stat(thissy - FIRSTTAIL, LIFE);
- } }
- orb[which].alive = FALSE;
- field[x][y] = BONUS;
- draw(x, y, BONUS);
- } }
- elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { worm[thissy - FIRSTHEAD].cause = ORB;
- worm[thissy - FIRSTHEAD].victor = -1;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- if (orb[which].mode == ARMOUR)
- { effect(FXUSEARMOUR);
- orbscore(which, KILLWORM);
- } else
- { effect(FXORBDEATH);
- orb[which].alive = FALSE;
- wormscore(thissy - FIRSTHEAD, orb[which].score);
- if (worm[thissy - FIRSTHEAD].bias)
- { worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
- stat(thissy - FIRSTHEAD, LIFE);
- } } }
- else
- { effect(FXUSEARMOUR);
- effect(FXORBDEATH);
- orb[which].alive = FALSE;
- wormscore(thissy - FIRSTHEAD, orb[which].score);
- if (worm[thissy - FIRSTHEAD].bias)
- { worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
- stat(thissy - FIRSTHEAD, LIFE);
- } }
- orb[which].last = thissy - FIRSTHEAD + FIRSTTAIL; // note sign issues
- } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { iwhich = whichdrip(x, y);
- drip[iwhich].alive = FALSE;
- if (orb[which].mode != ARMOUR)
- { orb[which].explode = TRUE;
- draw(x, y, EMPTY);
- } }
- elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
- { for (player = lo; player <= hi; player++)
- { letters[player][thissy - FIRSTLETTER] = FALSE;
- drawletter(player, thissy, BLACK);
- }
- putletter(-1);
- } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { missile[thissy - FIRSTMISSILE].alive = FALSE;
- if (orb[which].mode != ARMOUR)
- { effect(FXORBDEATH);
- wormscore(thissy - FIRSTMISSILE, orb[which].score);
- if (worm[thissy - FIRSTMISSILE].bias)
- { worm[thissy - FIRSTMISSILE].lives += ORBBLOOD;
- stat(thissy - FIRSTMISSILE, LIFE);
- }
- orb[which].alive = FALSE;
- draw(x, y, BONUS);
- field[x][y] = BONUS;
- } else effect(FXUSEARMOUR);
- } else switch (thissy) {
- case EMPTY:
- orbscore(which, EMPTYPOINT);
- break;
- case SILVER:
- orbscore(which, SILVERPOINT);
- break;
- case GOLD:
- orbscore(which, GOLDPOINT);
- break;
- case TELEPORT:
- iwhich = whichteleport(x, y);
- if (blocked(iwhich, orb[which].deltax, orb[which].deltay))
- orb[which].alive = FALSE;
- else
- { effect(FXUSETELEPORT);
- orbscore(which, TELPOINT);
- orb[which].x = xwrap(teleport[level][partner(iwhich)].x + orb[which].deltax);
- orb[which].y = ywrap(teleport[level][partner(iwhich)].y + orb[which].deltay);
- }
- break;
- case ORB:
- for (iwhich = 0; iwhich <= ORBS; iwhich++)
- if (iwhich != which && orb[iwhich].alive && x == orb[iwhich].x && y == orb[iwhich].y)
- { effect(FXORBDEATH);
- if (orb[iwhich].mode != ARMOUR)
- { orb[iwhich].alive = FALSE;
- if (orb[which].mode != ARMOUR)
- orb[which].alive = FALSE;
- else effect(FXUSEARMOUR);
- } else
- { orb[which].alive = FALSE;
- if (orb[which].mode == ARMOUR)
- orb[iwhich].alive = FALSE;
- else effect(FXUSEARMOUR);
- }
- if (orb[which].alive && !orb[iwhich].alive)
- orbscore(which, orb[iwhich].score);
- elif (!orb[which].alive && orb[iwhich].alive)
- orbscore(iwhich, orb[which].score);
- elif (!orb[which].alive && !orb[iwhich].alive)
- { draw(x, y, BONUS);
- field[x][y] = BONUS;
- } }
- break;
- case FRAGMENT:
- whichfrag(x, y, &iwhich, &iiwhich);
- frag[iwhich][iiwhich].alive = FALSE;
- if (orb[which].mode != ARMOUR)
- orb[which].explode = TRUE;
- else effect(FXUSEARMOUR);
- break;
- case SKULL:
- effect(FXGETSKULL);
- orbscore(which, SKULLPOINT);
- break;
- case SLIME:
- if (orb[which].mode != TONGUE)
- orb[which].alive = FALSE;
- break;
- default:
- break;
- } }
-
- // update field
-
- if (orb[which].alive)
- { if (orb[which].mode == TONGUE)
- draw(orb[which].x, orb[which].y, ORBTONGUE);
- elif (orb[which].mode == ARMOUR)
- draw(orb[which].x, orb[which].y, ORBARMOUR);
- else
- draw(orb[which].x, orb[which].y, ORB);
- field[orb[which].x][orb[which].y] = ORB;
- }
- }
-
- void orbsplit(SBYTE which)
- { ABOOL available;
- SBYTE copy = 0, iwhich, iiwhich;
-
- effect(FXORBSPLIT);
- for (iwhich = 0; iwhich <= ORBS; iwhich++)
- { available = TRUE;
- for (iiwhich = 0; iiwhich <= 7; iiwhich++)
- if (frag[iwhich][iiwhich].alive)
- available = FALSE;
- if (!orb[iwhich].alive && copy <= 3 && available)
- { orb[iwhich].x = orb[which].x;
- orb[iwhich].y = orb[which].y;
- orb[iwhich].score = orb[which].score;
- orb[iwhich].armour = orb[which].armour;
- orb[iwhich].tongue = orb[which].tongue;
- orb[iwhich].mode = orb[which].mode;
- orb[iwhich].speed = orb[which].speed;
- orb[iwhich].explode = FALSE;
- orb[iwhich].multi = orb[which].multi;
- orb[iwhich].moved = FALSE;
- switch (copy)
- {
- case 0:
- if (orb[which].deltax != -1 || orb[which].deltay != -1)
- { orb[iwhich].deltax = -1;
- orb[iwhich].deltay = -1;
- orb[iwhich].alive = TRUE;
- }
- break;
- case 1:
- if (orb[which].deltax != 1 || orb[which].deltay != 1)
- { orb[iwhich].deltax = 1;
- orb[iwhich].deltay = 1;
- orb[iwhich].alive = TRUE;
- }
- break;
- case 2:
- if (orb[which].deltax != 1 || orb[which].deltay != -1)
- { orb[iwhich].deltax = 1;
- orb[iwhich].deltay = -1;
- orb[iwhich].alive = TRUE;
- }
- break;
- case 3:
- if (orb[which].deltax != -1 || orb[which].deltay != 1)
- { orb[iwhich].deltax = -1;
- orb[iwhich].deltay = 1;
- orb[iwhich].alive = TRUE;
- }
- break;
- default:
- break;
- }
- copy++;
- } } }
-
- void orientworms(void)
- { SBYTE player;
-
- for (player = lo; player <= hi; player++)
- { worm[player].speed = NORMAL;
- if (worm[player].lives)
- stat(player, NITRO);
- worm[player].moved = FALSE;
- worm[player].x = startx[level];
- worm[player].y = starty[level];
- switch (player)
- {
- case 0:
- worm[0].deltax = -1;
- worm[0].deltay = 0;
- break;
- case 1:
- worm[1].deltax = 1;
- worm[1].deltay = 0;
- break;
- case 2:
- worm[2].deltax = 0;
- worm[2].deltay = -1;
- break;
- case 3:
- worm[3].deltax = 0;
- worm[3].deltay = 1;
- break;
- default:
- break;
- } } }
-
- SBYTE partner(SBYTE which)
- { if (which % 2 == 0)
- return((SBYTE) (which + 1));
- else return((SBYTE) (which - 1));
- }
-
- /* NAME putletter -- Put a letter onto the field
- SYNOPSIS void putletter(SBYTE player);
- INPUTS SBYTE player -
- 0-3: player on whose behalf the letter is put on for
- -1: any letter
- RESULT none
- NOTES noletter -
- -2: if we found somewhere to put the letter
- player: if we didn't */
-
- void putletter(SBYTE player)
- { SBYTE count = 0, letter;
- SBYTE i, x, y;
-
- do
- { x = rand() % (FIELDX + 1);
- y = rand() % (FIELDY + 1);
- } while ((field[x][y] < FIRSTEMPTY || field[x][y] > LASTEMPTY) && (++count < PATIENCE));
- if (count < PATIENCE)
- { noletter = -2;
- if (player != -1)
- { for (i = 0; i <= LETTERS; i++)
- if (!(letters[player][i]))
- { break;
- }
- if (i > LETTERS)
- letter = rand() % (LETTERS + 1);
- else
- { do
- letter = rand() % (LETTERS + 1);
- while (letters[player][letter]);
- }
- } else
- letter = rand() % (LETTERS + 1);
- field[x][y] = letter + FIRSTLETTER;
- draw(x, y, letter + FIRSTLETTER);
- } else noletter = player;
- }
-
- /* NAME queue -- adds a keystroke to the key queue
- SYNOPSIS name(SBYTE, SBYTE, SBYTE);
- FUNCTION Adds a keystroke to the in-game key queue.
- INPUTS player - player that pressed the key
- deltax - the deltax of the key
- deltay - the deltay of the key
- IMPLEMENTATION
- thequeue[] is an array, with QUEUELIMIT as its last index.
- It is implemented as a FIFO stack rather than LIFO so that
- the keystrokes are processed in the correct order (that is,
- the order in which they were pressed). The oldest keystroke
- is always at index [0], the next oldest at [1], and so on
- upwards to the newest keystroke, at [worm[player].pos].
- Keystrokes are removed from the bottom of the array ([0]),
- and the rest of the array is shuffled down to fill the gap,
- so that the contents of [1] go to [0], the contents of [2]
- go to [1], etc. worm[player].pos is adjusted to always point
- to the newest entry, which is the 'end' of the queue.
- MODULE engine.c */
-
- void queue(SBYTE player, SBYTE deltax, SBYTE deltay)
- { if (worm[player].pos < QUEUELIMIT)
- { worm[player].pos++;
- thequeue[player][worm[player].pos].deltax = deltax;
- thequeue[player][worm[player].pos].deltay = deltay;
- } }
-
- void reflect(SBYTE which, SBYTE iwhich)
- { frag[which][iwhich].deltax = -frag[which][iwhich].deltax;
- frag[which][iwhich].deltay = -frag[which][iwhich].deltay;
- frag[which][iwhich].x += frag[which][iwhich].deltax * 2;
- frag[which][iwhich].y += frag[which][iwhich].deltay * 2;
- }
-
- void renderboard(void)
- { SBYTE x, y;
-
- switch(rand() % 3) {
- case 0:
- // chequered
- for (y = 0; y <= FIELDY; y += 2)
- for (x = 0; x <= FIELDX; x += 2)
- draw(x, y, board[level][x][y]);
- for (x = 1; x <= FIELDX; x += 2)
- for (y = 1; y <= FIELDY; y += 2)
- draw(x, y, board[level][x][y]);
- for (y = 0; y <= FIELDY; y += 2)
- for (x = 1; x <= FIELDX; x += 2)
- draw(x, y, board[level][x][y]);
- for (x = 0; x <= FIELDX; x += 2)
- for (y = 1; y <= FIELDY; y += 2)
- draw(x, y, board[level][x][y]);
- break;
- case 1:
- // `closing sliding doors'
- for (x = 0; x <= FIELDX / 2; x++)
- for (y = 0; y <= FIELDY; y++)
- { draw(x, y, board[level][x][y]);
- draw(FIELDX - x, y, board[level][FIELDX - x][y]);
- }
- break;
- case 2:
- // `opening sliding doors'
- for (x = FIELDX / 2; x >= 0; x--)
- for (y = 0; y <= FIELDY; y++)
- { draw(x, y, board[level][x][y]);
- draw(FIELDX - x, y, board[level][FIELDX - x][y]);
- }
- break;
- default:
- break;
- }
-
- if (a == FIELDEDIT)
- { draw(startx[level], starty[level], START);
- if (teleport[level][0].alive)
- { draw(teleport[level][0].x, teleport[level][0].y, ONE);
- draw(teleport[level][1].x, teleport[level][1].y, TWO);
- } } }
-
- ABOOL savefields(STRPTR fieldname)
- { SBYTE i, j;
- TEXT IOBuffer[NAMELENGTH + 1];
-
- matchteleports();
-
- if (!ZOpen(fieldname, TRUE))
- return FALSE;
-
- // write header
-
- strcpy(IOBuffer, "FSET 4.4");
- IOBuffer[9] = levels;
- if (!ZWrite(IOBuffer, 10))
- { ZClose();
- return FALSE;
- }
-
- // write high score table
-
- for (i = 0; i <= HISCORES; i++)
- { IOBuffer[0] = hiscore[i].player;
- IOBuffer[1] = hiscore[i].level;
- IOBuffer[2] = 0;
- IOBuffer[3] = hiscore[i].score / 65536;
- IOBuffer[4] = (hiscore[i].score % 65536) / 256;
- IOBuffer[5] = (hiscore[i].score % 65536) % 256;
- if (!ZWrite(IOBuffer, 6))
- { ZClose();
- return FALSE;
- }
-
- for (j = 0; j <= NAMELENGTH; j++)
- IOBuffer[j] = hiscore[i].name[j];
- if (!ZWrite(IOBuffer, NAMELENGTH + 1))
- { ZClose();
- return FALSE;
- } }
-
- // write level data
-
- for (i = 0; i <= levels; i++)
- { IOBuffer[0] = startx[i];
- IOBuffer[1] = starty[i];
- IOBuffer[2] = teleport[i][0].alive;
- IOBuffer[3] = teleport[i][0].x;
- IOBuffer[4] = teleport[i][0].y;
- IOBuffer[5] = teleport[i][1].alive;
- IOBuffer[6] = teleport[i][1].x;
- IOBuffer[7] = teleport[i][1].y;
- if (!ZWrite(IOBuffer, 8))
- { ZClose();
- return FALSE;
- }
-
- if (!ZWrite((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
- { ZClose();
- return FALSE;
- } }
-
- // write version string
-
- if (!ZWrite(VERSION, strlen(VERSION)))
- { ZClose();
- return FALSE;
- }
-
- ZClose();
-
- if (clearthem)
- clearhiscores();
- modified = FALSE;
- return TRUE;
- }
-
- void saylevel(COLOUR colour)
- { TEXT mainstring[15] = "Level ", tempstring[4];
-
- if (level > 0)
- { stci_d(&mainstring[6], level);
- strcat((char*) mainstring, " of ");
- stci_d(tempstring, levels);
- strcat((char*) mainstring, (char*) tempstring);
- say(mainstring, colour);
- } else say((STRPTR) "Treasury", colour);
- }
-
- void setbrush(SBYTE newbrush)
- { brush = newbrush;
- setpointer(brush);
- underline(brush);
- }
-
- SBYTE slowdown(SBYTE speed)
- { speed *= 2;
- if (speed > SLOW)
- speed = SLOW;
- return(speed);
- }
-
- /* NAME slowloop -- things done rarely
- SYNOPSIS slowloop(void);
- FUNCTION Decrements strength; creates killers, orbs, objects,
- teleports, slime; controls timebombs; puts letters if
- neccessary; blanks out old causes.
- MODULE engine.c */
-
- void slowloop(void)
- { ABOOL available, done;
- SBYTE i, iwhich, player, which, x, xx, y, yy;
- PERSIST SBYTE type = FIRSTDRIP;
-
- // decrement strength
-
- for (player = lo; player <= hi; player++)
- if (worm[player].lives > 0 && ice == -1 || ice == player)
- { if (worm[player].bias > 0)
- { worm[player].bias--;
- stat(player, BIAS);
- }
- if (worm[player].ice > 0 && --worm[player].ice == 0)
- { for (which = lo; which <= hi; which++)
- if (player != which)
- worm[player].pos = -1;
- ice = -1;
- }
- if (worm[player].mode == ARMOUR)
- { if (--worm[player].armour == 0)
- { if (worm[player].tongue > 0)
- worm[player].mode = TONGUE;
- else worm[player].mode = NULL;
- }
- stat(player, ARMOUR);
- } elif (worm[player].mode == TONGUE)
- { if (--worm[player].tongue == 0)
- { if (worm[player].armour > 0)
- worm[player].mode = ARMOUR;
- else worm[player].mode = NULL;
- }
- stat(player, TONGUE);
- } }
-
- if (ice == -1)
- { for (which = 0; which <= ORBS; which++)
- if (orb[which].alive)
- if (orb[which].mode == ARMOUR)
- { if (--orb[which].armour == 0)
- if (orb[which].tongue > 0)
- orb[which].mode = TONGUE;
- else orb[which].mode = NULL;
- } elif (orb[which].mode == TONGUE)
- { if (--orb[which].tongue == 0)
- if (orb[which].armour > 0)
- orb[which].mode = ARMOUR;
- else orb[which].mode = NULL;
- }
-
- // create killers
-
- for (which = 0; which <= KILLERS; which++)
- if (!killer[which].alive && !(rand() % killerfreq) && findempty(&x, &y, FIRSTKILLER, LASTKILLER) && field[x][y] != KILLER)
- { effect(FXKILLERBORN);
- killer[which].x = x;
- killer[which].y = y;
- killer[which].alive = TRUE;
- killer[which].last = field[killer[which].x][killer[which].y];
- field[killer[which].x][killer[which].y] = KILLER;
- draw(killer[which].x, killer[which].y, KILLER);
- }
-
- // create orbs
-
- for (which = 0; which <= ORBS; which++)
- if (!orb[which].alive && !(rand() % orbfreq))
- { orb[which].x = rand() % (FIELDX + 1);
- orb[which].y = rand() % (FIELDY + 1);
- available = TRUE;
- for (iwhich = 0; iwhich <= 7; iwhich++)
- if (frag[which][iwhich].alive)
- available = FALSE;
- if (available && field[orb[which].x][orb[which].y] >= FIRSTEMPTY && field[orb[which].x][orb[which].y] <= LASTEMPTY)
- { orb[which].deltax = (rand() % 2) * 2 - 1;
- orb[which].deltay = (rand() % 2) * 2 - 1;
- if (field[orb[which].x + orb[which].deltay][orb[which].y + orb[which].deltay] >= FIRSTEMPTY && field[orb[which].x + orb[which].deltax][orb[which].y + orb[which].deltay] <= LASTEMPTY)
- { effect(FXORBBORN);
- orb[which].score = 0;
- orb[which].alive = TRUE;
- orb[which].armour = 0;
- orb[which].tongue = 0;
- orb[which].mode = NULL;
- orb[which].speed = orbspeed;
- orb[which].explode = FALSE;
- orb[which].multi = 1;
- orb[which].moved = FALSE;
- } } }
-
- // create drips
-
- for (which = 0; which <= DRIPS; which++)
- if (!drip[which].alive && !(rand() % dripfreq))
- { drip[which].x = rand() % (FIELDX + 1);
- drip[which].y = rand() % 3;
- if (field[drip[which].x][drip[which].y] >= FIRSTEMPTY && field[drip[which].x][drip[which].y] <= LASTEMPTY
- && field[drip[which].x][drip[which].y + 1] >= FIRSTEMPTY && field[drip[which].x][drip[which].y + 1] <= LASTEMPTY)
- { effect(FXDRIPBORN);
- drip[which].alive = TRUE;
- drip[which].moved = FALSE;
- drip[which].type = type;
- if (++type > LASTDRIP)
- type = FIRSTDRIP;
- } }
-
- // create objects
-
- for (which = 0; which <= LASTOBJECT; which++)
- if (!(rand() % object[which].frequency) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
- { field[x][y] = which;
- draw(x, y, which);
- }
-
- // create teleports
-
- if (!(rand() % TELFREQ)
- && !teleport[level][2].alive
- && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FIRSTEMPTY, LASTEMPTY)
- && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FIRSTEMPTY, LASTEMPTY)
- && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
- { teleport[level][2].alive = TRUE;
- field[teleport[level][2].x][teleport[level][2].y] = TELEPORT;
- draw(teleport[level][2].x, teleport[level][2].y, TELEPORT);
- teleport[level][3].alive = TRUE;
- field[teleport[level][3].x][teleport[level][3].y] = TELEPORT;
- draw(teleport[level][3].x, teleport[level][3].y, TELEPORT);
- }
-
- // create timebombs
-
- for (i = 0; i <= level; i++)
- { x = rand() % (FIELDX + 1);
- y = rand() % (FIELDY + 1);
- if (field[x][y] == BOMB)
- { done = FALSE;
- for (which = 0; which <= TIMEBOMBS; which++)
- if (timebomb[which].alive == FALSE && !done)
- { timebomb[which].alive = TRUE;
- timebomb[which].x = x;
- timebomb[which].y = y;
- timebomb[which].time = 10;
- done = TRUE;
- } } }
-
- // decrement and explode timebombs
-
- if (!(r % (VERYSLOW * TIMEBOMBSPEED)))
- for (which = 0; which <= TIMEBOMBS; which++)
- if (timebomb[which].alive)
- { if (field[timebomb[which].x][timebomb[which].y] != BOMB)
- timebomb[which].alive = FALSE;
- else
- { effect(FXTIMEBOMBTICK);
- timebomb[which].time--;
- if (timebomb[which].time < 0)
- { timebomb[which].alive = FALSE;
- field[timebomb[which].x][timebomb[which].y] = EMPTY;
- draw(timebomb[which].x, timebomb[which].y, EMPTY);
- bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
- } else draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
- } }
-
- // create slime
-
- if (!(rand() % slimefreq))
- { if (findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
- { field[x][y] = SLIME;
- draw(x, y, SLIME);
- } }
-
- // grow slime
-
- if (!(rand() % slimefreq))
- { for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SLIME)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy) && field[xx][yy] == EMPTY && !(rand() % 2))
- field[xx][yy] = TEMPSLIME;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == TEMPSLIME)
- { field[x][y] = SLIME;
- draw(x, y, SLIME);
- } }
-
- // retry putting letters if necessary
-
- if (noletter != -2)
- putletter(noletter);
- }
-
- // blank out old causes
-
- for (player = lo; player <= hi; player++)
- { if (worm[player].lives > 0 && r > worm[player].causewait)
- { drawcause(player, BLACK);
- worm[player].causewait = (ULONG) -1; // most future time possible
- } }
- }
-
- SBYTE speedup(SBYTE speed, ABOOL nitro)
- { speed /= 2;
- if (speed < FAST)
- speed = FAST;
- return(speed);
- }
-
- LONG squareblast(SBYTE type, SBYTE player, SBYTE thissy, SBYTE x, SBYTE y)
- { SBYTE iwhich, which;
- LONG score = 0L;
- SBYTE filler;
-
- if (type == HEAD && worm[player].bias)
- filler = SILVER;
- else filler = EMPTY;
-
- if (thissy <= LASTOBJECT)
- { field[x][y] = filler;
- draw(x, y, filler);
- if (thissy == BOMB)
- for (which = 0; which <= TIMEBOMBS; which++)
- if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
- timebomb[which].alive = FALSE;
- } elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
- { draw(x, y, filler);
- field[x][y] = filler;
- } elif (thissy == ORB)
- { which = whichorb(x, y);
- if (orb[which].mode != ARMOUR)
- { effect(FXORBDEATH);
- orb[which].alive = FALSE;
- score = orb[which].score;
- if (type == HEAD && worm[player].bias)
- worm[player].lives += ORBBLOOD;
- draw(x, y, BONUS);
- field[x][y] = BONUS;
- } else effect(FXUSEARMOUR);
- } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { which = whichdrip(x, y);
- drip[which].alive = FALSE;
- draw(x, y, filler);
- field[x][y] = filler;
- } elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (type != HEAD || player != thissy - FIRSTHEAD)
- if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { worm[thissy - FIRSTHEAD].cause = BOMB;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- stat(thissy - FIRSTHEAD, LIFE);
- if (type == HEAD)
- worm[thissy - FIRSTHEAD].victor = player;
- else
- { worm[thissy - FIRSTHEAD].victor = -1;
- score = KILLWORM; // worms will get thissy bonus from death(), so it is not given for them here.
- }
- } else effect(FXUSEARMOUR);
- } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { if (type != HEAD || player != thissy - FIRSTMISSILE)
- { missile[thissy - FIRSTMISSILE].alive = FALSE;
- draw(x, y, filler);
- field[x][y] = filler;
- } }
- elif (thissy == FRAGMENT)
- { whichfrag(x, y, &which, &iwhich);
- frag[which][iwhich].alive = FALSE;
- draw(x, y, filler);
- field[x][y] = filler;
- } elif (thissy == KILLER)
- { which = whichkiller(x, y);
- killer[which].alive = FALSE;
- draw(x, y, BONUS);
- field[x][y] = BONUS;
- }
- return(score);
- }
-
- void timeloop(void)
- { TEXT timedisplay[5] = {"#:##"};
- PERSIST ABOOL outoftime = FALSE;
-
- secondsleft = atleast(secondsleft, 0);
- timedisplay[0] = 48 + (secondsleft / 60);
- timedisplay[2] = 48 + ((secondsleft % 60) / 10);
- timedisplay[3] = 48 + ((secondsleft % 60) % 10);
-
- if (!level)
- { say(timedisplay, worm[treasurer].colour);
- if (!secondsleft)
- { level = reallevel + 1;
- secondsleft = SECONDSPERLEVEL;
- newlevel(treasurer);
- } }
- elif (!secondsleft)
- { say("Out of time!", WHITE);
- if (!outoftime)
- { effect(FXTIMEALERT);
- outoftime = TRUE;
- dripspeed = speedup(dripspeed, TRUE);
- fragspeed = speedup(fragspeed, TRUE);
- orbspeed = speedup(orbspeed, TRUE);
- killerspeed = speedup(killerspeed, TRUE);
- dripfreq = atleast( dripfreq / 2, DRIPFREQ_MIN);
- killerfreq = atleast(killerfreq / 2, KILLERFREQ_MIN);
- orbfreq = atleast( orbfreq / 2, ORBFREQ_MIN);
- slimefreq = atleast( slimefreq / 2, SLIMEFREQ_MIN);
- } }
- else
- { outoftime = FALSE;
- say(timedisplay, WHITE);
- } }
-
- void train(SCANCODE scancode)
- { SBYTE i, x, y;
-
- switch(scancode) {
- case HELP:
- trainer = !trainer;
- break;
- case NUMERICSLASH:
- // Complete the level.
- if (trainer)
- { trainer = FALSE;
- if (worm[1].lives > 0)
- for (i = 0; i <= LETTERS; i++)
- letters[1][i] = TRUE;
- drawletter(1, FIRSTLETTER + i, NORMAL);
- }
- break;
- case NUMERICASTERISK:
- // Change most squares to gold.
- if (trainer)
- { trainer = FALSE;
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == FIRSTTAIL + 1)
- { draw(x, y, METAL);
- field[x][y] = METAL;
- } elif (field[x][y] != STONE && field[x][y] != KILLER && field[x][y] != ORB && field[x][y] != SKULL && (field[x][y] < FIRSTHEAD || field[x][y] > LASTHEAD) && (field[x][y] < FIRSTLETTER || field[x][y] > LASTLETTER))
- { draw(x, y, GOLD);
- field[x][y] = GOLD;
- } }
- break;
- case NUMERICPLUS:
- // Full lives, tongue, bias, ammo, power, nitro and affixer.
- if (trainer)
- { trainer = FALSE;
- if (worm[1].lives > 0)
- { worm[1].lives = LIVESLIMIT;
- stat(1, LIFE);
- worm[1].tongue = MODELIMIT;
- worm[1].mode = TONGUE;
- stat(1, TONGUE);
- worm[1].bias = BIASLIMIT;
- stat(1, BIAS);
- worm[1].ammo = AMMOLIMIT;
- stat(1, AMMO);
- worm[1].power = POWERLIMIT;
- stat(1, POWER);
- worm[1].nitro = TRUE;
- stat(1, NITRO);
- worm[1].affixer = TRUE;
- trainer = FALSE;
- } }
- break;
- default:
- break;
- } }
-
- void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
- {
- if (worm[player].nitro || !deltax || !deltay)
- { if (worm[player].deltax == deltax && worm[player].deltay == deltay)
- { worm[player].speed = speedup(worm[player].speed, worm[player].nitro);
- stat(player, NITRO);
- } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
- { worm[player].speed = slowdown(worm[player].speed);
- stat(player, NITRO);
- } else
- { worm[player].deltax = deltax;
- worm[player].deltay = deltay;
- } }
- }
-
- void updatesquare(SBYTE x, SBYTE y)
- { SBYTE which;
-
- if (startx[level] == x && starty[level] == y)
- draw(x, y, START);
- elif (board[level][x][y] == TELEPORT)
- { for (which = 0; which <= 1; which++)
- if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
- draw(x, y, ONE + which);
- } else draw(x, y, board[level][x][y]);
- }
-
- SBYTE valid(SBYTE x, SBYTE y)
- { if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
- return(TRUE);
- else
- return(FALSE);
- }
-
- SBYTE whichdrip(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= DRIPS; which++)
- if (drip[which].alive && drip[which].x == x && drip[which].y == y)
- return(which);
- return(-1); // error code
- }
- void whichfrag(SBYTE x, SBYTE y, SBYTE* whichptr, SBYTE* iwhichptr)
- { SBYTE which, iwhich;
-
- for (which = 0; which <= ORBS + 1; which++)
- for (iwhich = 0; iwhich <= 7; iwhich++)
- if (frag[which][iwhich].alive && frag[which][iwhich].x == x && frag[which][iwhich].y == y)
- { *whichptr = which;
- *iwhichptr = iwhich;
- return;
- } }
- SBYTE whichkiller(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= KILLERS; which++)
- if (killer[which].alive && killer[which].x == x && killer[which].y == y)
- return(which);
- return(-1); // error code
- }
- SBYTE whichorb(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= ORBS; which++)
- if (orb[which].alive && orb[which].x == x && orb[which].y == y)
- return(which);
- return(-1); // error code
- }
- SBYTE whichteleport(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= TIMEBOMBS; which++)
- if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
- return((SBYTE) which);
- return((SBYTE) -1); // error code
- }
- SBYTE whichtimebomb(SBYTE x, SBYTE y)
- { SBYTE which;
-
- for (which = 0; which <= TIMEBOMBS; which++)
- if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
- return(which);
- return(-1); // error code
- }
-
- void wormbullet(SBYTE player)
- { ABOOL finished,
- flag = FALSE,
- ok = FALSE,
- lettered = FALSE;
- LONG score;
- SBYTE distance,
- thissy,
- i, j, k,
- x, y;
-
- if (!worm[player].ammo)
- { stat(player, BONUS);
- if (worm[player].speed == FAST)
- distance = FASTDISTANCE;
- elif (worm[player].speed == NORMAL)
- distance = NORMALDISTANCE;
- else
- { // assert(worm[player].speed == SLOW);
- distance = SLOWDISTANCE;
- }
-
- // check for metal
-
- for (i = 1; i < distance; i++)
- { x = xwrap(worm[player].x + (i * worm[player].deltax));
- y = ywrap(worm[player].y + (i * worm[player].deltay));
- if (field[x][y] == METAL)
- flag = TRUE;
- }
-
- if (!flag)
- { // assert(abs(worm[player].deltax) == 1 && abs(worm[player].deltay) == 1);
- x = xwrap(worm[player].x + worm[player].deltax * distance);
- y = ywrap(worm[player].y + worm[player].deltay * distance);
- thissy = field[x][y];
- if (thissy == TELEPORT)
- { i = whichteleport(x, y);
- if (!blocked(i, worm[player].deltax, worm[player].deltay))
- ok = TRUE;
- }
- if (ok || ((thissy < STONE || thissy > KILLER) && thissy != METAL))
- { // Amiga-worms only make jumping sounds in demo mode
- flag = FALSE;
- for (i = lo; i <= hi; i++)
- if (worm[i].control == HUMAN)
- flag = TRUE;
- if (!flag || worm[player].control == HUMAN)
- effect(FXJUMP);
- worm[player].deltax *= distance;
- worm[player].deltay *= distance;
- } } }
- else
- { effect(FXSHOOT);
- worm[player].ammo--;
- stat(player, AMMO);
- if (!missile[player].alive && worm[player].bias)
- { missile[player].alive = TRUE;
- missile[player].x = worm[player].x;
- missile[player].y = worm[player].y;
- missile[player].moved = FALSE;
- }
- for (i = 0; i <= worm[player].power; i++)
- { bullet[i].alive = TRUE;
- bullet[i].teleported = 0;
- bullet[i].visible = TRUE;
- bullet[i].reflected = FALSE;
- if (i % 2 == 0)
- distance = i / 2;
- else
- distance = -((i + 1) / 2);
- if (worm[player].deltax == 0)
- { bullet[i].x = worm[player].x + distance;
- bullet[i].y = worm[player].y + worm[player].deltay + 1;
- } elif (worm[player].deltay == 0)
- { bullet[i].x = worm[player].x + worm[player].deltax + 1;
- bullet[i].y = worm[player].y + distance;
- } else
- { switch (i) {
- case 0:
- bullet[i].x = worm[player].x + worm[player].deltax;
- bullet[i].y = worm[player].y + worm[player].deltay;
- break;
- case 1:
- bullet[i].x = worm[player].x + worm[player].deltax;
- bullet[i].y = worm[player].y;
- break;
- case 2:
- bullet[i].x = worm[player].x;
- bullet[i].y = worm[player].y + worm[player].deltay;
- break;
- case 3:
- bullet[i].x = worm[player].x + worm[player].deltax * 2;
- bullet[i].y = worm[player].y;
- break;
- case 4:
- bullet[i].x = worm[player].x;
- bullet[i].y = worm[player].y + worm[player].deltay * 2;
- break;
- case 5:
- bullet[i].x = worm[player].x + worm[player].deltax * 2;
- bullet[i].y = worm[player].y - worm[player].deltay;
- break;
- case 6:
- bullet[i].x = worm[player].x - worm[player].deltax;
- bullet[i].y = worm[player].y + worm[player].deltay * 2;
- break;
- default:
- break;
- } }
- if (!(valid(bullet[i].x, bullet[i].y)))
- bullet[i].alive = FALSE;
- }
- score = 0L;
- finished = FALSE;
- while (!finished)
- { finished = TRUE;
- for (i = 0; i <= worm[player].power; i++)
- { if (bullet[i].alive)
- { finished = FALSE;
- if (bullet[i].visible)
- if (bullet[i].teleported)
- { if (worm[player].bias)
- { draw(bullet[i].x, bullet[i].y, GOLD);
- field[bullet[i].x][bullet[i].y] = GOLD;
- } else
- { draw(bullet[i].x, bullet[i].y, SILVER);
- field[bullet[i].x][bullet[i].y] = SILVER;
- } }
- else
- { draw(bullet[i].x, bullet[i].y, EMPTY);
- field[bullet[i].x][bullet[i].y] = EMPTY;
- }
- else bullet[i].visible = TRUE;
- if (bullet[i].reflected)
- { bullet[i].x -= worm[player].deltax;
- bullet[i].y -= worm[player].deltay;
- } else
- { bullet[i].x += worm[player].deltax;
- bullet[i].y += worm[player].deltay;
- }
- if (!(valid(bullet[i].x, bullet[i].y)))
- bullet[i].alive = FALSE;
- else if (bullet[i].x == worm[player].x && bullet[i].y == worm[player].y)
- { // hit by own bullet
- bullet[i].alive = FALSE;
- if (worm[player].mode != ARMOUR)
- { worm[player].cause = FIRSTFIRE + player;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- } }
- else
- { thissy = field[bullet[i].x][bullet[i].y];
- if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { worm[thissy - FIRSTHEAD].cause = FIRSTFIRE + player;
- worm[thissy - FIRSTHEAD].victor = player;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- if (player != thissy - FIRSTHEAD)
- score += KILLWORM + HITSHOT;
- } else effect(FXUSEARMOUR);
- bullet[i].alive = FALSE;
- } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { if (player != thissy - FIRSTPROTECTOR)
- { effect(FXUSEPROTECTOR);
- bullet[i].alive = FALSE;
- } else
- bullet[i].visible = FALSE;
- } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { if (player != thissy - FIRSTMISSILE)
- missile[thissy - FIRSTMISSILE].alive = FALSE;
- else bullet[i].visible = FALSE;
- } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { j = whichdrip(bullet[i].x, bullet[i].y);
- drip[j].alive = FALSE;
- } elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
- { wormletter(player, thissy);
- lettered = TRUE;
- } else
- { switch(thissy) {
- case METAL:
- if (bullet[i].reflected)
- bullet[i].alive = FALSE;
- else
- { bullet[i].reflected = TRUE;
- bullet[i].x -= worm[player].deltax;
- bullet[i].y -= worm[player].deltay;
- }
- break;
- case STONE:
- bullet[i].alive = FALSE;
- break;
- case ORB:
- bullet[i].alive = FALSE;
- j = whichorb(bullet[i].x, bullet[i].y);
- if (orb[j].mode != ARMOUR)
- { orb[j].explode = TRUE;
- score += orb[j].score + HITSHOT;
- if (worm[player].bias)
- worm[player].lives += ORBBLOOD;
- } else effect(FXUSEARMOUR);
- break;
- case TELEPORT:
- j = whichteleport(bullet[i].x, bullet[i].y);
- if (bullet[i].teleported == 2)
- bullet[i].alive = FALSE;
- else
- { effect(FXUSETELEPORT);
- bullet[i].visible = FALSE;
- bullet[i].teleported++;
- bullet[i].x = teleport[level][partner(j)].x;
- bullet[i].y = teleport[level][partner(j)].y;
- score += TELPOINT;
- }
- break;
- case WOOD:
- if (!worm[player].bias)
- bullet[i].alive = FALSE;
- break;
- case KILLER:
- for (j = 0; j <= KILLERS; j++)
- if (killer[j].alive && killer[j].x == bullet[i].x && killer[j].y == bullet[i].y)
- { killer[j].alive = FALSE;
- draw(bullet[i].x, bullet[i].y, BONUS);
- field[bullet[i].x][bullet[i].y] = BONUS;
- score += KILLKILLER + HITSHOT;
- if (worm[player].bias)
- worm[player].lives += KILLERBLOOD;
- }
- bullet[i].alive = FALSE;
- break;
- case SKULL:
- bullet[i].alive = FALSE;
- break;
- case FRAGMENT:
- bullet[i].alive = FALSE;
- whichfrag(bullet[i].x, bullet[i].y, &j, &k);
- frag[j][k].alive = FALSE;
- field[bullet[i].x][bullet[i].y] = EMPTY;
- draw(bullet[i].x, bullet[i].y, EMPTY);
- break;
- case BOMB:
- j = whichtimebomb(bullet[i].x, bullet[i].y);
- if (j != -1)
- { bullet[i].alive = FALSE;
- timebomb[j].alive = FALSE;
- field[timebomb[j].x][timebomb[j].y] = EMPTY;
- draw(timebomb[j].x, timebomb[j].y, EMPTY);
- bombblast(HEAD, player, timebomb[j].x, timebomb[j].y);
- }
- break;
- default:
- break;
- }
- if (bullet[i].alive && bullet[i].visible)
- draw(bullet[i].x, bullet[i].y, FIRSTFIRE + player);
- } } } } }
- if (lettered)
- putletter(player);
- wormscore(player, score);
- if (worm[player].bias)
- stat(player, LIFE);
- clearkybd();
- } }
-
- void wormletter(SBYTE player, SBYTE thissy)
- { if (thissy == GREEN_C)
- effect(FX_C);
- elif (thissy == RED_O)
- effect(FX_O);
- elif (thissy == BLUE_M)
- effect(FX_M);
- elif (thissy == YELLOW_P)
- effect(FX_P);
- elif (thissy == GREEN_L)
- effect(FX_L);
- elif (thissy == BLUE_T)
- effect(FX_T);
- else // assumes RED_E or YELLOW_E
- effect(FX_E);
- letters[player][thissy - FIRSTLETTER] = TRUE;
- drawletter(player, thissy, NORMAL);
- if (player == (thissy - FIRSTLETTER) % 4)
- wormscore(player, MYLETTER);
- else wormscore(player, YOURLETTER);
- }
-
- /* NAME wormloop -- controls worms and protectors
- SYNOPSIS wormloop(SBYTE);
- FUNCTION Amiga-worm thinking, processing one keystroke from the
- worm's queue, all the worm's protectors' control, the
- worm's control.
- MODULE engine.c */
-
- void wormloop(SBYTE player)
- {
- ABOOL complete, done, flag;
- SBYTE bestgood, bestx, besty, creature, dirx, diry, good, i, ithis,
- iwhich, thissy, thisletter, thisprot = -1, which, x, xx, y, yy;
- LONG score = 0L;
-
- /* AI: Amiga worm control
-
- Worm checks ahead, left and right one square. Assigns opinions to those
- three choices and then takes the appropriate one.
-
- Possible enhancements:
- recognition of possession of objects
- (esp. ammo, nitro, tongue, armour)
- finer gradients of decision
- (eg. certain objects better than others)
- longer lookahead */
-
- if (worm[player].control == AMIGA)
- { if (!(rand() % 200))
- queue(player, (rand() % 3) - 1, (rand() % 3) - 1);
- else
- { bestgood = -128;
-
- for (i = 0; i <= 2; i++)
- { switch(i) {
- case 0:
- dirx = worm[player].deltax;
- diry = worm[player].deltay;
- break;
- case 1:
- if (worm[player].deltax == 0) // if going north or south
- { dirx = -1; // then look west
- diry = 0;
- } else // if going east or west
- { dirx = 0; // then look north
- diry = -1;
- }
- break;
- case 2:
- if (worm[player].deltax == 0) // if going north or south
- { dirx = 1; // then look east
- diry = 0;
- } else // if going east or west
- { dirx = 0; // then look south
- diry = 1;
- }
- break;
- default:
- break;
- }
- thissy = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
- if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
- good = 100;
- elif (thissy <= LASTOBJECT)
- good = 80;
- elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
- { if (player == thissy - FIRSTTAIL)
- good = -30;
- else good = -60;
- } else switch(thissy) {
- case SKULL:
- good = 70;
- break;
- case GOLD:
- good = 50;
- break;
- case SILVER:
- good = 40;
- break;
- case EMPTY:
- good = 10;
- break;
- case WOOD:
- good = -80;
- break;
- case STONE:
- good = -90;
- break;
- case METAL:
- good = -90;
- break;
- case KILLER:
- good = -100;
- break;
- default:
- good = -50; // slime, heads, orbs, etc.
- break;
- }
- if (good > bestgood)
- { bestx = dirx;
- besty = diry;
- bestgood = good;
- } }
-
- if (bestgood <= -60)
- queue(player, 0, 0);
- elif (bestgood < 0 && (!(rand() % 2)))
- queue(player, 0, 0);
- elif (bestx != worm[player].deltax || besty != worm[player].deltay)
- queue(player, bestx, besty);
- } }
-
- // remove a keystroke from the queue
-
- if (worm[player].pos != -1)
- { if (thequeue[player][0].deltax == 0 && thequeue[player][0].deltay == 0)
- wormbullet(player);
- else turnworm(player, thequeue[player][0].deltax, thequeue[player][0].deltay);
- if (--worm[player].pos != -1)
- for (i = 0; i <= worm[player].pos; i++)
- { thequeue[player][i].deltax = thequeue[player][i + 1].deltax;
- thequeue[player][i].deltay = thequeue[player][i + 1].deltay;
- } }
-
- // move worm
-
- field[worm[player].x][worm[player].y] = worm[player].last;
- draw(worm[player].x, worm[player].y, worm[player].last);
- worm[player].x = xwrap(worm[player].x + worm[player].deltax);
- worm[player].y = ywrap(worm[player].y + worm[player].deltay);
- worm[player].deltax = bsign(worm[player].deltax);
- worm[player].deltay = bsign(worm[player].deltay);
- worm[player].last = FIRSTTAIL + player;
-
- // move protectors
-
- for (which = 0; which <= PROTECTORS; which++)
- { if (protector[player][which].alive)
- { if (protector[player][which].visible)
- { draw(protector[player][which].x, protector[player][which].y, protector[player][which].last);
- field[protector[player][which].x][protector[player][which].y] = protector[player][which].last;
- } else protector[player][which].visible = TRUE;
- protector[player][which].last = EMPTY;
-
- if (which == NOSE)
- { protector[player][which].relx = worm[player].deltax * NOSEDISTANCE;
- protector[player][which].rely = worm[player].deltay * NOSEDISTANCE;
- if (!worm[player].affixer)
- { if (worm[player].position == -1)
- worm[player].posidir = 1;
- elif (worm[player].position == 1)
- worm[player].posidir = -1;
- worm[player].position += worm[player].posidir;
- if (worm[player].deltax == 0)
- protector[player][which].relx = worm[player].position;
- elif (worm[player].deltay == 0)
- protector[player][which].rely = worm[player].position;
- elif (worm[player].position == -1)
- protector[player][which].relx = worm[player].deltax * (NOSEDISTANCE - 1);
- elif (worm[player].position == 1)
- protector[player][which].rely = worm[player].deltay * (NOSEDISTANCE - 1);
- } }
- elif (!worm[player].affixer)
- { if (protector[player][which].relx == 1 && protector[player][which].rely == -1)
- { protector[player][which].deltax = 0;
- protector[player][which].deltay = 1;
- } elif (protector[player][which].relx == 1 && protector[player][which].rely == 1)
- { protector[player][which].deltax = -1;
- protector[player][which].deltay = 0;
- } elif (protector[player][which].relx == -1 && protector[player][which].rely == 1)
- { protector[player][which].deltax = 0;
- protector[player][which].deltay = -1;
- } elif (protector[player][which].relx == -1 && protector[player][which].rely == -1)
- { protector[player][which].deltax = 1;
- protector[player][which].deltay = 0;
- }
- protector[player][which].relx += protector[player][which].deltax;
- protector[player][which].rely += protector[player][which].deltay;
- }
- protector[player][which].x = worm[player].x + protector[player][which].relx;
- protector[player][which].y = worm[player].y + protector[player][which].rely;
- if (!valid(protector[player][which].x, protector[player][which].y))
- protector[player][which].visible = FALSE;
- } }
-
- // collision detection
-
- creature = HEAD;
- while (creature != NULL)
- { if (creature == HEAD)
- { x = worm[player].x;
- y = worm[player].y;
- } else
- { x = protector[player][thisprot].x;
- y = protector[player][thisprot].y;
- }
- thissy = field[x][y];
- if (creature == HEAD)
- { if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (worm[player].mode != TONGUE)
- if (worm[thissy - FIRSTHEAD].mode != TONGUE)
- { // both worms die
- worm[player].cause = thissy;
- worm[player].alive = FALSE;
- worm[player].victor = -1;
- worm[thissy - FIRSTHEAD].cause = FIRSTHEAD + player;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- worm[thissy - FIRSTHEAD].victor = -1;
- } else
- { // this worm dies
- worm[player].cause = thissy;
- worm[player].alive = FALSE;
- worm[player].victor = thissy - FIRSTHEAD;
- }
- elif (worm[thissy - FIRSTHEAD].mode != TONGUE)
- { // other worm dies
- worm[thissy - FIRSTHEAD].cause = FIRSTHEAD + player;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- worm[thissy - FIRSTHEAD].victor = player;
- } }
- elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
- { if (worm[player].mode == TONGUE)
- { effect(FXUSETONGUE);
- if (lo != hi)
- if (player == thissy - FIRSTTAIL)
- { score += TURNTOSILVER;
- worm[player].last = SILVER;
- } else
- { score += TURNTOGOLD;
- worm[player].last = GOLD;
- } }
- else
- { worm[player].cause = thissy;
- worm[player].alive = FALSE;
- worm[player].victor = thissy - FIRSTTAIL;
- } }
- elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- if (worm[player].mode != ARMOUR)
- { worm[player].cause = thissy;
- worm[player].victor = thissy - FIRSTPROTECTOR;
- worm[player].alive = FALSE;
- } else effect(FXUSEARMOUR);
- elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { if (player != thissy - FIRSTMISSILE)
- { missile[thissy - FIRSTMISSILE].alive = FALSE;
- if (worm[player].mode != ARMOUR)
- { worm[player].alive = FALSE;
- worm[player].cause = thissy;
- worm[player].victor = thissy - FIRSTMISSILE;
- } else effect(FXUSEARMOUR);
- } }
- elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { which = whichdrip(x, y);
- drip[which].alive = FALSE;
- if (player == thissy - FIRSTDRIP || worm[player].bias)
- { effect(FXDRIP);
- wormscore(player, DRIPBONUS);
- } else
- { worm[player].alive = FALSE;
- worm[player].cause = thissy;
- worm[player].victor = -1;
- }
- } elif (thissy == STONE || thissy == KILLER || thissy == METAL)
- { worm[player].cause = thissy;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- ramming(player);
- } elif (thissy == WOOD)
- { if (worm[player].mode != TONGUE)
- { worm[player].cause = WOOD;
- worm[player].alive = FALSE;
- worm[player].victor = -1;
- } }
- elif (thissy == SLIME)
- { if (worm[player].mode != ARMOUR)
- { worm[player].cause = SLIME;
- worm[player].alive = FALSE;
- worm[player].victor = -1;
- } }
- elif (thissy == TELEPORT)
- { which = whichteleport(x, y);
- if (blocked(which, worm[player].deltax, worm[player].deltay))
- { worm[player].cause = TELEPORT;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- ramming(player);
- } else
- { effect(FXUSETELEPORT);
- score += TELPOINT;
- worm[player].x = xwrap(teleport[level][partner(which)].x + worm[player].deltax);
- worm[player].y = ywrap(teleport[level][partner(which)].y + worm[player].deltay);
- } } }
- else // creature == PROTECTOR
- { if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { if (player != thissy - FIRSTHEAD)
- { if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
- { effect(FXUSEPROTECTOR);
- worm[thissy - FIRSTHEAD].cause = FIRSTPROTECTOR + player;
- worm[thissy - FIRSTHEAD].alive = FALSE;
- worm[thissy - FIRSTHEAD].victor = player;
- } else
- { effect(FXUSEARMOUR);
- protector[player][thisprot].visible = FALSE;
- } }
- else // protector is over worm's own head; caused by ramming
- protector[player][thisprot].visible = FALSE;
- } elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
- { if (player == thissy - FIRSTTAIL || worm[player].mode == TONGUE)
- protector[player][thisprot].visible = FALSE;
- } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { protector[player][thisprot].alive = FALSE;
- for (which = 0; which <= PROTECTORS; which++)
- if (protector[thissy - FIRSTPROTECTOR][which].alive && protector[thissy - FIRSTPROTECTOR][which].x == x && protector[thissy - FIRSTPROTECTOR][which].y == y)
- { protector[thissy - FIRSTPROTECTOR][which].alive = FALSE;
- break;
- }
- draw(x, y, EMPTY);
- field[x][y] = EMPTY;
- } elif (thissy == STONE || thissy == WOOD || thissy == METAL)
- protector[player][thisprot].visible = FALSE;
- elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- { if (player != thissy - FIRSTMISSILE)
- { effect(FXUSEPROTECTOR);
- missile[thissy - FIRSTMISSILE].alive = FALSE;
- } else protector[player][thisprot].visible = FALSE;
- } elif (thissy == TELEPORT)
- { protector[player][thisprot].visible = FALSE;
- score += TELPOINT;
- } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
- { which = whichdrip(x, y);
- drip[which].alive = FALSE;
- if (player == thissy - FIRSTDRIP || worm[player].bias)
- { score += DRIPBONUS;
- effect(FXDRIP);
- } }
- elif (thissy == KILLER)
- { effect(FXUSEPROTECTOR);
- effect(FXKILLERDEATH);
- which = whichkiller(x, y);
- protector[player][thisprot].last = BONUS;
- killer[which].alive = FALSE;
- score += KILLKILLER;
- if (worm[player].bias)
- { worm[player].lives += KILLERBLOOD;
- stat(player, LIFE);
- } } }
- if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
- { wormletter(player, thissy);
- putletter(player);
- } elif (thissy <= LASTOBJECT)
- { score += object[thissy].score;
- if (thissy != SLAYER
- && thissy != BOMB
- && thissy != MISSILE
- && thissy != NITRO
- && thissy != POWER
- && thissy != AMMO)
- effect(FXGETOBJECT);
- switch(thissy)
- {
- case BONUS:
- if (!worm[player].bias)
- thisletter = rand() % (LETTERS + 1);
- else
- { complete = TRUE;
- for (which = 0; which <= LETTERS; which++)
- if (!letters[player][which])
- { complete = FALSE;
- do thisletter = rand() % (LETTERS + 1);
- while (letters[player][thisletter]);
- break;
- }
- if (complete)
- thisletter = rand() % (LETTERS + 1);
- }
- letters[player][thisletter] = TRUE;
- drawletter(player, FIRSTLETTER + thisletter, NORMAL);
- break;
- case AMMO:
- effect(FXGETAMMO);
- worm[player].ammo += (rand() % 5) + 2; // 2-6 bullets
- stat(player, AMMO);
- break;
- case ARMOUR:
- /* FXUSEDRILL sample will automatically stop, because
- a square with ARMOUR is not a square with TAIL. */
-
- worm[player].armour += MODEADD + (rand() % MODERAND);
- worm[player].mode = ARMOUR;
- stat(player, ARMOUR);
- break;
- case TONGUE:
- worm[player].tongue += MODEADD + (rand() % MODERAND);
- worm[player].mode = TONGUE;
- stat(player, TONGUE);
- worm[player].last = FIRSTTAIL + player;
- break;
- case NITRO:
- effect(FXGETNITRO);
- worm[player].nitro = TRUE;
- stat(player, NITRO);
- break;
- case BOMB:
- flag = FALSE;
- which = whichtimebomb(x, y);
- if (which != -1)
- { flag = TRUE;
- if (creature == HEAD)
- { // push timebomb
-
- if (valid(x + worm[player].deltax, y + worm[player].deltay))
- { ithis = field[x + worm[player].deltax][y + worm[player].deltay];
- if (ithis == TELEPORT)
- score += BOMBOVEREDGE;
- elif (ithis == SKULL)
- { effect(FXGETSKULL);
- score += SKULLPOINT;
- } elif (ithis <= LASTEMPTY)
- { if (ithis <= LASTOBJECT)
- { score += object[thissy].score;
- if (ithis == BOMB)
- { iwhich = whichtimebomb(x + worm[player].deltax, y + worm[player].deltay);
- if (iwhich != -1)
- timebomb[iwhich].alive = FALSE;
- } }
- timebomb[which].x += worm[player].deltax;
- timebomb[which].y += worm[player].deltay;
- field[timebomb[which].x][timebomb[which].y] = BOMB;
- draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
- } else flag = FALSE;
- } else score += BOMBOVEREDGE;
- } else protector[player][thisprot].visible = FALSE;
- }
- if (!flag)
- { if (worm[player].mode == NULL)
- draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- bombblast(HEAD, player, worm[player].x, worm[player].y);
- }
- break;
- case POWER:
- effect(FXGETPOWERUP);
- if (worm[player].power < POWERLIMIT)
- { worm[player].power += 2;
- stat(player, POWER);
- }
- break;
- case SLAYER:
- for (which = 0; which <= ORBS; which++)
- if (orb[which].alive)
- { score += orb[which].score;
- orb[which].explode = TRUE;
- if (worm[player].bias)
- worm[player].lives += ORBBLOOD;
- }
- for (which = 0; which <= KILLERS; which++)
- if (killer[which].alive)
- { effect(FXKILLERDEATH);
- killer[which].alive = FALSE;
- score += KILLKILLER;
- if (worm[player].bias)
- worm[player].lives += KILLERBLOOD;
- field[killer[which].x][killer[which].y] = BONUS;
- draw(killer[which].x, killer[which].y, BONUS);
- }
- for (which = 0; which <= DRIPS; which++)
- { drip[which].alive = FALSE;
- field[drip[which].x][drip[which].y] = EMPTY;
- draw(drip[which].x, drip[which].y, EMPTY);
- }
- for (which = lo; which <= hi; which++)
- if (player != which && worm[which].mode != ARMOUR)
- { worm[which].alive = FALSE;
- worm[which].cause = SLAYER;
- worm[which].victor = player;
- }
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SLIME)
- { draw(x, y, EMPTY);
- field[x][y] = EMPTY;
- }
- if (worm[player].bias)
- stat(player, LIFE);
- break;
- case PROTECTOR:
- done = FALSE;
- for (which = 0; which <= PROTECTORS; which++)
- if (!protector[player][which].alive && !done)
- { do
- { protector[player][which].relx = ((rand() % 2) * 2) - 1;
- protector[player][which].rely = ((rand() % 2) * 2) - 1;
- for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
- if (which == NOSE || !protector[player][iwhich].alive || protector[player][iwhich].x != xwrap(worm[player].x + protector[player][which].relx) || protector[player][iwhich].y != ywrap(worm[player].y + protector[player][which].rely))
- { effect(FXPROTECTORBORN);
- done = TRUE;
- protector[player][which].alive = TRUE;
- protector[player][which].visible = FALSE;
- protector[player][which].last = EMPTY;
- if (which == NOSE)
- worm[player].position = -1;
- }
- } while (!done);
- }
- break;
- case MISSILE:
- if (!missile[player].alive)
- { missile[player].alive = TRUE;
- missile[player].x = worm[player].x;
- missile[player].y = worm[player].y;
- missile[player].moved = FALSE;
- }
- break;
- case LIFE:
- worm[player].lives += (rand() % 5) + 2; // 2-6 lives
- stat(player, LIFE);
- break;
- case MULTIPLIER:
- if (worm[player].multi < MULTILIMIT)
- worm[player].multi *= 2;
- break;
- case BIAS:
- worm[player].bias += MODEADD + (rand() % MODERAND);
- stat(player, BIAS);
- break;
- case ICE:
- worm[player].ice += ICEADD + (rand() % ICERAND);
- ice = player;
- break;
- case GROWER:
- effect(FXGETGROWER);
-
- // grow tail
-
- if (worm[player].bias)
- { for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == FIRSTTAIL + player)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY)
- field[xx][yy] = TEMPTAIL;
- }
-
- // grow silver
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == SILVER)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPTAIL)
- field[xx][yy] = TEMPSILVER;
-
- // grow gold
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] == GOLD)
- for (xx = x - 1; xx <= x + 1; xx++)
- for (yy = y - 1; yy <= y + 1; yy++)
- if (valid(xx, yy))
- if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPTAIL || field[xx][yy] == TEMPSILVER)
- field[xx][yy] = TEMPGOLD;
-
- // update
-
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- switch (field[x][y])
- {
- case TEMPGOLD:
- field[x][y] = GOLD;
- draw(x, y, GOLD);
- break;
- case TEMPSILVER:
- field[x][y] = SILVER;
- draw(x, y, SILVER);
- break;
- case TEMPTAIL:
- field[x][y] = FIRSTTAIL + player;
- draw(x, y, FIRSTTAIL + player);
- break;
- default:
- break;
- }
- break;
- case TREASURE:
- treasurer = player;
- if (level)
- { say((STRPTR) "Treasure!", worm[treasurer].colour);
- secondsperlevel = 0;
- }
- secondsperlevel += TREASUREADD + (rand() % TREASURERAND);
- if (level)
- { stat(player, BONUS);
- reallevel = level;
- level = 0;
- newlevel(player);
- }
- break;
- case AFFIXER:
- worm[player].affixer = TRUE;
- break;
- case SWITCHER:
- if (lo != hi)
- for (x = 0; x <= FIELDX; x++)
- for (y = 0; y <= FIELDY; y++)
- if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL && field[x][y] != FIRSTTAIL + player)
- { field[x][y] = FIRSTTAIL + player;
- draw(x, y, FIRSTTAIL + player);
- }
- break;
- case HEALER:
- if (worm[player].lives < 100)
- worm[player].lives = 100;
- else worm[player].lives = LIVESLIMIT;
- stat(player, LIFE);
- break;
- case UMBRELLA:
- level += (rand() % 3);
- if (level >= levels)
- level = level - 1;
- for (i = 0; i <= LETTERS; i++)
- letters[player][i] = TRUE;
- break;
- case CLOCK:
- if (secondsleft)
- secondsperlevel += (rand() % CLOCKRAND) + CLOCKADD;
- break;
- case SLOWER:
- dripspeed = (SBYTE) atleast( dripspeed * 2, VERYFAST);
- fragspeed = (SBYTE) atleast( fragspeed * 2, VERYFAST);
- killerspeed = (SBYTE) atleast(killerspeed * 2, VERYFAST);
- orbspeed = (SBYTE) atleast( orbspeed * 2, VERYFAST);
- for (i = 0; i <= ORBS; i++)
- if (orb[i].alive)
- orb[i].speed = (SBYTE) atleast(orb[i].speed * 2, VERYFAST);
- break;
- default:
- break;
- } }
- else
- { switch (thissy)
- {
- case EMPTY:
- score += EMPTYPOINT;
- break;
- case SILVER:
- score += SILVERPOINT;
- break;
- case GOLD:
- score += GOLDPOINT;
- break;
- case ORB:
- iwhich = whichorb(x, y);
- if (worm[player].mode == ARMOUR || creature == PROTECTOR)
- { if (creature == HEAD)
- effect(FXUSEARMOUR);
- else effect(FXUSEPROTECTOR);
- effect(FXORBDEATH);
- score += orb[iwhich].score;
- orb[iwhich].alive = FALSE;
- if (worm[player].bias)
- { worm[player].lives += ORBBLOOD;
- stat(player, LIFE);
- } }
- else
- { if (orb[iwhich].mode == ARMOUR)
- { effect(FXUSEARMOUR);
- orbscore(iwhich, KILLWORM);
- } else orb[iwhich].alive = FALSE;
- worm[player].cause = ORB;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- }
- break;
- case FRAGMENT:
- whichfrag(x, y, &which, &iwhich);
- if (creature == HEAD)
- { if (worm[player].mode != ARMOUR)
- { worm[player].cause = FRAGMENT;
- worm[player].victor = -1;
- worm[player].alive = FALSE;
- frag[which][iwhich].alive = FALSE;
- } else
- { effect(FXUSEARMOUR);
- reflect(which, iwhich);
- } }
- else
- { effect(FXUSEPROTECTOR);
- reflect(which, iwhich);
- }
- break;
- case SKULL:
- effect(FXGETSKULL);
- score += SKULLPOINT;
- for (which = lo; which <= hi; which++)
- { if (worm[which].alive == FALSE && worm[which].x == worm[player].x && worm[which].y == worm[player].y)
- iwhich = which;
- }
- worm[player].bias += worm[iwhich].bias;
- if (worm[player].bias > 0)
- { stat(player, BIAS);
- worm[iwhich].bias = 0;
- stat(iwhich, BIAS);
- }
- worm[player].multi *= worm[iwhich].multi;
- if (worm[player].multi > 1)
- { if (worm[player].multi > MULTILIMIT)
- worm[player].multi = MULTILIMIT;
- }
- worm[player].power += worm[iwhich].power;
- if (worm[player].power > 1)
- { if (worm[player].power > POWERLIMIT)
- worm[player].power = POWERLIMIT;
- stat(player, POWER);
- worm[iwhich].power = 0;
- stat(iwhich, POWER);
- }
- worm[player].ammo += worm[iwhich].ammo;
- if (worm[player].ammo > 0)
- { stat(player, AMMO);
- worm[iwhich].ammo = 0;
- stat(iwhich, AMMO);
- }
- worm[player].armour += worm[iwhich].armour;
- if (worm[player].armour > 0)
- { stat(player, ARMOUR);
- worm[iwhich].armour = 0;
- stat(iwhich, ARMOUR);
- }
- worm[player].tongue += worm[iwhich].tongue;
- if (worm[player].tongue > 0)
- { stat(player, TONGUE);
- worm[iwhich].tongue = 0;
- stat(iwhich, TONGUE);
- }
- if (worm[player].armour > 0 || worm[player].tongue > 0)
- { if (worm[player].armour >= worm[player].tongue)
- worm[player].mode = ARMOUR;
- else worm[player].mode = TONGUE;
- }
- if (worm[iwhich].nitro)
- { worm[player].nitro = TRUE;
- stat(player, NITRO);
- worm[iwhich].nitro = FALSE;
- worm[iwhich].speed = NORMAL;
- stat(iwhich, NITRO);
- }
- for (which = 0; which <= LETTERS; which++)
- if (letters[iwhich][which])
- { drawletter(iwhich, FIRSTLETTER + which, BLACK);
- if (!letters[player][which])
- { letters[player][which] = TRUE;
- drawletter(player, FIRSTLETTER + which, NORMAL);
- } }
- break;
- default:
- break;
- } }
- if (creature == HEAD)
- // it is important that HEAD is done before PROTECTORs
- { field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
- if (worm[player].alive)
- { switch (worm[player].mode)
- {
- case NULL:
- draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- break;
- case TONGUE:
- if (worm[player].tongue < 10 && (r / SLOW) % 2 == 0)
- draw(worm[player].x, worm[player].y, WHITENED);
- else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- break;
- case ARMOUR:
- if (worm[player].armour < 10 && (r / SLOW) % 2 == 0)
- draw(worm[player].x, worm[player].y, WHITENED);
- else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
- break;
- default:
- break;
- } }
- else draw(worm[player].x, worm[player].y, SKULL);
- } else // assumes creature == PROTECTOR
- if (protector[player][thisprot].alive && protector[player][thisprot].visible)
- { field[x][y] = FIRSTPROTECTOR + player;
- draw(x, y, FIRSTPROTECTOR + player);
- }
- while (++thisprot <= PROTECTORS)
- if (protector[player][thisprot].alive && valid(protector[player][thisprot].x, protector[player][thisprot].y))
- break;
- if (thisprot > PROTECTORS)
- creature = NULL;
- else creature = PROTECTOR;
- }
- wormscore(player, score);
- }
-
- void wormscore(SBYTE player, LONG score)
- { worm[player].score += score * worm[player].multi;
- stat(player, BONUS);
- }
-
- SWORD wsign(SWORD value)
- { if (value < 0)
- return (-1);
- elif (value > 0)
- return (1);
- else
- return (0);
- }
-
- SWORD xpixeltosquare(SWORD x)
- { x = (x - STARTXPIXEL) / SQUAREX;
- if (x < 0)
- x--;
- return (x);
- }
- SWORD ypixeltosquare(SWORD y)
- { y = (y - STARTYPIXEL) / SQUAREY;
- if (y < 0)
- y--;
- return (y);
- }
-
- SBYTE xwrap(SBYTE x)
- { if (x < 0)
- x += FIELDX + 1;
- elif (x > FIELDX)
- x -= FIELDX + 1;
- return(x);
- }
- SBYTE ywrap(SBYTE y)
- { if (y < 0)
- y += FIELDY + 1;
- elif (y > FIELDY)
- y -= FIELDY + 1;
- return(y);
- }
- void ramming(SBYTE player)
- { SBYTE i;
-
- worm[player].x = xwrap(worm[player].x - worm[player].deltax);
- worm[player].y = ywrap(worm[player].y - worm[player].deltay);
- for (i = 0; i <= PROTECTORS; i++)
- { // no point checking whether the protectors are alive or dead
- protector[player][i].x -= worm[player].deltax;
- protector[player][i].y -= worm[player].deltay;
- } }
-
- void driploop(void)
- { SBYTE i, j, k, thissy;
-
- for (i = 0; i <= DRIPS; i++)
- if (drip[i].alive)
- { if (drip[i].moved)
- { field[drip[i].x][drip[i].y] = EMPTY;
- draw(drip[i].x, drip[i].y, EMPTY);
- } else drip[i].moved = TRUE;
- drip[i].y++;
- if (!valid(drip[i].x, drip[i].y))
- drip[i].alive = FALSE;
- else
- { thissy = field[drip[i].x][drip[i].y];
- if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
- { drip[i].alive = FALSE;
- if (drip[i].type - FIRSTDRIP == thissy - FIRSTHEAD || worm[thissy - FIRSTHEAD].bias)
- { effect(FXDRIP);
- wormscore(thissy - FIRSTHEAD, DRIPBONUS);
- } else
- { worm[thissy - FIRSTHEAD].alive = FALSE;
- worm[thissy - FIRSTHEAD].cause = drip[i].type;
- worm[thissy - FIRSTHEAD].victor = -1;
- } }
- elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
- { drip[i].alive = FALSE;
- if (drip[i].type == thissy - FIRSTPROTECTOR + FIRSTDRIP || worm[thissy - FIRSTPROTECTOR].bias)
- { wormscore(thissy - FIRSTPROTECTOR, DRIPBONUS);
- effect(FXDRIP);
- } }
- elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
- drip[i].alive = FALSE;
- elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
- missile[thissy - FIRSTMISSILE].alive = FALSE;
- else switch(thissy)
- {
- case FRAGMENT:
- drip[i].alive = FALSE;
- whichfrag(drip[i].x, drip[i].y, &j, &k);
- frag[j][k].alive = BONUS;
- draw(drip[i].x, drip[i].y, BONUS);
- case ORB:
- drip[i].alive = FALSE;
- j = whichorb(drip[i].x, drip[i].y);
- if (orb[j].mode != ARMOUR)
- { orb[j].explode = TRUE;
- draw(drip[i].x, drip[i].y, EMPTY);
- }
- break;
- case KILLER:
- drip[i].alive = FALSE;
- j = whichkiller(drip[i].x, drip[i].y);
- killer[j].alive = FALSE;
- field[drip[i].x][drip[i].y] = BONUS;
- draw(drip[i].x, drip[i].y, BONUS);
- break;
- case SLIME:
- drip[i].alive = FALSE;
- field[drip[i].x][drip[i].y] = EMPTY;
- draw(drip[i].x, drip[i].y, EMPTY);
- break;
- case STONE:
- drip[i].alive = FALSE;
- break;
- case METAL:
- drip[i].alive = FALSE;
- break;
- case TELEPORT:
- j = whichteleport(drip[i].x, drip[i].y);
- if (blocked(j, 0, 1))
- drip[i].alive = FALSE;
- else
- { drip[i].x = teleport[level][partner(j)].x;
- drip[i].y = teleport[level][partner(j)].y;
- drip[i].moved = FALSE;
- }
- break;
- default:
- break;
- }
- if (drip[i].alive)
- { draw(drip[i].x, drip[i].y, drip[i].type);
- field[drip[i].x][drip[i].y] = drip[i].type;
- } } } }
-
- SWORD atleast(SWORD value, SWORD minimum)
- { if (value < minimum)
- return(minimum);
- else return(value);
- }
-
- void orbscore(SBYTE which, ULONG score)
- { orb[which].score += score * orb[which].multi;
- }
-
- // Must have blank line at EOF.
-