+ int target_element;
+ int change_delay;
+ void (*pre_change_function)(int x, int y);
+ void (*change_function)(int x, int y);
+ void (*post_change_function)(int x, int y);
+};
+
+static struct ChangingElementInfo change_delay_list[] =
+{
+ {
+ EL_NUT_BREAKING,
+ EL_EMERALD,
+ 6,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_PEARL_BREAKING,
+ EL_EMPTY,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EXIT_OPENING,
+ EL_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EXIT_CLOSING,
+ EL_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_STEEL_EXIT_OPENING,
+ EL_STEEL_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_STEEL_EXIT_CLOSING,
+ EL_STEEL_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EM_EXIT_OPENING,
+ EL_EM_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EM_EXIT_CLOSING,
+#if 1
+ EL_EMPTY,
+#else
+ EL_EM_EXIT_CLOSED,
+#endif
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EM_STEEL_EXIT_OPENING,
+ EL_EM_STEEL_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_EM_STEEL_EXIT_CLOSING,
+#if 1
+ EL_STEELWALL,
+#else
+ EL_EM_STEEL_EXIT_CLOSED,
+#endif
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_EXIT_OPENING,
+ EL_SP_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_EXIT_CLOSING,
+ EL_SP_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SWITCHGATE_OPENING,
+ EL_SWITCHGATE_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SWITCHGATE_CLOSING,
+ EL_SWITCHGATE_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_TIMEGATE_OPENING,
+ EL_TIMEGATE_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_TIMEGATE_CLOSING,
+ EL_TIMEGATE_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+
+ {
+ EL_ACID_SPLASH_LEFT,
+ EL_EMPTY,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_ACID_SPLASH_RIGHT,
+ EL_EMPTY,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_BUGGY_BASE,
+ EL_SP_BUGGY_BASE_ACTIVATING,
+ 0,
+ InitBuggyBase,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_BUGGY_BASE_ACTIVATING,
+ EL_SP_BUGGY_BASE_ACTIVE,
+ 0,
+ InitBuggyBase,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_BUGGY_BASE_ACTIVE,
+ EL_SP_BUGGY_BASE,
+ 0,
+ InitBuggyBase,
+ WarnBuggyBase,
+ NULL
+ },
+ {
+ EL_TRAP,
+ EL_TRAP_ACTIVE,
+ 0,
+ InitTrap,
+ NULL,
+ ActivateTrap
+ },
+ {
+ EL_TRAP_ACTIVE,
+ EL_TRAP,
+ 31,
+ NULL,
+ ChangeActiveTrap,
+ NULL
+ },
+ {
+ EL_ROBOT_WHEEL_ACTIVE,
+ EL_ROBOT_WHEEL,
+ 0,
+ InitRobotWheel,
+ RunRobotWheel,
+ StopRobotWheel
+ },
+ {
+ EL_TIMEGATE_SWITCH_ACTIVE,
+ EL_TIMEGATE_SWITCH,
+ 0,
+ InitTimegateWheel,
+ RunTimegateWheel,
+ NULL
+ },
+ {
+ EL_DC_TIMEGATE_SWITCH_ACTIVE,
+ EL_DC_TIMEGATE_SWITCH,
+ 0,
+ InitTimegateWheel,
+ RunTimegateWheel,
+ NULL
+ },
+ {
+ EL_EMC_MAGIC_BALL_ACTIVE,
+ EL_EMC_MAGIC_BALL_ACTIVE,
+ 0,
+ InitMagicBallDelay,
+ NULL,
+ ActivateMagicBall
+ },
+ {
+ EL_EMC_SPRING_BUMPER_ACTIVE,
+ EL_EMC_SPRING_BUMPER,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_SHRINKING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_GROWING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ },
+
+ {
+ EL_UNDEFINED,
+ EL_UNDEFINED,
+ -1,
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+struct
+{
+ int element;
+ int push_delay_fixed, push_delay_random;
+}
+push_delay_list[] =
+{
+ { EL_SPRING, 0, 0 },
+ { EL_BALLOON, 0, 0 },
+
+ { EL_SOKOBAN_OBJECT, 2, 0 },
+ { EL_SOKOBAN_FIELD_FULL, 2, 0 },
+ { EL_SATELLITE, 2, 0 },
+ { EL_SP_DISK_YELLOW, 2, 0 },
+
+ { EL_UNDEFINED, 0, 0 },
+};
+
+struct
+{
+ int element;
+ int move_stepsize;
+}
+move_stepsize_list[] =
+{
+ { EL_AMOEBA_DROP, 2 },
+ { EL_AMOEBA_DROPPING, 2 },
+ { EL_QUICKSAND_FILLING, 1 },
+ { EL_QUICKSAND_EMPTYING, 1 },
+ { EL_QUICKSAND_FAST_FILLING, 2 },
+ { EL_QUICKSAND_FAST_EMPTYING, 2 },
+ { EL_MAGIC_WALL_FILLING, 2 },
+ { EL_MAGIC_WALL_EMPTYING, 2 },
+ { EL_BD_MAGIC_WALL_FILLING, 2 },
+ { EL_BD_MAGIC_WALL_EMPTYING, 2 },
+ { EL_DC_MAGIC_WALL_FILLING, 2 },
+ { EL_DC_MAGIC_WALL_EMPTYING, 2 },
+
+ { EL_UNDEFINED, 0 },
+};
+
+struct
+{
+ int element;
+ int count;
+}
+collect_count_list[] =
+{
+ { EL_EMERALD, 1 },
+ { EL_BD_DIAMOND, 1 },
+ { EL_EMERALD_YELLOW, 1 },
+ { EL_EMERALD_RED, 1 },
+ { EL_EMERALD_PURPLE, 1 },
+ { EL_DIAMOND, 3 },
+ { EL_SP_INFOTRON, 1 },
+ { EL_PEARL, 5 },
+ { EL_CRYSTAL, 8 },
+
+ { EL_UNDEFINED, 0 },
+};
+
+struct
+{
+ int element;
+ int direction;
+}
+access_direction_list[] =
+{
+ { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL, MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT },
+ { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP },
+ { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN },
+ { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP },
+ { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN },
+ { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP },
+ { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN },
+
+ { EL_SP_PORT_LEFT, MV_RIGHT },
+ { EL_SP_PORT_RIGHT, MV_LEFT },
+ { EL_SP_PORT_UP, MV_DOWN },
+ { EL_SP_PORT_DOWN, MV_UP },
+ { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT },
+ { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN },
+ { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_PORT_DOWN, MV_UP },
+ { EL_SP_GRAVITY_ON_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_ON_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_ON_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_ON_PORT_DOWN, MV_UP },
+ { EL_SP_GRAVITY_OFF_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_OFF_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_OFF_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_OFF_PORT_DOWN, MV_UP },
+
+ { EL_UNDEFINED, MV_NONE }
+};
+
+static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
+
+#define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY])
+#define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
+#define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \
+ IS_JUST_CHANGING(x, y))
+
+#define CE_PAGE(e, ce) (element_info[e].event_page[ce])
+
+/* static variables for playfield scan mode (scanning forward or backward) */
+static int playfield_scan_start_x = 0;
+static int playfield_scan_start_y = 0;
+static int playfield_scan_delta_x = 1;
+static int playfield_scan_delta_y = 1;
+
+#define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \
+ (y) >= 0 && (y) <= lev_fieldy - 1; \
+ (y) += playfield_scan_delta_y) \
+ for ((x) = playfield_scan_start_x; \
+ (x) >= 0 && (x) <= lev_fieldx - 1; \
+ (x) += playfield_scan_delta_x)
+
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite()
+{
+ int i;
+
+ for (i = 0; i < MAX_INVENTORY_SIZE; i++)
+ if (local_player->inventory_size < MAX_INVENTORY_SIZE)
+ local_player->inventory_element[local_player->inventory_size++] =
+ EL_DYNAMITE;
+}
+#endif
+
+static void InitPlayfieldScanModeVars()
+{
+ if (game.use_reverse_scan_direction)
+ {
+ playfield_scan_start_x = lev_fieldx - 1;
+ playfield_scan_start_y = lev_fieldy - 1;
+
+ playfield_scan_delta_x = -1;
+ playfield_scan_delta_y = -1;
+ }
+ else
+ {
+ playfield_scan_start_x = 0;
+ playfield_scan_start_y = 0;
+
+ playfield_scan_delta_x = 1;
+ playfield_scan_delta_y = 1;
+ }
+}
+
+static void InitPlayfieldScanMode(int mode)
+{
+ game.use_reverse_scan_direction =
+ (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE);
+
+ InitPlayfieldScanModeVars();
+}
+
+static int get_move_delay_from_stepsize(int move_stepsize)
+{
+ move_stepsize =
+ MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX);
+
+ /* make sure that stepsize value is always a power of 2 */
+ move_stepsize = (1 << log_2(move_stepsize));
+
+ return TILEX / move_stepsize;
+}
+
+static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize,
+ boolean init_game)
+{
+ int player_nr = player->index_nr;
+ int move_delay = get_move_delay_from_stepsize(move_stepsize);
+ boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE);
+
+ /* do no immediately change move delay -- the player might just be moving */
+ player->move_delay_value_next = move_delay;
+
+ /* information if player can move must be set separately */
+ player->cannot_move = cannot_move;
+
+ if (init_game)
+ {
+ player->move_delay = game.initial_move_delay[player_nr];
+ player->move_delay_value = game.initial_move_delay_value[player_nr];
+
+ player->move_delay_value_next = -1;
+
+ player->move_delay_reset_counter = 0;
+ }
+}
+
+void GetPlayerConfig()
+{
+ GameFrameDelay = setup.game_frame_delay;
+
+ if (!audio.sound_available)
+ setup.sound_simple = FALSE;
+
+ if (!audio.loops_available)
+ setup.sound_loops = FALSE;
+
+ if (!audio.music_available)
+ setup.sound_music = FALSE;
+
+ if (!video.fullscreen_available)
+ setup.fullscreen = FALSE;
+
+ setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music);
+
+ SetAudioMode(setup.sound);
+ InitJoysticks();
+}
+
+int GetElementFromGroupElement(int element)
+{
+ if (IS_GROUP_ELEMENT(element))
+ {
+ struct ElementGroupInfo *group = element_info[element].group;
+ int last_anim_random_frame = gfx.anim_random_frame;
+ int element_pos;
+
+ if (group->choice_mode == ANIM_RANDOM)
+ gfx.anim_random_frame = RND(group->num_elements_resolved);
+
+ element_pos = getAnimationFrame(group->num_elements_resolved, 1,
+ group->choice_mode, 0,
+ group->choice_pos);
+
+ if (group->choice_mode == ANIM_RANDOM)
+ gfx.anim_random_frame = last_anim_random_frame;
+
+ group->choice_pos++;
+
+ element = group->element_resolved[element_pos];
+ }
+
+ return element;
+}
+
+static void InitPlayerField(int x, int y, int element, boolean init_game)
+{
+ if (element == EL_SP_MURPHY)
+ {
+ if (init_game)
+ {
+ if (stored_player[0].present)
+ {
+ Feld[x][y] = EL_SP_MURPHY_CLONE;
+
+ return;
+ }
+ else
+ {
+ stored_player[0].initial_element = element;
+ stored_player[0].use_murphy = TRUE;
+
+ if (!level.use_artwork_element[0])
+ stored_player[0].artwork_element = EL_SP_MURPHY;
+ }
+
+ Feld[x][y] = EL_PLAYER_1;
+ }
+ }
+
+ if (init_game)
+ {
+ struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
+ int jx = player->jx, jy = player->jy;
+
+ player->present = TRUE;
+
+ player->block_last_field = (element == EL_SP_MURPHY ?
+ level.sp_block_last_field :
+ level.block_last_field);
+
+ /* ---------- initialize player's last field block delay --------------- */
+
+ /* always start with reliable default value (no adjustment needed) */
+ player->block_delay_adjustment = 0;
+
+ /* special case 1: in Supaplex, Murphy blocks last field one more frame */
+ if (player->block_last_field && element == EL_SP_MURPHY)
+ player->block_delay_adjustment = 1;
+
+ /* special case 2: in game engines before 3.1.1, blocking was different */
+ if (game.use_block_last_field_bug)
+ player->block_delay_adjustment = (player->block_last_field ? -1 : 1);
+
+ if (!options.network || player->connected)
+ {
+ player->active = TRUE;
+
+ /* remove potentially duplicate players */
+ if (StorePlayer[jx][jy] == Feld[x][y])
+ StorePlayer[jx][jy] = 0;
+
+ StorePlayer[x][y] = Feld[x][y];
+
+ if (options.debug)
+ {
+ printf("Player %d activated.\n", player->element_nr);
+ printf("[Local player is %d and currently %s.]\n",
+ local_player->element_nr,
+ local_player->active ? "active" : "not active");
+ }
+ }
+
+ Feld[x][y] = EL_EMPTY;
+
+ player->jx = player->last_jx = x;
+ player->jy = player->last_jy = y;
+ }
+
+#if USE_PLAYER_REANIMATION
+ if (!init_game)
+ {
+ int player_nr = GET_PLAYER_NR(element);
+ struct PlayerInfo *player = &stored_player[player_nr];
+
+ if (player->active && player->killed)
+ player->reanimated = TRUE; /* if player was just killed, reanimate him */
+ }
+#endif
+}
+
+static void InitField(int x, int y, boolean init_game)
+{
+ int element = Feld[x][y];
+
+ switch (element)
+ {
+ case EL_SP_MURPHY:
+ case EL_PLAYER_1:
+ case EL_PLAYER_2:
+ case EL_PLAYER_3:
+ case EL_PLAYER_4:
+ InitPlayerField(x, y, element, init_game);
+ break;
+
+ case EL_SOKOBAN_FIELD_PLAYER:
+ element = Feld[x][y] = EL_PLAYER_1;
+ InitField(x, y, init_game);
+
+ element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+ InitField(x, y, init_game);
+ break;
+
+ case EL_SOKOBAN_FIELD_EMPTY:
+ local_player->sokobanfields_still_needed++;
+ break;
+
+ case EL_STONEBLOCK:
+ if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
+ Feld[x][y] = EL_ACID_POOL_TOPLEFT;
+ else if (x > 0 && Feld[x-1][y] == EL_ACID)
+ Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
+ else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
+ Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
+ else if (y > 0 && Feld[x][y-1] == EL_ACID)
+ Feld[x][y] = EL_ACID_POOL_BOTTOM;
+ else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
+ Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
+ break;
+
+ case EL_BUG:
+ case EL_BUG_RIGHT:
+ case EL_BUG_UP:
+ case EL_BUG_LEFT:
+ case EL_BUG_DOWN:
+ case EL_SPACESHIP:
+ case EL_SPACESHIP_RIGHT:
+ case EL_SPACESHIP_UP:
+ case EL_SPACESHIP_LEFT:
+ case EL_SPACESHIP_DOWN:
+ case EL_BD_BUTTERFLY:
+ case EL_BD_BUTTERFLY_RIGHT:
+ case EL_BD_BUTTERFLY_UP:
+ case EL_BD_BUTTERFLY_LEFT:
+ case EL_BD_BUTTERFLY_DOWN:
+ case EL_BD_FIREFLY:
+ case EL_BD_FIREFLY_RIGHT:
+ case EL_BD_FIREFLY_UP:
+ case EL_BD_FIREFLY_LEFT:
+ case EL_BD_FIREFLY_DOWN:
+ case EL_PACMAN_RIGHT:
+ case EL_PACMAN_UP:
+ case EL_PACMAN_LEFT:
+ case EL_PACMAN_DOWN:
+ case EL_YAMYAM:
+ case EL_YAMYAM_LEFT:
+ case EL_YAMYAM_RIGHT:
+ case EL_YAMYAM_UP:
+ case EL_YAMYAM_DOWN:
+ case EL_DARK_YAMYAM:
+ case EL_ROBOT:
+ case EL_PACMAN:
+ case EL_SP_SNIKSNAK:
+ case EL_SP_ELECTRON:
+ case EL_MOLE:
+ case EL_MOLE_LEFT:
+ case EL_MOLE_RIGHT:
+ case EL_MOLE_UP:
+ case EL_MOLE_DOWN:
+ InitMovDir(x, y);
+ break;
+
+ case EL_AMOEBA_FULL:
+ case EL_BD_AMOEBA:
+ InitAmoebaNr(x, y);
+ break;
+
+ case EL_AMOEBA_DROP:
+ if (y == lev_fieldy - 1)
+ {
+ Feld[x][y] = EL_AMOEBA_GROWING;
+ Store[x][y] = EL_AMOEBA_WET;
+ }
+ break;
+
+ case EL_DYNAMITE_ACTIVE:
+ case EL_SP_DISK_RED_ACTIVE:
+ case EL_DYNABOMB_PLAYER_1_ACTIVE:
+ case EL_DYNABOMB_PLAYER_2_ACTIVE:
+ case EL_DYNABOMB_PLAYER_3_ACTIVE:
+ case EL_DYNABOMB_PLAYER_4_ACTIVE:
+ MovDelay[x][y] = 96;
+ break;
+
+ case EL_EM_DYNAMITE_ACTIVE:
+ MovDelay[x][y] = 32;
+ break;
+
+ case EL_LAMP:
+ local_player->lights_still_needed++;
+ break;
+
+ case EL_PENGUIN:
+ local_player->friends_still_needed++;
+ break;
+
+ case EL_PIG:
+ case EL_DRAGON:
+ GfxDir[x][y] = MovDir[x][y] = 1 << RND(4);
+ break;
+
+ case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
+ if (init_game)
+ {
+ int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
+ int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
+ int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
+
+ if (game.belt_dir_nr[belt_nr] == 3) /* initial value */
+ {
+ game.belt_dir[belt_nr] = belt_dir;
+ game.belt_dir_nr[belt_nr] = belt_dir_nr;
+ }
+ else /* more than one switch -- set it like the first switch */
+ {
+ Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
+ }
+ }
+ break;
+
+#if !USE_BOTH_SWITCHGATE_SWITCHES
+ case EL_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */
+ if (init_game)
+ Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
+ break;
+
+ case EL_DC_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */
+ if (init_game)
+ Feld[x][y] = EL_DC_SWITCHGATE_SWITCH_UP;
+ break;
+#endif
+
+ case EL_LIGHT_SWITCH_ACTIVE:
+ if (init_game)
+ game.light_time_left = level.time_light * FRAMES_PER_SECOND;
+ break;
+
+ case EL_INVISIBLE_STEELWALL:
+ case EL_INVISIBLE_WALL:
+ case EL_INVISIBLE_SAND:
+ if (game.light_time_left > 0 ||
+ game.lenses_time_left > 0)
+ Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+ break;
+
+ case EL_EMC_MAGIC_BALL:
+ if (game.ball_state)
+ Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
+ break;
+
+ case EL_EMC_MAGIC_BALL_SWITCH:
+ if (game.ball_state)
+ Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
+ break;
+
+ case EL_TRIGGER_PLAYER:
+ case EL_TRIGGER_ELEMENT:
+ case EL_TRIGGER_CE_VALUE:
+ case EL_TRIGGER_CE_SCORE:
+ case EL_SELF:
+ case EL_ANY_ELEMENT:
+ case EL_CURRENT_CE_VALUE:
+ case EL_CURRENT_CE_SCORE:
+ case EL_PREV_CE_1:
+ case EL_PREV_CE_2:
+ case EL_PREV_CE_3:
+ case EL_PREV_CE_4:
+ case EL_PREV_CE_5:
+ case EL_PREV_CE_6:
+ case EL_PREV_CE_7:
+ case EL_PREV_CE_8:
+ case EL_NEXT_CE_1:
+ case EL_NEXT_CE_2:
+ case EL_NEXT_CE_3:
+ case EL_NEXT_CE_4:
+ case EL_NEXT_CE_5:
+ case EL_NEXT_CE_6:
+ case EL_NEXT_CE_7:
+ case EL_NEXT_CE_8:
+ /* reference elements should not be used on the playfield */
+ Feld[x][y] = EL_EMPTY;
+ break;
+
+ default:
+ if (IS_CUSTOM_ELEMENT(element))
+ {
+ if (CAN_MOVE(element))
+ InitMovDir(x, y);
+
+#if USE_NEW_CUSTOM_VALUE
+ if (!element_info[element].use_last_ce_value || init_game)
+ CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
+#endif
+ }
+ else if (IS_GROUP_ELEMENT(element))
+ {
+ Feld[x][y] = GetElementFromGroupElement(element);
+
+ InitField(x, y, init_game);
+ }
+
+ break;
+ }
+
+ if (!init_game)
+ CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X);
+}
+
+static inline void InitField_WithBug1(int x, int y, boolean init_game)
+{
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
+ CAN_MOVE(Feld[x][y]))
+ InitMovDir(x, y);
+}
+
+static inline void InitField_WithBug2(int x, int y, boolean init_game)
+{
+ int old_element = Feld[x][y];
+
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
+ CAN_MOVE(old_element) &&
+ (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
+ InitMovDir(x, y);
+
+ /* this case is in fact a combination of not less than three bugs:
+ first, it calls InitMovDir() for elements that can move, although this is
+ already done by InitField(); then, it checks the element that was at this
+ field _before_ the call to InitField() (which can change it); lastly, it
+ was not called for "mole with direction" elements, which were treated as
+ "cannot move" due to (fixed) wrong element initialization in "src/init.c"
+ */