+ ResetGfxAnimation(x, y);
+ ResetRandomAnimationValue(x, y);
+
+ if (change->pre_change_function)
+ change->pre_change_function(x, y);
+ }
+
+ ChangeDelay[x][y]--;
+
+ if (ChangeDelay[x][y] != 0) /* continue element change */
+ {
+ int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+ if (change->change_function)
+ change->change_function(x, y);
+ }
+ else /* finish element change */
+ {
+ if (IS_MOVING(x, y)) /* never change a running system ;-) */
+ {
+ ChangeDelay[x][y] = 1; /* try change after next move step */
+
+ return;
+ }
+
+ ChangeElementNow(x, y, element, page);
+
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
+}
+
+static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
+ int trigger_event)
+{
+ int i, j, x, y;
+
+ if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ return FALSE;
+
+ /* prevent this function from running into a loop */
+ if (trigger_event == CE_OTHER_IS_CHANGING)
+ Changing[lx][ly] = TRUE;
+
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+#if 1
+ boolean change_element = FALSE;
+ int page;
+
+ if (!CAN_CHANGE(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ continue;
+
+ for (j=0; j < element_info[element].num_change_pages; j++)
+ {
+ if (element_info[element].change_page[j].trigger_element ==
+ trigger_element)
+ {
+ change_element = TRUE;
+ page = j;
+
+ break;
+ }
+ }
+
+ if (!change_element)
+ continue;
+
+#else
+ if (!CAN_CHANGE(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event) ||
+ element_info[element].change->trigger_element != trigger_element)
+ continue;
+#endif
+
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+ if (x == lx && y == ly) /* do not change trigger element itself */
+ continue;
+
+ if (Changing[x][y]) /* do not change just changing elements */
+ continue;
+
+ if (Feld[x][y] == element)
+ {
+ ChangeDelay[x][y] = 1;
+ ChangeElement(x, y, page);
+
+ Changing[x][y] = TRUE; /* do not change just changed elements */
+ }
+ }
+ }
+
+ /* reset change prevention array */
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ Changing[x][y] = FALSE;
+
+ return TRUE;
+}
+
+static boolean CheckElementChangeExt(int x, int y, int element,
+ int trigger_event, int page)
+{
+ if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ return FALSE;
+
+ if (Feld[x][y] == EL_BLOCKED)
+ Blocked2Moving(x, y, &x, &y);
+
+ ChangeDelay[x][y] = 1;
+ ChangeElement(x, y, page);
+
+ return TRUE;
+}
+
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+ int page = element_info[element].event_page_num[trigger_event];
+
+ return CheckElementChangeExt(x, y, element, trigger_event, page);
+}
+
+static void PlayerActions(struct PlayerInfo *player, byte player_action)
+{
+ static byte stored_player_action[MAX_PLAYERS];
+ static int num_stored_actions = 0;
+ boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
+ int left = player_action & JOY_LEFT;
+ int right = player_action & JOY_RIGHT;
+ int up = player_action & JOY_UP;
+ int down = player_action & JOY_DOWN;
+ int button1 = player_action & JOY_BUTTON_1;
+ int button2 = player_action & JOY_BUTTON_2;
+ int dx = (left ? -1 : right ? 1 : 0);
+ int dy = (up ? -1 : down ? 1 : 0);
+
+ stored_player_action[player->index_nr] = 0;
+ num_stored_actions++;
+
+ if (!player->active || tape.pausing)
+ return;
+
+ if (player_action)
+ {
+ if (button1)
+ snapped = SnapField(player, dx, dy);
+ else
+ {
+ if (button2)
+ dropped = DropElement(player);
+
+ moved = MoveFigure(player, dx, dy);
+ }
+
+ if (tape.single_step && tape.recording && !tape.pausing)
+ {
+ if (button1 || (dropped && !moved))
+ {
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+ SnapField(player, 0, 0); /* stop snapping */
+ }
+ }
+
+ stored_player_action[player->index_nr] = player_action;
+ }
+ else
+ {
+ /* no actions for this player (no input at player's configured device) */
+
+ DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+ SnapField(player, 0, 0);
+ CheckGravityMovement(player);
+
+ if (player->MovPos == 0)
+ InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
+
+ if (player->MovPos == 0) /* needed for tape.playing */
+ player->is_moving = FALSE;
+ }
+
+ if (tape.recording && num_stored_actions >= MAX_PLAYERS)
+ {
+ TapeRecordAction(stored_player_action);
+ num_stored_actions = 0;
+ }
+}
+
+void GameActions()
+{
+ static unsigned long action_delay = 0;
+ unsigned long action_delay_value;
+ int magic_wall_x = 0, magic_wall_y = 0;
+ int i, x, y, element, graphic;
+ byte *recorded_player_action;
+ byte summarized_player_action = 0;
+
+ if (game_status != GAME_MODE_PLAYING)
+ return;
+
+ action_delay_value =