+static int getBeltNrFromBeltElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT2_LEFT ? 0 :
+ element < EL_CONVEYOR_BELT3_LEFT ? 1 :
+ element < EL_CONVEYOR_BELT4_LEFT ? 2 : 3);
+}
+
+static int getBeltNrFromBeltActiveElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT2_LEFT_ACTIVE ? 0 :
+ element < EL_CONVEYOR_BELT3_LEFT_ACTIVE ? 1 :
+ element < EL_CONVEYOR_BELT4_LEFT_ACTIVE ? 2 : 3);
+}
+
+static int getBeltNrFromBeltSwitchElement(int element)
+{
+ return (element < EL_CONVEYOR_BELT2_SWITCH_LEFT ? 0 :
+ element < EL_CONVEYOR_BELT3_SWITCH_LEFT ? 1 :
+ element < EL_CONVEYOR_BELT4_SWITCH_LEFT ? 2 : 3);
+}
+
+static int getBeltDirNrFromBeltSwitchElement(int element)
+{
+ static int belt_base_element[4] =
+ {
+ EL_CONVEYOR_BELT1_SWITCH_LEFT,
+ EL_CONVEYOR_BELT2_SWITCH_LEFT,
+ EL_CONVEYOR_BELT3_SWITCH_LEFT,
+ EL_CONVEYOR_BELT4_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)
+{
+ switch (Feld[x][y])
+ {
+ case EL_SP_MURPHY:
+ if (init_game)
+ {
+ if (stored_player[0].present)
+ {
+ Feld[x][y] = EL_SP_MURPHY_CLONE;
+ break;
+ }
+
+ Feld[x][y] = EL_PLAYER1;
+ }
+ /* no break! */
+ case EL_PLAYER1:
+ case EL_PLAYER2:
+ case EL_PLAYER3:
+ case EL_PLAYER4:
+ if (init_game)
+ {
+ struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER1];
+ 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_ACIDPOOL_TOPLEFT;
+ else if (x > 0 && Feld[x-1][y] == EL_ACID)
+ Feld[x][y] = EL_ACIDPOOL_TOPRIGHT;
+ else if (y > 0 && Feld[x][y-1] == EL_ACIDPOOL_TOPLEFT)
+ Feld[x][y] = EL_ACIDPOOL_BOTTOMLEFT;
+ else if (y > 0 && Feld[x][y-1] == EL_ACID)
+ Feld[x][y] = EL_ACIDPOOL_BOTTOM;
+ else if (y > 0 && Feld[x][y-1] == EL_ACIDPOOL_TOPRIGHT)
+ Feld[x][y] = EL_ACIDPOOL_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_CREATING;
+ 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_KEY1_FILE:
+ Feld[x][y] = EL_EM_KEY1;
+ break;
+ case EL_EM_KEY2_FILE:
+ Feld[x][y] = EL_EM_KEY2;
+ break;
+ case EL_EM_KEY3_FILE:
+ Feld[x][y] = EL_EM_KEY3;
+ break;
+ case EL_EM_KEY4_FILE:
+ Feld[x][y] = EL_EM_KEY4;
+ break;
+
+ case EL_CONVEYOR_BELT1_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT1_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT2_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT2_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT3_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT3_SWITCH_RIGHT:
+ case EL_CONVEYOR_BELT4_SWITCH_LEFT:
+ case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:
+ case EL_CONVEYOR_BELT4_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:
+ 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,
+ IMG_KEY1 + j);
+
+ DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
+ int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
+ int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_SCORE, DY + YY_SCORE,
+ int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
+ DrawText(DX + XX_TIME, DY + YY_TIME,
+ int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+}
+
+
+/*
+ =============================================================================
+ InitGameSound()
+ -----------------------------------------------------------------------------
+ initialize sound effect lookup table for element actions
+ =============================================================================
+*/
+
+void InitGameSound()
+{
+ int sound_effect_properties[NUM_SOUND_FILES];
+ int i, j;
+
+#if 0
+ debug_print_timestamp(0, NULL);
+#endif
+
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ for (j=0; j<NUM_SND_ACTIONS; j++)
+ element_action_sound[i][j] = -1;
+
+ for (i=0; i<NUM_SOUND_FILES; i++)
+ {
+ int len_effect_text = strlen(sound_files[i].token);
+
+ sound_effect_properties[i] = SND_ACTION_UNKNOWN;
+ is_loop_sound[i] = FALSE;
+
+ /* determine all loop sounds and identify certain sound classes */
+
+ for (j=0; sound_action_properties[j].text; j++)
+ {
+ int len_action_text = strlen(sound_action_properties[j].text);
+
+ if (len_action_text < len_effect_text &&
+ strcmp(&sound_files[i].token[len_effect_text - len_action_text],
+ sound_action_properties[j].text) == 0)
+ {
+ sound_effect_properties[i] = sound_action_properties[j].value;
+
+ if (sound_action_properties[j].is_loop)
+ is_loop_sound[i] = TRUE;
+ }
+ }
+
+ /* associate elements and some selected sound actions */
+
+ for (j=0; j<MAX_NUM_ELEMENTS; j++)
+ {
+ if (element_info[j].sound_class_name)
+ {
+ int len_class_text = strlen(element_info[j].sound_class_name);
+
+ if (len_class_text + 1 < len_effect_text &&
+ strncmp(sound_files[i].token,
+ element_info[j].sound_class_name, len_class_text) == 0 &&
+ sound_files[i].token[len_class_text] == '.')
+ {
+ int sound_action_value = sound_effect_properties[i];
+
+ element_action_sound[j][sound_action_value] = i;
+ }
+ }
+ }
+ }
+
+#if 0
+ debug_print_timestamp(0, "InitGameEngine");
+#endif
+
+#if 0
+ /* TEST ONLY */
+ {
+ int element = EL_SAND;
+ int sound_action = SND_ACTION_DIGGING;
+ int j = 0;
+
+ while (sound_action_properties[j].text)
+ {
+ if (sound_action_properties[j].value == sound_action)
+ printf("element %d, sound action '%s' == %d\n",
+ element, sound_action_properties[j].text,
+ element_action_sound[element][sound_action]);
+ j++;
+ }
+ }
+#endif
+}
+
+
+/*
+ =============================================================================
+ InitGameEngine()
+ -----------------------------------------------------------------------------
+ initialize game engine due to level / tape version number
+ =============================================================================
+*/
+
+static void InitGameEngine()
+{
+ int i;
+
+ game.engine_version = (tape.playing ? tape.engine_version :
+ level.game_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
+
+ /* 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);
+
+ /* dynamically adjust element properties according to game engine version */
+ {
+ static int ep_em_slippery_wall[] =
+ {
+ EL_STEELWALL,
+ EL_WALL,
+ EL_WALL_GROWING,
+ EL_WALL_GROWING_X,
+ EL_WALL_GROWING_Y,
+ EL_WALL_GROWING_XY
+ };
+ static int ep_em_slippery_wall_num = SIZEOF_ARRAY_INT(ep_em_slippery_wall);
+
+ for (i=0; i<ep_em_slippery_wall_num; i++)
+ {
+ if (level.em_slippery_gems) /* special EM style gems behaviour */
+ Elementeigenschaften2[ep_em_slippery_wall[i]] |=
+ EP_BIT_EM_SLIPPERY_WALL;
+ else
+ Elementeigenschaften2[ep_em_slippery_wall[i]] &=
+ ~EP_BIT_EM_SLIPPERY_WALL;
+ }
+
+ /* "EL_WALL_GROWING_ACTIVE" wasn't slippery for EM gems in version 2.0.1 */
+ if (level.em_slippery_gems && game.engine_version > VERSION_IDENT(2,0,1))
+ Elementeigenschaften2[EL_WALL_GROWING_ACTIVE] |= EP_BIT_EM_SLIPPERY_WALL;
+ else
+ Elementeigenschaften2[EL_WALL_GROWING_ACTIVE] &=~EP_BIT_EM_SLIPPERY_WALL;
+ }
+}
+
+
+/*
+ =============================================================================
+ InitGame()
+ -----------------------------------------------------------------------------
+ initialize and start new game
+ =============================================================================
+*/
+