+ }
+#endif
+
+ for (y=0; y<lev_fieldy; y++)
+ {
+ for (x=0; x<lev_fieldx; x++)
+ {
+ if (AmoebaNr[x][y] == group_nr &&
+ (Feld[x][y] == EL_AMOEBA_DEAD ||
+ Feld[x][y] == EL_BD_AMOEBA ||
+ Feld[x][y] == EL_AMOEBA_GROWING))
+ {
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = new_element;
+ InitField(x, y, FALSE);
+ DrawLevelField(x, y);
+ done = TRUE;
+ }
+ }
+ }
+
+ if (done)
+ PlayLevelSound(ax, ay, (new_element == EL_BD_ROCK ?
+ SND_BD_AMOEBA_TURNING_TO_ROCK :
+ SND_BD_AMOEBA_TURNING_TO_GEM));
+}
+
+void AmoebeWaechst(int x, int y)
+{
+ static unsigned long sound_delay = 0;
+ static unsigned long sound_delay_value = 0;
+
+ if (!MovDelay[x][y]) /* start new growing cycle */
+ {
+ MovDelay[x][y] = 7;
+
+ if (DelayReached(&sound_delay, sound_delay_value))
+ {
+#if 1
+ PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
+#else
+ if (Store[x][y] == EL_BD_AMOEBA)
+ PlayLevelSound(x, y, SND_BD_AMOEBA_GROWING);
+ else
+ PlayLevelSound(x, y, SND_AMOEBA_GROWING);
+#endif
+ sound_delay_value = 30;
+ }
+ }
+
+ if (MovDelay[x][y]) /* wait some time before growing bigger */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ {
+ int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
+ 6 - MovDelay[x][y]);
+
+ DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
+ }
+
+ if (!MovDelay[x][y])
+ {
+ Feld[x][y] = Store[x][y];
+ Store[x][y] = 0;
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+void AmoebaDisappearing(int x, int y)
+{
+ static unsigned long sound_delay = 0;
+ static unsigned long sound_delay_value = 0;
+
+ if (!MovDelay[x][y]) /* start new shrinking cycle */
+ {
+ MovDelay[x][y] = 7;
+
+ if (DelayReached(&sound_delay, sound_delay_value))
+ sound_delay_value = 30;
+ }
+
+ if (MovDelay[x][y]) /* wait some time before shrinking */
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ {
+ int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
+ 6 - MovDelay[x][y]);
+
+ DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
+ }
+
+ if (!MovDelay[x][y])
+ {
+ Feld[x][y] = EL_EMPTY;
+ DrawLevelField(x, y);
+
+ /* don't let mole enter this field in this cycle;
+ (give priority to objects falling to this field from above) */
+ Stop[x][y] = TRUE;
+ }
+ }
+}
+
+void AmoebeAbleger(int ax, int ay)
+{
+ int i;
+ int element = Feld[ax][ay];
+ int graphic = el2img(element);
+ int newax = ax, neway = ay;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ if (!level.amoeba_speed)
+ {
+ Feld[ax][ay] = EL_AMOEBA_DEAD;
+ DrawLevelField(ax, ay);
+ return;
+ }
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
+
+ if (!MovDelay[ax][ay]) /* start making new amoeba field */
+ MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
+
+ if (MovDelay[ax][ay]) /* wait some time before making new amoeba */
+ {
+ MovDelay[ax][ay]--;
+ if (MovDelay[ax][ay])
+ return;
+ }
+
+ if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
+ {
+ int start = RND(4);
+ int x = ax + xy[start][0];
+ int y = ay + xy[start][1];
+
+ if (!IN_LEV_FIELD(x, y))
+ return;
+
+ /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
+ if (IS_FREE(x, y) ||
+ Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
+ {
+ newax = x;
+ neway = y;
+ }
+
+ if (newax == ax && neway == ay)
+ return;
+ }
+ else /* normal or "filled" (BD style) amoeba */
+ {
+ int start = RND(4);
+ boolean waiting_for_player = FALSE;
+
+ for (i=0; i<4; i++)
+ {
+ int j = (start + i) % 4;
+ int x = ax + xy[j][0];
+ int y = ay + xy[j][1];
+
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
+ if (IS_FREE(x, y) ||
+ Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
+ {
+ newax = x;
+ neway = y;
+ break;
+ }
+ else if (IS_PLAYER(x, y))
+ waiting_for_player = TRUE;
+ }
+
+ if (newax == ax && neway == ay) /* amoeba cannot grow */
+ {
+ if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
+ {
+ Feld[ax][ay] = EL_AMOEBA_DEAD;
+ DrawLevelField(ax, ay);
+ AmoebaCnt[AmoebaNr[ax][ay]]--;
+
+ if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */
+ {
+ if (element == EL_AMOEBA_FULL)
+ AmoebeUmwandeln(ax, ay);
+ else if (element == EL_BD_AMOEBA)
+ AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
+ }
+ }
+ return;
+ }
+ else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
+ {
+ /* amoeba gets larger by growing in some direction */
+
+ int new_group_nr = AmoebaNr[ax][ay];
+
+#ifdef DEBUG
+ if (new_group_nr == 0)
+ {
+ printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
+ printf("AmoebeAbleger(): This should never happen!\n");
+ return;
+ }
+#endif
+
+ AmoebaNr[newax][neway] = new_group_nr;
+ AmoebaCnt[new_group_nr]++;
+ AmoebaCnt2[new_group_nr]++;
+
+ /* if amoeba touches other amoeba(s) after growing, unify them */
+ AmoebenVereinigen(newax, neway);
+
+ if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
+ {
+ AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
+ return;
+ }
+ }
+ }
+
+ if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
+ (neway == lev_fieldy - 1 && newax != ax))
+ {
+ Feld[newax][neway] = EL_AMOEBA_GROWING; /* creation of new amoeba */
+ Store[newax][neway] = element;
+ }
+ else if (neway == ay)
+ {
+ Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */
+#if 1
+ PlayLevelSoundAction(newax, neway, ACTION_GROWING);
+#else
+ PlayLevelSound(newax, neway, SND_AMOEBA_GROWING);
+#endif
+ }
+ else
+ {
+ InitMovingField(ax, ay, MV_DOWN); /* drop dripping from amoeba */
+ Feld[ax][ay] = EL_AMOEBA_DROPPING;
+ Store[ax][ay] = EL_AMOEBA_DROP;
+ ContinueMoving(ax, ay);
+ return;
+ }
+
+ DrawLevelField(newax, neway);
+}
+
+void Life(int ax, int ay)
+{
+ int x1, y1, x2, y2;
+ static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
+ int life_time = 40;
+ int element = Feld[ax][ay];
+ int graphic = el2img(element);
+ boolean changed = FALSE;
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
+
+ if (Stop[ax][ay])
+ return;
+
+ if (!MovDelay[ax][ay]) /* start new "game of life" cycle */
+ MovDelay[ax][ay] = life_time;
+
+ if (MovDelay[ax][ay]) /* wait some time before next cycle */
+ {
+ MovDelay[ax][ay]--;
+ if (MovDelay[ax][ay])
+ return;
+ }
+
+ for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
+ {
+ int xx = ax+x1, yy = ay+y1;
+ int nachbarn = 0;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
+ {
+ int x = xx+x2, y = yy+y2;
+
+ if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
+ continue;
+
+ if (((Feld[x][y] == element ||
+ (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) &&
+ !Stop[x][y]) ||
+ (IS_FREE(x, y) && Stop[x][y]))
+ nachbarn++;
+ }
+
+ if (xx == ax && yy == ay) /* field in the middle */
+ {
+ if (nachbarn < life[0] || nachbarn > life[1])
+ {
+ Feld[xx][yy] = EL_EMPTY;
+ if (!Stop[xx][yy])
+ DrawLevelField(xx, yy);
+ Stop[xx][yy] = TRUE;
+ changed = TRUE;
+ }
+ }
+ /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
+ else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
+ { /* free border field */
+ if (nachbarn >= life[2] && nachbarn <= life[3])
+ {
+ Feld[xx][yy] = element;
+ MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
+ if (!Stop[xx][yy])
+ DrawLevelField(xx, yy);
+ Stop[xx][yy] = TRUE;
+ changed = TRUE;
+ }
+ }
+ }
+
+ if (changed)
+ PlayLevelSound(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING :
+ SND_GAME_OF_LIFE_GROWING);
+}
+
+static void InitRobotWheel(int x, int y)
+{
+ ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
+}
+
+static void RunRobotWheel(int x, int y)
+{
+ PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE);
+}
+
+static void StopRobotWheel(int x, int y)
+{
+ if (ZX == x && ZY == y)
+ ZX = ZY = -1;
+}
+
+static void InitTimegateWheel(int x, int y)
+{
+ ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
+}
+
+static void RunTimegateWheel(int x, int y)
+{
+ PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
+}
+
+void CheckExit(int x, int y)
+{
+ if (local_player->gems_still_needed > 0 ||
+ local_player->sokobanfields_still_needed > 0 ||
+ local_player->lights_still_needed > 0)
+ {
+ int element = Feld[x][y];
+ int graphic = el2img(element);
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+ return;
+ }
+
+ if (AllPlayersGone) /* do not re-open exit door closed after last player */
+ return;
+
+ Feld[x][y] = EL_EXIT_OPENING;
+
+ PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING);
+}
+
+void CheckExitSP(int x, int y)
+{
+ if (local_player->gems_still_needed > 0)
+ {
+ int element = Feld[x][y];
+ int graphic = el2img(element);
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+ return;
+ }
+
+ if (AllPlayersGone) /* do not re-open exit door closed after last player */
+ return;
+
+ Feld[x][y] = EL_SP_EXIT_OPENING;
+
+ PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
+}
+
+static void CloseAllOpenTimegates()
+{
+ int x, y;
+
+ for (y=0; y<lev_fieldy; y++)
+ {
+ for (x=0; x<lev_fieldx; x++)
+ {
+ int element = Feld[x][y];
+
+ if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
+ {
+ Feld[x][y] = EL_TIMEGATE_CLOSING;
+#if 1
+ PlayLevelSoundAction(x, y, ACTION_CLOSING);
+#else
+ PlayLevelSound(x, y, SND_TIMEGATE_CLOSING);
+#endif
+ }
+ }
+ }
+}
+
+void EdelsteinFunkeln(int x, int y)
+{
+ if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
+ return;