+ /* ---------- initialize trigger events ---------------------------------- */
+
+ /* initialize trigger events information */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ trigger_events[i] = EP_BITMASK_DEFAULT;
+
+#if 1
+ /* add trigger events from element change event properties */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[i];
+
+ for (j = 0; j < ei->num_change_pages; j++)
+ {
+ if (!ei->change_page[j].can_change)
+ continue;
+
+ if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
+ {
+ int trigger_element = ei->change_page[j].trigger_element;
+
+ trigger_events[trigger_element] |= ei->change_page[j].events;
+ }
+ }
+ }
+#else
+ /* add trigger events from element change event properties */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
+ trigger_events[element_info[i].change->trigger_element] |=
+ element_info[i].change->events;
+#endif
+
+ /* ---------- 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 = game.default_push_delay_fixed;
+ element_info[i].push_delay_random = game.default_push_delay_random;
+ }
+ }
+
+ /* 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].collect_count = 0;
+
+ /* add gem count values for all elements from pre-defined list */
+ for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
+ element_info[collect_count_list[i].element].collect_count =
+ collect_count_list[i].count;
+}
+
+
+/*
+ =============================================================================
+ InitGame()
+ -----------------------------------------------------------------------------
+ initialize and start new game
+ =============================================================================
+*/
+
+void InitGame()
+{
+ boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
+ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
+ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */
+ int i, j, k, x, y;
+
+ InitGameEngine();
+
+#if 0
+#if DEBUG
+#if USE_NEW_AMOEBA_CODE
+ printf("Using new amoeba code.\n");
+#else
+ printf("Using old amoeba code.\n");
+#endif
+#endif
+#endif
+
+ /* don't play tapes over network */
+ network_playing = (options.network && !tape.playing);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ player->index_nr = i;
+ player->element_nr = EL_PLAYER_1 + i;
+
+ player->present = FALSE;
+ player->active = FALSE;
+
+ player->action = 0;
+ player->effective_action = 0;
+ player->programmed_action = 0;
+
+ player->score = 0;
+ player->gems_still_needed = level.gems_needed;
+ player->sokobanfields_still_needed = 0;
+ player->lights_still_needed = 0;
+ player->friends_still_needed = 0;
+
+ for (j = 0; j < 4; j++)
+ player->key[j] = FALSE;
+
+ player->dynabomb_count = 0;
+ player->dynabomb_size = 1;
+ player->dynabombs_left = 0;
+ player->dynabomb_xl = FALSE;
+
+ player->MovDir = MV_NO_MOVING;
+ player->MovPos = 0;
+ player->GfxPos = 0;
+ player->GfxDir = MV_NO_MOVING;
+ player->GfxAction = ACTION_DEFAULT;
+ player->Frame = 0;
+ player->StepFrame = 0;
+
+ player->use_murphy_graphic = FALSE;
+
+ player->actual_frame_counter = 0;
+
+ player->step_counter = 0;
+
+ player->last_move_dir = MV_NO_MOVING;
+
+ player->is_waiting = FALSE;
+ player->is_moving = FALSE;
+ player->is_digging = FALSE;
+ player->is_snapping = FALSE;
+ player->is_collecting = FALSE;
+ player->is_pushing = FALSE;
+ player->is_switching = FALSE;
+
+ player->is_bored = FALSE;
+ player->is_sleeping = FALSE;
+
+ player->frame_counter_bored = -1;
+ player->frame_counter_sleeping = -1;
+
+ player->anim_delay_counter = 0;
+ player->post_delay_counter = 0;
+
+ player->action_waiting = ACTION_DEFAULT;
+ player->last_action_waiting = ACTION_DEFAULT;
+ player->special_action_bored = ACTION_DEFAULT;
+ player->special_action_sleeping = ACTION_DEFAULT;
+
+ player->num_special_action_bored = 0;
+ player->num_special_action_sleeping = 0;
+
+ /* determine number of special actions for bored and sleeping animation */
+ for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++)
+ {
+ boolean found = FALSE;
+
+ for (k = 0; k < NUM_DIRECTIONS; k++)
+ if (el_act_dir2img(player->element_nr, j, k) !=
+ el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
+ found = TRUE;
+
+ if (found)
+ player->num_special_action_bored++;
+ else
+ break;
+ }
+ for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++)
+ {
+ boolean found = FALSE;
+
+ for (k = 0; k < NUM_DIRECTIONS; k++)
+ if (el_act_dir2img(player->element_nr, j, k) !=
+ el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
+ found = TRUE;
+
+ if (found)
+ player->num_special_action_sleeping++;
+ else
+ break;
+ }
+
+ player->switch_x = -1;
+ player->switch_y = -1;
+
+ player->show_envelope = 0;
+
+ player->move_delay = game.initial_move_delay;
+ player->move_delay_value = game.initial_move_delay_value;
+
+ player->push_delay = 0;
+ player->push_delay_value = game.initial_push_delay_value;
+
+ player->last_jx = player->last_jy = 0;
+ player->jx = player->jy = 0;
+
+ player->shield_normal_time_left = 0;
+ player->shield_deadly_time_left = 0;
+
+ player->inventory_size = 0;
+
+ DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+ SnapField(player, 0, 0);
+
+ player->LevelSolved = FALSE;
+ player->GameOver = FALSE;
+ }
+
+ network_player_action_received = FALSE;
+
+#if defined(PLATFORM_UNIX)
+ /* initial null action */
+ if (network_playing)
+ SendToServer_MovePlayer(MV_NO_MOVING);
+#endif
+
+ ZX = ZY = -1;
+
+ FrameCounter = 0;
+ TimeFrames = 0;
+ TimePlayed = 0;
+ TimeLeft = level.time;
+
+ ScreenMovDir = MV_NO_MOVING;
+ ScreenMovPos = 0;
+ ScreenGfxPos = 0;
+
+ ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */
+
+ AllPlayersGone = FALSE;
+
+ game.yamyam_content_nr = 0;
+ game.magic_wall_active = FALSE;
+ game.magic_wall_time_left = 0;
+ game.light_time_left = 0;
+ game.timegate_time_left = 0;
+ game.switchgate_pos = 0;
+ game.balloon_dir = MV_NO_MOVING;
+ game.gravity = level.initial_gravity;
+ game.explosions_delayed = TRUE;
+
+ game.envelope_active = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ game.belt_dir[i] = MV_NO_MOVING;
+ game.belt_dir_nr[i] = 3; /* not moving, next moving left */
+ }
+
+ for (i = 0; i < MAX_NUM_AMOEBA; i++)
+ AmoebaCnt[i] = AmoebaCnt2[i] = 0;
+
+ for (x = 0; x < lev_fieldx; x++)
+ {
+ for (y = 0; y < lev_fieldy; y++)
+ {
+ Feld[x][y] = level.field[x][y];
+ MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+ ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
+ Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
+ AmoebaNr[x][y] = 0;
+ WasJustMoving[x][y] = 0;
+ WasJustFalling[x][y] = 0;
+ Stop[x][y] = FALSE;
+ Pushed[x][y] = FALSE;
+
+ Changed[x][y] = CE_BITMASK_DEFAULT;
+ ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+
+ ExplodePhase[x][y] = 0;
+ ExplodeField[x][y] = EX_NO_EXPLOSION;
+
+ RunnerVisit[x][y] = 0;
+ PlayerVisit[x][y] = 0;
+
+ GfxFrame[x][y] = 0;
+ GfxRandom[x][y] = INIT_GFX_RANDOM();
+ GfxElement[x][y] = EL_UNDEFINED;
+ GfxAction[x][y] = ACTION_DEFAULT;
+ GfxDir[x][y] = MV_NO_MOVING;
+ }
+ }
+
+ for (y = 0; y < lev_fieldy; y++)
+ {
+ for (x = 0; x < lev_fieldx; x++)
+ {
+ if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
+ emulate_bd = FALSE;
+ if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
+ emulate_sb = FALSE;
+ if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
+ emulate_sp = FALSE;
+
+ InitField(x, y, TRUE);
+ }
+ }
+
+ InitBeltMovement();
+
+ game.emulation = (emulate_bd ? EMU_BOULDERDASH :
+ emulate_sb ? EMU_SOKOBAN :
+ emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
+
+ /* correct non-moving belts to start moving left */
+ for (i = 0; i < 4; i++)
+ if (game.belt_dir[i] == MV_NO_MOVING)
+ game.belt_dir_nr[i] = 3; /* not moving, next moving left */
+
+ /* check if any connected player was not found in playfield */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ if (player->connected && !player->present)
+ {
+ for (j = 0; j < MAX_PLAYERS; j++)
+ {
+ struct PlayerInfo *some_player = &stored_player[j];
+ int jx = some_player->jx, jy = some_player->jy;
+
+ /* assign first free player found that is present in the playfield */
+ if (some_player->present && !some_player->connected)
+ {
+ player->present = TRUE;
+ player->active = TRUE;
+ some_player->present = FALSE;
+
+ StorePlayer[jx][jy] = player->element_nr;
+ player->jx = player->last_jx = jx;
+ player->jy = player->last_jy = jy;
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (tape.playing)
+ {
+ /* when playing a tape, eliminate all players who do not participate */
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (stored_player[i].active && !tape.player_participates[i])
+ {
+ struct PlayerInfo *player = &stored_player[i];
+ int jx = player->jx, jy = player->jy;
+
+ player->active = FALSE;