+ /* put moving element to center field (and let it explode there) */
+ center_element = MovingOrBlocked2Element(ex, ey);
+ RemoveMovingField(ex, ey);
+ Feld[ex][ey] = center_element;
+ }
+
+ /* now "center_element" is finally determined -- set related values now */
+ artwork_element = center_element; /* for custom player artwork */
+ explosion_element = center_element; /* for custom player artwork */
+
+ if (IS_PLAYER(ex, ey))
+ {
+ int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]);
+
+ artwork_element = stored_player[player_nr].artwork_element;
+
+ if (level.use_explosion_element[player_nr])
+ {
+ explosion_element = level.explosion_element[player_nr];
+ artwork_element = explosion_element;
+ }
+ }
+
+#if 1
+ if (mode == EX_TYPE_NORMAL ||
+ mode == EX_TYPE_CENTER ||
+ mode == EX_TYPE_CROSS)
+ PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING);
+#endif
+
+#if 1
+ last_phase = element_info[explosion_element].explosion_delay + 1;
+#else
+ last_phase = element_info[center_element].explosion_delay + 1;
+#endif
+
+ for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
+ {
+ int xx = x - ex + 1;
+ int yy = y - ey + 1;
+ int element;
+
+ if (!IN_LEV_FIELD(x, y) ||
+ (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) ||
+ (mode == EX_TYPE_CROSS && (x != ex && y != ey)))
+ continue;
+
+ element = Feld[x][y];
+
+ if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+ {
+ element = MovingOrBlocked2Element(x, y);
+
+ if (!IS_EXPLOSION_PROOF(element))
+ RemoveMovingField(x, y);
+ }
+
+ /* indestructible elements can only explode in center (but not flames) */
+ if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey ||
+ mode == EX_TYPE_BORDER)) ||
+ element == EL_FLAMES)
+ continue;
+
+ /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy
+ behaviour, for example when touching a yamyam that explodes to rocks
+ with active deadly shield, a rock is created under the player !!! */
+ /* (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) */
+#if 0
+ if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
+ (game.engine_version < VERSION_IDENT(3,1,0,0) ||
+ (x == ex && y == ey && mode != EX_TYPE_BORDER)))
+#else
+ if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
+#endif
+ {
+ if (IS_ACTIVE_BOMB(element))
+ {
+ /* re-activate things under the bomb like gate or penguin */
+ Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
+ Back[x][y] = 0;
+ }
+
+ continue;
+ }
+
+ /* save walkable background elements while explosion on same tile */
+ if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
+ (x != ex || y != ey || mode == EX_TYPE_BORDER))
+ Back[x][y] = element;
+
+ /* ignite explodable elements reached by other explosion */
+ if (element == EL_EXPLOSION)
+ element = Store2[x][y];
+
+ if (AmoebaNr[x][y] &&
+ (element == EL_AMOEBA_FULL ||
+ element == EL_BD_AMOEBA ||
+ element == EL_AMOEBA_GROWING))
+ {
+ AmoebaCnt[AmoebaNr[x][y]]--;
+ AmoebaCnt2[AmoebaNr[x][y]]--;
+ }
+
+ RemoveField(x, y);
+
+ if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
+ {
+#if 1
+ int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1;
+
+ Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr;
+#else
+ switch(StorePlayer[ex][ey])
+ {
+ case EL_PLAYER_2:
+ Store[x][y] = EL_PLAYER_IS_EXPLODING_2;
+ break;
+ case EL_PLAYER_3:
+ Store[x][y] = EL_PLAYER_IS_EXPLODING_3;
+ break;
+ case EL_PLAYER_4:
+ Store[x][y] = EL_PLAYER_IS_EXPLODING_4;
+ break;
+ case EL_PLAYER_1:
+ default:
+ Store[x][y] = EL_PLAYER_IS_EXPLODING_1;
+ break;
+ }
+#endif
+
+ if (PLAYERINFO(ex, ey)->use_murphy)
+ Store[x][y] = EL_EMPTY;
+ }
+#if 1
+ /* !!! check this case -- currently needed for rnd_rado_negundo_v,
+ !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */
+ else if (ELEM_IS_PLAYER(center_element))
+ Store[x][y] = EL_EMPTY;
+ else if (center_element == EL_YAMYAM)
+ Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
+ else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+ Store[x][y] = element_info[center_element].content.e[xx][yy];
+#if 1
+ /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE"
+ (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond
+ otherwise) -- FIX THIS !!! */
+ else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY)
+ Store[x][y] = element_info[element].content.e[1][1];
+#else
+ else if (!CAN_EXPLODE(element))
+ Store[x][y] = element_info[element].content.e[1][1];
+#endif
+ else
+ Store[x][y] = EL_EMPTY;
+#else
+ else if (center_element == EL_MOLE)
+ Store[x][y] = EL_EMERALD_RED;
+ else if (center_element == EL_PENGUIN)
+ Store[x][y] = EL_EMERALD_PURPLE;
+ else if (center_element == EL_BUG)
+ Store[x][y] = ((x == ex && y == ey) ? EL_DIAMOND : EL_EMERALD);
+ else if (center_element == EL_BD_BUTTERFLY)
+ Store[x][y] = EL_BD_DIAMOND;
+ else if (center_element == EL_SP_ELECTRON)
+ Store[x][y] = EL_SP_INFOTRON;
+ else if (center_element == EL_AMOEBA_TO_DIAMOND)
+ Store[x][y] = level.amoeba_content;
+ else if (center_element == EL_YAMYAM)
+ Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
+ else if (IS_CUSTOM_ELEMENT(center_element) &&
+ element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+ Store[x][y] = element_info[center_element].content.e[xx][yy];
+ else if (element == EL_WALL_EMERALD)
+ Store[x][y] = EL_EMERALD;
+ else if (element == EL_WALL_DIAMOND)
+ Store[x][y] = EL_DIAMOND;
+ else if (element == EL_WALL_BD_DIAMOND)
+ Store[x][y] = EL_BD_DIAMOND;
+ else if (element == EL_WALL_EMERALD_YELLOW)
+ Store[x][y] = EL_EMERALD_YELLOW;
+ else if (element == EL_WALL_EMERALD_RED)
+ Store[x][y] = EL_EMERALD_RED;
+ else if (element == EL_WALL_EMERALD_PURPLE)
+ Store[x][y] = EL_EMERALD_PURPLE;
+ else if (element == EL_WALL_PEARL)
+ Store[x][y] = EL_PEARL;
+ else if (element == EL_WALL_CRYSTAL)
+ Store[x][y] = EL_CRYSTAL;
+ else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
+ Store[x][y] = element_info[element].content.e[1][1];
+ else
+ Store[x][y] = EL_EMPTY;
+#endif
+
+ if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
+ center_element == EL_AMOEBA_TO_DIAMOND)
+ Store2[x][y] = element;
+
+ Feld[x][y] = EL_EXPLOSION;
+ GfxElement[x][y] = artwork_element;
+
+#if 0
+ printf(":: setting gfx(%d,%d) to %d ['%s']\n",
+ x, y, artwork_element, EL_NAME(artwork_element));
+#endif
+
+ ExplodePhase[x][y] = 1;
+ ExplodeDelay[x][y] = last_phase;
+
+ Stop[x][y] = TRUE;
+ }
+
+ if (center_element == EL_YAMYAM)
+ game.yamyam_content_nr =
+ (game.yamyam_content_nr + 1) % level.num_yamyam_contents;
+
+ return;
+ }
+
+ if (Stop[ex][ey])
+ return;
+
+ x = ex;
+ y = ey;
+
+ if (phase == 1)
+ GfxFrame[x][y] = 0; /* restart explosion animation */
+
+ last_phase = ExplodeDelay[x][y];
+
+ ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
+
+#ifdef DEBUG
+
+ /* activate this even in non-DEBUG version until cause for crash in
+ getGraphicAnimationFrame() (see below) is found and eliminated */
+
+#endif
+#if 1
+
+#if 1
+ /* this can happen if the player leaves an explosion just in time */
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ GfxElement[x][y] = EL_EMPTY;
+#else
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ {
+ printf("\n\n");
+ printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
+ printf("Explode(): This should never happen!\n");
+ printf("\n\n");
+
+ GfxElement[x][y] = EL_EMPTY;
+ }
+#endif
+
+#endif
+
+ border_element = Store2[x][y];
+ if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
+ border_element = StorePlayer[x][y];
+
+ if (phase == element_info[border_element].ignition_delay ||
+ phase == last_phase)
+ {
+ boolean border_explosion = FALSE;
+
+ if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present &&
+ !PLAYER_EXPLOSION_PROTECTED(x, y))
+ {
+ KillPlayerUnlessExplosionProtected(x, y);
+ border_explosion = TRUE;
+ }
+ else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
+ {
+ Feld[x][y] = Store2[x][y];
+ Store2[x][y] = 0;
+ Bang(x, y);
+ border_explosion = TRUE;
+ }
+ else if (border_element == EL_AMOEBA_TO_DIAMOND)
+ {
+ AmoebeUmwandeln(x, y);
+ Store2[x][y] = 0;
+ border_explosion = TRUE;
+ }
+
+ /* if an element just explodes due to another explosion (chain-reaction),
+ do not immediately end the new explosion when it was the last frame of
+ the explosion (as it would be done in the following "if"-statement!) */
+ if (border_explosion && phase == last_phase)
+ return;
+ }
+
+ if (phase == last_phase)
+ {
+ int element;
+
+ element = Feld[x][y] = Store[x][y];
+ Store[x][y] = Store2[x][y] = 0;
+ GfxElement[x][y] = EL_UNDEFINED;
+
+ /* player can escape from explosions and might therefore be still alive */
+ if (element >= EL_PLAYER_IS_EXPLODING_1 &&
+ element <= EL_PLAYER_IS_EXPLODING_4)
+ {
+ int player_nr = element - EL_PLAYER_IS_EXPLODING_1;
+ int explosion_element = EL_PLAYER_1 + player_nr;
+ int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2);
+ int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2);
+
+ if (level.use_explosion_element[player_nr])
+ explosion_element = level.explosion_element[player_nr];
+
+ Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY :
+ element_info[explosion_element].content.e[xx][yy]);
+ }
+
+ /* restore probably existing indestructible background element */
+ if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
+ element = Feld[x][y] = Back[x][y];
+ Back[x][y] = 0;
+
+ MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+ GfxDir[x][y] = MV_NONE;
+ ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
+
+#if USE_NEW_CUSTOM_VALUE
+ CustomValue[x][y] = 0;
+#endif
+
+ InitField_WithBug2(x, y, FALSE);
+
+ DrawLevelField(x, y);
+
+ TestIfElementTouchesCustomElement(x, y);
+
+ if (GFX_CRUMBLED(element))
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+
+ if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
+ StorePlayer[x][y] = 0;
+
+ if (ELEM_IS_PLAYER(element))
+ RelocatePlayer(x, y, element);
+ }
+ else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ {
+ int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
+ int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+
+ if (phase == delay)
+ DrawLevelFieldCrumbledSand(x, y);
+
+ if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
+ {
+ DrawLevelElement(x, y, Back[x][y]);
+ DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
+ }
+ else if (IS_WALKABLE_UNDER(Back[x][y]))
+ {
+ DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelElementThruMask(x, y, Back[x][y]);
+ }
+ else if (!IS_WALKABLE_INSIDE(Back[x][y]))
+ DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ }
+}
+
+void DynaExplode(int ex, int ey)
+{
+ int i, j;
+ int dynabomb_element = Feld[ex][ey];
+ int dynabomb_size = 1;
+ boolean dynabomb_xl = FALSE;
+ struct PlayerInfo *player;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ if (IS_ACTIVE_BOMB(dynabomb_element))
+ {
+ player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE];
+ dynabomb_size = player->dynabomb_size;
+ dynabomb_xl = player->dynabomb_xl;
+ player->dynabombs_left++;
+ }
+
+ Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER);
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ for (j = 1; j <= dynabomb_size; j++)
+ {
+ int x = ex + j * xy[i][0];
+ int y = ey + j * xy[i][1];
+ int element;
+
+ if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
+ break;
+
+ element = Feld[x][y];
+
+ /* do not restart explosions of fields with active bombs */
+ if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
+ continue;
+
+ Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER);
+
+ if (element != EL_EMPTY && element != EL_EXPLOSION &&
+ !IS_DIGGABLE(element) && !dynabomb_xl)
+ break;
+ }
+ }
+}
+
+void Bang(int x, int y)
+{
+ int element = MovingOrBlocked2Element(x, y);
+ int explosion_type = EX_TYPE_NORMAL;
+
+ if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
+ {
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY :
+ player->element_nr);
+
+ if (level.use_explosion_element[player->index_nr])
+ {
+ int explosion_element = level.explosion_element[player->index_nr];
+
+ if (element_info[explosion_element].explosion_type == EXPLODES_CROSS)
+ explosion_type = EX_TYPE_CROSS;
+ else if (element_info[explosion_element].explosion_type == EXPLODES_1X1)
+ explosion_type = EX_TYPE_CENTER;
+ }
+ }
+
+ switch(element)
+ {
+ case EL_BUG:
+ case EL_SPACESHIP:
+ case EL_BD_BUTTERFLY:
+ case EL_BD_FIREFLY:
+ case EL_YAMYAM:
+ case EL_DARK_YAMYAM:
+ case EL_ROBOT:
+ case EL_PACMAN:
+ case EL_MOLE:
+ RaiseScoreElement(element);
+ break;
+
+ case EL_DYNABOMB_PLAYER_1_ACTIVE:
+ case EL_DYNABOMB_PLAYER_2_ACTIVE:
+ case EL_DYNABOMB_PLAYER_3_ACTIVE:
+ case EL_DYNABOMB_PLAYER_4_ACTIVE:
+ case EL_DYNABOMB_INCREASE_NUMBER:
+ case EL_DYNABOMB_INCREASE_SIZE:
+ case EL_DYNABOMB_INCREASE_POWER:
+ explosion_type = EX_TYPE_DYNA;
+ break;
+
+ case EL_PENGUIN:
+ case EL_LAMP:
+ case EL_LAMP_ACTIVE:
+ case EL_AMOEBA_TO_DIAMOND:
+ if (!IS_PLAYER(x, y)) /* penguin and player may be at same field */
+ explosion_type = EX_TYPE_CENTER;
+ break;
+
+ default:
+ if (element_info[element].explosion_type == EXPLODES_CROSS)
+ explosion_type = EX_TYPE_CROSS;
+ else if (element_info[element].explosion_type == EXPLODES_1X1)
+ explosion_type = EX_TYPE_CENTER;
+ break;
+ }
+
+ if (explosion_type == EX_TYPE_DYNA)
+ DynaExplode(x, y);
+ else
+ Explode(x, y, EX_PHASE_START, explosion_type);
+
+ CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X);
+}
+
+void SplashAcid(int x, int y)
+{
+ if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
+ (!IN_LEV_FIELD(x - 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
+ Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
+
+ if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) &&
+ (!IN_LEV_FIELD(x + 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2))))
+ Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
+
+ PlayLevelSound(x, y, SND_ACID_SPLASHING);
+}
+
+static void InitBeltMovement()
+{
+ static int belt_base_element[4] =
+ {
+ EL_CONVEYOR_BELT_1_LEFT,
+ EL_CONVEYOR_BELT_2_LEFT,
+ EL_CONVEYOR_BELT_3_LEFT,
+ EL_CONVEYOR_BELT_4_LEFT
+ };
+ static int belt_base_active_element[4] =
+ {
+ EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_4_LEFT_ACTIVE
+ };
+
+ int x, y, i, j;
+
+ /* set frame order for belt animation graphic according to belt direction */
+ for (i = 0; i < NUM_BELTS; i++)
+ {
+ int belt_nr = i;
+
+ for (j = 0; j < NUM_BELT_PARTS; j++)
+ {
+ int element = belt_base_active_element[belt_nr] + j;
+ int graphic = el2img(element);
+
+ if (game.belt_dir[i] == MV_LEFT)
+ graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
+ else
+ graphic_info[graphic].anim_mode |= ANIM_REVERSE;
+ }
+ }
+
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+ {
+ int element = Feld[x][y];
+
+ for (i = 0; i < NUM_BELTS; i++)
+ {
+ if (IS_BELT(element) && game.belt_dir[i] != MV_NONE)
+ {
+ int e_belt_nr = getBeltNrFromBeltElement(element);
+ int belt_nr = i;
+
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[x][y] - belt_base_element[belt_nr];
+
+ Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
+ }
+ }
+ }
+ }
+}
+
+static void ToggleBeltSwitch(int x, int y)
+{
+ static int belt_base_element[4] =
+ {
+ EL_CONVEYOR_BELT_1_LEFT,
+ EL_CONVEYOR_BELT_2_LEFT,
+ EL_CONVEYOR_BELT_3_LEFT,
+ EL_CONVEYOR_BELT_4_LEFT
+ };
+ static int belt_base_active_element[4] =
+ {
+ EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+ EL_CONVEYOR_BELT_4_LEFT_ACTIVE
+ };
+ static int belt_base_switch_element[4] =
+ {
+ EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+ EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+ EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+ EL_CONVEYOR_BELT_4_SWITCH_LEFT
+ };
+ static int belt_move_dir[4] =
+ {
+ MV_LEFT,
+ MV_NONE,
+ MV_RIGHT,
+ MV_NONE,
+ };
+
+ int element = Feld[x][y];
+ int belt_nr = getBeltNrFromBeltSwitchElement(element);
+ int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
+ int belt_dir = belt_move_dir[belt_dir_nr];
+ int xx, yy, i;
+
+ if (!IS_BELT_SWITCH(element))
+ return;
+
+ game.belt_dir_nr[belt_nr] = belt_dir_nr;
+ game.belt_dir[belt_nr] = belt_dir;
+
+ if (belt_dir_nr == 3)
+ belt_dir_nr = 1;
+
+ /* set frame order for belt animation graphic according to belt direction */
+ for (i = 0; i < NUM_BELT_PARTS; i++)
+ {
+ int element = belt_base_active_element[belt_nr] + i;
+ int graphic = el2img(element);
+
+ if (belt_dir == MV_LEFT)
+ graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
+ else
+ graphic_info[graphic].anim_mode |= ANIM_REVERSE;
+ }
+
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ {
+ int element = Feld[xx][yy];
+
+ if (IS_BELT_SWITCH(element))
+ {
+ int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
+
+ if (e_belt_nr == belt_nr)
+ {
+ Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
+ DrawLevelField(xx, yy);
+ }
+ }
+ else if (IS_BELT(element) && belt_dir != MV_NONE)
+ {
+ int e_belt_nr = getBeltNrFromBeltElement(element);
+
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
+
+ Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
+ DrawLevelField(xx, yy);
+ }
+ }
+ else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE)
+ {
+ int e_belt_nr = getBeltNrFromBeltActiveElement(element);
+
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
+
+ Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
+ DrawLevelField(xx, yy);
+ }
+ }
+ }
+}
+
+static void ToggleSwitchgateSwitch(int x, int y)
+{
+ int xx, yy;
+
+ game.switchgate_pos = !game.switchgate_pos;
+
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ {
+ int element = Feld[xx][yy];
+
+#if !USE_BOTH_SWITCHGATE_SWITCHES
+ if (element == EL_SWITCHGATE_SWITCH_UP ||
+ element == EL_SWITCHGATE_SWITCH_DOWN)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
+ DrawLevelField(xx, yy);
+ }
+#else
+ if (element == EL_SWITCHGATE_SWITCH_UP)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN;
+ DrawLevelField(xx, yy);
+ }
+ else if (element == EL_SWITCHGATE_SWITCH_DOWN)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP;
+ DrawLevelField(xx, yy);
+ }
+#endif
+ else if (element == EL_SWITCHGATE_OPEN ||
+ element == EL_SWITCHGATE_OPENING)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+
+ PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
+ }
+ else if (element == EL_SWITCHGATE_CLOSED ||
+ element == EL_SWITCHGATE_CLOSING)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_OPENING;
+
+ PlayLevelSoundAction(xx, yy, ACTION_OPENING);
+ }
+ }
+}
+
+static int getInvisibleActiveFromInvisibleElement(int element)
+{
+ return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE :
+ element == EL_INVISIBLE_WALL ? EL_INVISIBLE_WALL_ACTIVE :
+ element == EL_INVISIBLE_SAND ? EL_INVISIBLE_SAND_ACTIVE :
+ element);
+}
+
+static int getInvisibleFromInvisibleActiveElement(int element)
+{
+ return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL :
+ element == EL_INVISIBLE_WALL_ACTIVE ? EL_INVISIBLE_WALL :
+ element == EL_INVISIBLE_SAND_ACTIVE ? EL_INVISIBLE_SAND :
+ element);
+}
+
+static void RedrawAllLightSwitchesAndInvisibleElements()
+{
+ int x, y;
+
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+ {
+ int element = Feld[x][y];
+
+ if (element == EL_LIGHT_SWITCH &&
+ game.light_time_left > 0)
+ {
+ Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_LIGHT_SWITCH_ACTIVE &&
+ game.light_time_left == 0)
+ {
+ Feld[x][y] = EL_LIGHT_SWITCH;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_EMC_DRIPPER &&
+ game.light_time_left > 0)
+ {
+ Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_EMC_DRIPPER_ACTIVE &&
+ game.light_time_left == 0)
+ {
+ Feld[x][y] = EL_EMC_DRIPPER;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_INVISIBLE_STEELWALL ||
+ element == EL_INVISIBLE_WALL ||
+ element == EL_INVISIBLE_SAND)
+ {
+ if (game.light_time_left > 0)
+ Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+
+ DrawLevelField(x, y);
+
+ /* uncrumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+ }
+ else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
+ element == EL_INVISIBLE_WALL_ACTIVE ||
+ element == EL_INVISIBLE_SAND_ACTIVE)
+ {
+ if (game.light_time_left == 0)
+ Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
+
+ DrawLevelField(x, y);
+
+ /* re-crumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+ }
+ }
+}
+
+static void RedrawAllInvisibleElementsForLenses()
+{
+ int x, y;
+
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+ {
+ int element = Feld[x][y];
+
+ if (element == EL_EMC_DRIPPER &&
+ game.lenses_time_left > 0)
+ {
+ Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_EMC_DRIPPER_ACTIVE &&
+ game.lenses_time_left == 0)
+ {
+ Feld[x][y] = EL_EMC_DRIPPER;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_INVISIBLE_STEELWALL ||
+ element == EL_INVISIBLE_WALL ||
+ element == EL_INVISIBLE_SAND)
+ {
+ if (game.lenses_time_left > 0)
+ Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+
+ DrawLevelField(x, y);
+
+ /* uncrumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+ }
+ else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
+ element == EL_INVISIBLE_WALL_ACTIVE ||
+ element == EL_INVISIBLE_SAND_ACTIVE)
+ {
+ if (game.lenses_time_left == 0)
+ Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
+
+ DrawLevelField(x, y);
+
+ /* re-crumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+ }
+ }
+}
+
+static void RedrawAllInvisibleElementsForMagnifier()
+{
+ int x, y;
+
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+ {
+ int element = Feld[x][y];
+
+ if (element == EL_EMC_FAKE_GRASS &&
+ game.magnify_time_left > 0)
+ {
+ Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_EMC_FAKE_GRASS_ACTIVE &&
+ game.magnify_time_left == 0)
+ {
+ Feld[x][y] = EL_EMC_FAKE_GRASS;
+ DrawLevelField(x, y);
+ }
+ else if (IS_GATE_GRAY(element) &&
+ game.magnify_time_left > 0)
+ {
+ Feld[x][y] = (IS_RND_GATE_GRAY(element) ?
+ element - EL_GATE_1_GRAY + EL_GATE_1_GRAY_ACTIVE :
+ IS_EM_GATE_GRAY(element) ?
+ element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE :
+ IS_EMC_GATE_GRAY(element) ?
+ element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE :
+ element);
+ DrawLevelField(x, y);
+ }
+ else if (IS_GATE_GRAY_ACTIVE(element) &&
+ game.magnify_time_left == 0)
+ {
+ Feld[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ?
+ element - EL_GATE_1_GRAY_ACTIVE + EL_GATE_1_GRAY :
+ IS_EM_GATE_GRAY_ACTIVE(element) ?
+ element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY :
+ IS_EMC_GATE_GRAY_ACTIVE(element) ?
+ element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY :
+ element);
+ DrawLevelField(x, y);
+ }
+ }
+}
+
+static void ToggleLightSwitch(int x, int y)
+{
+ int element = Feld[x][y];
+
+ game.light_time_left =
+ (element == EL_LIGHT_SWITCH ?
+ level.time_light * FRAMES_PER_SECOND : 0);
+
+ RedrawAllLightSwitchesAndInvisibleElements();
+}
+
+static void ActivateTimegateSwitch(int x, int y)
+{
+ int xx, yy;
+
+ game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
+
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ {
+ int element = Feld[xx][yy];
+
+ if (element == EL_TIMEGATE_CLOSED ||
+ element == EL_TIMEGATE_CLOSING)
+ {
+ Feld[xx][yy] = EL_TIMEGATE_OPENING;
+ PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
+ }
+
+ /*
+ else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
+ {
+ Feld[xx][yy] = EL_TIMEGATE_SWITCH;
+ DrawLevelField(xx, yy);
+ }
+ */
+
+ }
+
+ Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
+}
+
+void Impact(int x, int y)
+{
+ boolean last_line = (y == lev_fieldy - 1);
+ boolean object_hit = FALSE;
+ boolean impact = (last_line || object_hit);
+ int element = Feld[x][y];
+ int smashed = EL_STEELWALL;
+
+ if (!last_line) /* check if element below was hit */
+ {
+ if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
+ return;
+
+ object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) ||
+ MovDir[x][y + 1] != MV_DOWN ||
+ MovPos[x][y + 1] <= TILEY / 2));
+
+ /* do not smash moving elements that left the smashed field in time */
+ if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) &&
+ ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX)
+ object_hit = FALSE;
+
+#if USE_QUICKSAND_IMPACT_BUGFIX
+ if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE)
+ {
+ RemoveMovingField(x, y + 1);
+ Feld[x][y + 1] = EL_QUICKSAND_EMPTY;
+ Feld[x][y + 2] = EL_ROCK;
+ DrawLevelField(x, y + 2);
+
+ object_hit = TRUE;
+ }
+#endif
+
+ if (object_hit)
+ smashed = MovingOrBlocked2Element(x, y + 1);
+
+ impact = (last_line || object_hit);
+ }
+
+ if (!last_line && smashed == EL_ACID) /* element falls into acid */
+ {
+ SplashAcid(x, y + 1);
+ return;
+ }
+
+ /* !!! not sufficient for all cases -- see EL_PEARL below !!! */
+ /* only reset graphic animation if graphic really changes after impact */
+ if (impact &&
+ el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element))
+ {
+ ResetGfxAnimation(x, y);
+ DrawLevelField(x, y);
+ }
+
+ if (impact && CAN_EXPLODE_IMPACT(element))
+ {
+ Bang(x, y);
+ return;
+ }
+ else if (impact && element == EL_PEARL)
+ {
+ ResetGfxAnimation(x, y);
+
+ Feld[x][y] = EL_PEARL_BREAKING;
+ PlayLevelSound(x, y, SND_PEARL_BREAKING);
+ return;
+ }
+ else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT))
+ {
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+
+ return;
+ }
+
+ if (impact && element == EL_AMOEBA_DROP)
+ {
+ if (object_hit && IS_PLAYER(x, y + 1))
+ KillPlayerUnlessEnemyProtected(x, y + 1);
+ else if (object_hit && smashed == EL_PENGUIN)
+ Bang(x, y + 1);
+ else
+ {
+ Feld[x][y] = EL_AMOEBA_GROWING;
+ Store[x][y] = EL_AMOEBA_WET;
+
+ ResetRandomAnimationValue(x, y);
+ }
+ return;
+ }
+
+ if (object_hit) /* check which object was hit */
+ {
+ if (CAN_PASS_MAGIC_WALL(element) &&
+ (smashed == EL_MAGIC_WALL ||
+ smashed == EL_BD_MAGIC_WALL))
+ {
+ int xx, yy;
+ int activated_magic_wall =
+ (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE :
+ EL_BD_MAGIC_WALL_ACTIVE);
+
+ /* activate magic wall / mill */
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ if (Feld[xx][yy] == smashed)
+ Feld[xx][yy] = activated_magic_wall;
+
+ game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
+ game.magic_wall_active = TRUE;
+
+ PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ?
+ SND_MAGIC_WALL_ACTIVATING :
+ SND_BD_MAGIC_WALL_ACTIVATING));
+ }
+
+ if (IS_PLAYER(x, y + 1))
+ {
+ if (CAN_SMASH_PLAYER(element))
+ {
+ KillPlayerUnlessEnemyProtected(x, y + 1);
+ return;
+ }
+ }
+ else if (smashed == EL_PENGUIN)
+ {
+ if (CAN_SMASH_PLAYER(element))
+ {
+ Bang(x, y + 1);
+ return;
+ }
+ }
+ else if (element == EL_BD_DIAMOND)
+ {
+ if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
+ {
+ Bang(x, y + 1);
+ return;
+ }
+ }
+ else if (((element == EL_SP_INFOTRON ||
+ element == EL_SP_ZONK) &&
+ (smashed == EL_SP_SNIKSNAK ||
+ smashed == EL_SP_ELECTRON ||
+ smashed == EL_SP_DISK_ORANGE)) ||
+ (element == EL_SP_INFOTRON &&
+ smashed == EL_SP_DISK_YELLOW))
+ {
+ Bang(x, y + 1);
+ return;
+ }
+ else if (CAN_SMASH_EVERYTHING(element))
+ {
+ if (IS_CLASSIC_ENEMY(smashed) ||
+ CAN_EXPLODE_SMASHED(smashed))
+ {
+ Bang(x, y + 1);
+ return;
+ }
+ else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1))
+ {
+ if (smashed == EL_LAMP ||
+ smashed == EL_LAMP_ACTIVE)
+ {
+ Bang(x, y + 1);
+ return;
+ }
+ else if (smashed == EL_NUT)
+ {
+ Feld[x][y + 1] = EL_NUT_BREAKING;
+ PlayLevelSound(x, y, SND_NUT_BREAKING);
+ RaiseScoreElement(EL_NUT);
+ return;
+ }
+ else if (smashed == EL_PEARL)
+ {
+ ResetGfxAnimation(x, y);
+
+ Feld[x][y + 1] = EL_PEARL_BREAKING;
+ PlayLevelSound(x, y, SND_PEARL_BREAKING);
+ return;
+ }
+ else if (smashed == EL_DIAMOND)
+ {
+ Feld[x][y + 1] = EL_DIAMOND_BREAKING;
+ PlayLevelSound(x, y, SND_DIAMOND_BREAKING);
+ return;
+ }
+ else if (IS_BELT_SWITCH(smashed))
+ {
+ ToggleBeltSwitch(x, y + 1);
+ }
+ else if (smashed == EL_SWITCHGATE_SWITCH_UP ||
+ smashed == EL_SWITCHGATE_SWITCH_DOWN)
+ {
+ ToggleSwitchgateSwitch(x, y + 1);
+ }
+ else if (smashed == EL_LIGHT_SWITCH ||
+ smashed == EL_LIGHT_SWITCH_ACTIVE)
+ {
+ ToggleLightSwitch(x, y + 1);
+ }
+ else
+ {
+#if 0
+ TestIfElementSmashesCustomElement(x, y, MV_DOWN);
+#endif
+
+ CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
+
+ CheckElementChangeBySide(x, y + 1, smashed, element,
+ CE_SWITCHED, CH_SIDE_TOP);
+ CheckTriggeredElementChangeBySide(x, y + 1, smashed, CE_SWITCH_OF_X,
+ CH_SIDE_TOP);
+ }
+ }
+ else
+ {
+ CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
+ }
+ }
+ }
+
+ /* play sound of magic wall / mill */
+ if (!last_line &&
+ (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+ Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
+ {
+ if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
+ PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING);
+ else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
+ PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING);
+
+ return;
+ }
+
+ /* play sound of object that hits the ground */
+ if (last_line || object_hit)
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+}
+
+inline static void TurnRoundExt(int x, int y)
+{
+ static struct
+ {
+ int dx, dy;
+ } move_xy[] =
+ {
+ { 0, 0 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, 0 },
+ { 0, -1 },
+ { 0, 0 }, { 0, 0 }, { 0, 0 },
+ { 0, +1 }
+ };
+ static struct
+ {
+ int left, right, back;
+ } turn[] =
+ {
+ { 0, 0, 0 },
+ { MV_DOWN, MV_UP, MV_RIGHT },
+ { MV_UP, MV_DOWN, MV_LEFT },
+ { 0, 0, 0 },
+ { MV_LEFT, MV_RIGHT, MV_DOWN },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { MV_RIGHT, MV_LEFT, MV_UP }
+ };
+
+ int element = Feld[x][y];
+ int move_pattern = element_info[element].move_pattern;
+
+ int old_move_dir = MovDir[x][y];
+ int left_dir = turn[old_move_dir].left;
+ int right_dir = turn[old_move_dir].right;
+ int back_dir = turn[old_move_dir].back;
+
+ int left_dx = move_xy[left_dir].dx, left_dy = move_xy[left_dir].dy;
+ int right_dx = move_xy[right_dir].dx, right_dy = move_xy[right_dir].dy;
+ int move_dx = move_xy[old_move_dir].dx, move_dy = move_xy[old_move_dir].dy;
+ int back_dx = move_xy[back_dir].dx, back_dy = move_xy[back_dir].dy;
+
+ int left_x = x + left_dx, left_y = y + left_dy;
+ int right_x = x + right_dx, right_y = y + right_dy;
+ int move_x = x + move_dx, move_y = y + move_dy;
+
+ int xx, yy;
+
+ if (element == EL_BUG || element == EL_BD_BUTTERFLY)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
+ MovDir[x][y] = right_dir;
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = left_dir;
+
+ if (element == EL_BUG && MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */
+ MovDelay[x][y] = 1;
+ }
+ else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
+ MovDir[x][y] = left_dir;
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = right_dir;
+
+ if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */
+ MovDelay[x][y] = 1;
+ }
+ else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0))
+ MovDir[x][y] = left_dir;
+ else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0))
+ MovDir[x][y] = right_dir;
+
+ if (MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ }
+ else if (element == EL_YAMYAM)
+ {
+ boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 16 + 16 * RND(3);
+ }
+ else if (element == EL_DARK_YAMYAM)
+ {
+ boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+ left_x, left_y);
+ boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+ right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 16 + 16 * RND(3);
+ }
+ else if (element == EL_PACMAN)
+ {
+ boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 6 + RND(40);
+ }
+ else if (element == EL_PIG)
+ {
+ boolean can_turn_left = PIG_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y);
+ boolean can_move_on = PIG_CAN_ENTER_FIELD(element, move_x, move_y);
+ boolean should_turn_left, should_turn_right, should_move_on;
+ int rnd_value = 24;
+ int rnd = RND(rnd_value);
+
+ should_turn_left = (can_turn_left &&
+ (!can_move_on ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx,
+ y + back_dy + left_dy)));
+ should_turn_right = (can_turn_right &&
+ (!can_move_on ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx,
+ y + back_dy + right_dy)));
+ should_move_on = (can_move_on &&
+ (!can_turn_left ||
+ !can_turn_right ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx,
+ y + move_dy + left_dy) ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx,
+ y + move_dy + right_dy)));
+
+ if (should_turn_left || should_turn_right || should_move_on)
+ {
+ if (should_turn_left && should_turn_right && should_move_on)
+ MovDir[x][y] = (rnd < rnd_value / 3 ? left_dir :