+static int getBeltNrFromBeltElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
+ element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
+ element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
+}
+
+static int getBeltNrFromBeltActiveElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
+ element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
+ element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
+}
+
+static int getBeltNrFromBeltSwitchElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
+ element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
+ element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
+}
+
+static int getBeltDirNrFromBeltSwitchElement(int element)
+{
+ static int belt_base_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
+ };
+
+ int belt_nr = getBeltNrFromBeltSwitchElement(element);
+ int belt_dir_nr = element - belt_base_element[belt_nr];
+
+ return (belt_dir_nr % 3);
+}
+
+static int getBeltDirFromBeltSwitchElement(int element)
+{
+ static int belt_move_dir[3] =
+ {
+ MV_LEFT,
+ MV_NO_MOVING,
+ MV_RIGHT
+ };
+
+ int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
+
+ return belt_move_dir[belt_dir_nr];
+}
+
+static void InitField(int x, int y, boolean init_game)
+{
+ int element = Feld[x][y];
+
+ switch (element)
+ {
+ case EL_SP_MURPHY:
+ if (init_game)
+ {
+ if (stored_player[0].present)
+ {
+ Feld[x][y] = EL_SP_MURPHY_CLONE;
+ break;
+ }
+ else
+ {
+ stored_player[0].use_murphy_graphic = TRUE;
+ }
+
+ Feld[x][y] = EL_PLAYER_1;
+ }
+ /* no break! */
+ case EL_PLAYER_1:
+ case EL_PLAYER_2:
+ case EL_PLAYER_3:
+ case EL_PLAYER_4:
+ if (init_game)
+ {
+ struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
+ int jx = player->jx, jy = player->jy;
+
+ player->present = TRUE;
+
+ 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;
+ }
+ 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_RIGHT:
+ case EL_BUG_UP:
+ case EL_BUG_LEFT:
+ case EL_BUG_DOWN:
+ case EL_BUG:
+ case EL_SPACESHIP_RIGHT:
+ case EL_SPACESHIP_UP:
+ case EL_SPACESHIP_LEFT:
+ case EL_SPACESHIP_DOWN:
+ case EL_SPACESHIP:
+ case EL_BD_BUTTERFLY_RIGHT:
+ case EL_BD_BUTTERFLY_UP:
+ case EL_BD_BUTTERFLY_LEFT:
+ case EL_BD_BUTTERFLY_DOWN:
+ case EL_BD_BUTTERFLY:
+ case EL_BD_FIREFLY_RIGHT:
+ case EL_BD_FIREFLY_UP:
+ case EL_BD_FIREFLY_LEFT:
+ case EL_BD_FIREFLY_DOWN:
+ case EL_BD_FIREFLY:
+ case EL_PACMAN_RIGHT:
+ case EL_PACMAN_UP:
+ case EL_PACMAN_LEFT:
+ case EL_PACMAN_DOWN:
+ case EL_YAMYAM:
+ case EL_DARK_YAMYAM:
+ case EL_ROBOT:
+ case EL_PACMAN:
+ case EL_SP_SNIKSNAK:
+ case EL_SP_ELECTRON:
+ case EL_MOLE_LEFT:
+ case EL_MOLE_RIGHT:
+ case EL_MOLE_UP:
+ case EL_MOLE_DOWN:
+ case EL_MOLE:
+ 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:
+ MovDelay[x][y] = 96;
+ break;
+
+ case EL_LAMP:
+ local_player->lights_still_needed++;
+ break;
+
+ case EL_SOKOBAN_FIELD_EMPTY:
+ local_player->sokobanfields_still_needed++;
+ break;
+
+ case EL_PENGUIN:
+ local_player->friends_still_needed++;
+ break;
+
+ case EL_PIG:
+ case EL_DRAGON:
+ MovDir[x][y] = 1 << RND(4);
+ break;
+
+ case EL_SP_EMPTY:
+ Feld[x][y] = EL_EMPTY;
+ break;
+
+ case EL_EM_KEY_1_FILE:
+ Feld[x][y] = EL_EM_KEY_1;
+ break;
+ case EL_EM_KEY_2_FILE:
+ Feld[x][y] = EL_EM_KEY_2;
+ break;
+ case EL_EM_KEY_3_FILE:
+ Feld[x][y] = EL_EM_KEY_3;
+ break;
+ case EL_EM_KEY_4_FILE:
+ Feld[x][y] = EL_EM_KEY_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;
+
+ case EL_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */
+ if (init_game)
+ Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
+ break;
+
+ case EL_LIGHT_SWITCH_ACTIVE:
+ if (init_game)
+ game.light_time_left = level.time_light * FRAMES_PER_SECOND;
+ break;
+
+ default:
+ if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
+ InitMovDir(x, y);
+ break;
+ }
+}
+
+void DrawGameDoorValues()
+{
+ int i, j;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ for (j=0; j<4; j++)
+ if (stored_player[i].key[j])
+ DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS,
+ el2edimg(EL_KEY_1 + j));
+
+ DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
+ int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
+ DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
+ int2str(local_player->dynamite, 3), FONT_TEXT_2);
+ DrawText(DX + XX_SCORE, DY + YY_SCORE,
+ int2str(local_player->score, 5), FONT_TEXT_2);
+ DrawText(DX + XX_TIME, DY + YY_TIME,
+ int2str(TimeLeft, 3), FONT_TEXT_2);
+}
+
+
+/*
+ =============================================================================
+ InitGameEngine()
+ -----------------------------------------------------------------------------
+ initialize game engine due to level / tape version number
+ =============================================================================
+*/
+
+static void InitGameEngine()
+{
+ int i;
+
+ /* set game engine from tape file when re-playing, else from level file */
+ game.engine_version = (tape.playing ? tape.engine_version :
+ level.game_version);
+
+ /* dynamically adjust element properties according to game engine version */
+ InitElementPropertiesEngine(game.engine_version);
+
+#if 0
+ printf("level %d: level version == %06d\n", level_nr, level.game_version);
+ printf(" tape version == %06d [%s] [file: %06d]\n",
+ tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
+ tape.file_version);
+ printf(" => game.engine_version == %06d\n", game.engine_version);
+#endif
+
+ /* ---------- initialize player's initial move delay --------------------- */
+
+ /* dynamically adjust player properties according to game engine version */
+ game.initial_move_delay =
+ (game.engine_version <= VERSION_IDENT(2,0,1) ? INITIAL_MOVE_DELAY_ON :
+ INITIAL_MOVE_DELAY_OFF);
+
+ /* dynamically adjust player properties according to level information */
+ game.initial_move_delay_value =
+ (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
+
+ /* ---------- initialize changing elements ------------------------------- */
+
+ /* initialize changing elements information */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+#if 1
+ element_info[i].change.pre_change_function = NULL;
+ element_info[i].change.change_function = NULL;
+ element_info[i].change.post_change_function = NULL;
+
+ if (!IS_CUSTOM_ELEMENT(i))
+ {
+ element_info[i].change.target_element = EL_EMPTY_SPACE;
+ element_info[i].change.delay_fixed = 0;
+ element_info[i].change.delay_random = 0;
+ element_info[i].change.delay_frames = 1;
+ }
+
+ changing_element[i] = FALSE;
+#else
+ changing_element[i].base_element = EL_UNDEFINED;
+ changing_element[i].next_element = EL_UNDEFINED;
+ changing_element[i].change_delay = -1;
+ changing_element[i].pre_change_function = NULL;
+ changing_element[i].change_function = NULL;
+ changing_element[i].post_change_function = NULL;
+#endif
+ }
+
+ /* add changing elements from pre-defined list */
+ for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++)
+ {
+ int element = changing_element_list[i].element;
+ struct ChangingElementInfo *ce = &changing_element_list[i];
+ struct ElementChangeInfo *change = &element_info[element].change;
+
+#if 1
+ change->target_element = ce->target_element;
+ change->delay_fixed = ce->change_delay;
+ change->pre_change_function = ce->pre_change_function;
+ change->change_function = ce->change_function;
+ change->post_change_function = ce->post_change_function;
+
+ changing_element[element] = TRUE;
+#else
+ changing_element[element].base_element = ce->base_element;
+ changing_element[element].next_element = ce->next_element;
+ changing_element[element].change_delay = ce->change_delay;
+ changing_element[element].pre_change_function = ce->pre_change_function;
+ changing_element[element].change_function = ce->change_function;
+ changing_element[element].post_change_function = ce->post_change_function;
+#endif
+ }
+
+ /* add changing elements from custom element configuration */
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+#if 0
+ struct ElementChangeInfo *change = &element_info[element].change;
+#endif
+
+ /* only add custom elements that change after fixed/random frame delay */
+ if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY))
+ continue;
+
+#if 1
+ changing_element[element] = TRUE;
+#else
+ changing_element[element].base_element = element;
+ changing_element[element].next_element = change->target_element;
+ changing_element[element].change_delay = (change->delay_fixed *
+ change->delay_frames);
+#endif
+ }
+
+ /* ---------- initialize trigger events ---------------------------------- */
+
+ /* initialize trigger events information */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ trigger_events[i] = EP_BITMASK_DEFAULT;
+
+ /* add trigger events from element change event properties */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
+ trigger_events[element_info[i].change.trigger_element] |=
+ element_info[i].change.events;
+
+ /* ---------- initialize push delay -------------------------------------- */
+
+ /* initialize push delay values to default */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+ if (!IS_CUSTOM_ELEMENT(i))
+ {
+ element_info[i].push_delay_fixed = 2;
+ element_info[i].push_delay_random = 8;
+ }
+ }
+
+ /* set push delay value for certain elements from pre-defined list */
+ for (i=0; push_delay_list[i].element != EL_UNDEFINED; i++)
+ {
+ int e = push_delay_list[i].element;
+
+ element_info[e].push_delay_fixed = push_delay_list[i].push_delay_fixed;
+ element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
+ }
+
+ /* ---------- initialize move stepsize ----------------------------------- */
+
+ /* initialize move stepsize values to default */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ if (!IS_CUSTOM_ELEMENT(i))
+ element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL;
+
+ /* set move stepsize value for certain elements from pre-defined list */
+ for (i=0; move_stepsize_list[i].element != EL_UNDEFINED; i++)
+ {
+ int e = move_stepsize_list[i].element;
+
+ element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
+ }
+
+ /* ---------- initialize gem count --------------------------------------- */
+
+ /* initialize gem count values for each element */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ if (!IS_CUSTOM_ELEMENT(i))
+ element_info[i].gem_count = 0;
+
+ /* add gem count values for all elements from pre-defined list */
+ for (i=0; gem_count_list[i].element != EL_UNDEFINED; i++)
+ element_info[gem_count_list[i].element].gem_count =
+ gem_count_list[i].gem_count;
+}
+
+
+/*
+ =============================================================================
+ InitGame()
+ -----------------------------------------------------------------------------
+ initialize and start new game
+ =============================================================================
+*/
+