+ Bang(x, y);
+
+ return TRUE;
+ }
+
+ if (change->use_content)
+ {
+ boolean complete_change = TRUE;
+ boolean can_change[3][3];
+ int xx, yy;
+
+ for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++)
+ {
+ boolean half_destructible;
+ int ex = x + xx - 1;
+ int ey = y + yy - 1;
+ int e;
+
+ can_change[xx][yy] = TRUE;
+
+ if (ex == x && ey == y) /* do not check changing element itself */
+ continue;
+
+ if (change->content[xx][yy] == EL_EMPTY_SPACE)
+ {
+ can_change[xx][yy] = FALSE; /* do not change empty borders */
+
+ continue;
+ }
+
+ if (!IN_LEV_FIELD(ex, ey))
+ {
+ can_change[xx][yy] = FALSE;
+ complete_change = FALSE;
+
+ continue;
+ }
+
+ e = Feld[ex][ey];
+
+ if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+ e = MovingOrBlocked2Element(ex, ey);
+
+ half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
+
+ if ((change->power <= CP_NON_DESTRUCTIVE && !IS_FREE(ex, ey)) ||
+ (change->power <= CP_HALF_DESTRUCTIVE && !half_destructible) ||
+ (change->power <= CP_FULL_DESTRUCTIVE && IS_INDESTRUCTIBLE(e)))
+ {
+ can_change[xx][yy] = FALSE;
+ complete_change = FALSE;
+ }
+ }
+
+ if (!change->only_complete || complete_change)
+ {
+ boolean something_has_changed = FALSE;
+
+ if (change->only_complete && change->use_random_change &&
+ RND(100) < change->random)
+ return FALSE;
+
+ for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++)
+ {
+ int ex = x + xx - 1;
+ int ey = y + yy - 1;
+
+ if (can_change[xx][yy] && (!change->use_random_change ||
+ RND(100) < change->random))
+ {
+ if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+ RemoveMovingField(ex, ey);
+
+ ChangeEvent[ex][ey] = ChangeEvent[x][y];
+
+ ChangeElementNowExt(ex, ey, change->content[xx][yy]);
+
+ something_has_changed = TRUE;
+
+ /* for symmetry reasons, freeze newly created border elements */
+ if (ex != x || ey != y)
+ Stop[ex][ey] = TRUE; /* no more moving in this frame */
+ }
+ }
+
+ if (something_has_changed)
+ PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
+ }
+ }
+ else
+ {
+ ChangeElementNowExt(x, y, change->target_element);
+
+ PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
+ }
+
+ return TRUE;
+}
+
+static void ChangeElement(int x, int y, int page)
+{
+ int element = MovingOrBlocked2Element(x, y);
+ struct ElementChangeInfo *change = &element_info[element].change_page[page];
+
+#if 0
+#ifdef DEBUG
+ if (!CAN_CHANGE(element))
+ {
+ printf("\n\n");
+ printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
+ x, y, element, element_info[element].token_name);
+ printf("ChangeElement(): This should never happen!\n");
+ printf("\n\n");
+ }
+#endif
+#endif
+
+ if (ChangeDelay[x][y] == 0) /* initialize element change */
+ {
+ ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames +
+ RND(change->delay_random * change->delay_frames)) + 1;
+
+ 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;
+ }
+
+ if (ChangeElementNow(x, y, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
+ }
+}
+
+static boolean CheckTriggeredElementSideChange(int lx, int ly,
+ int trigger_element,
+ int trigger_side,
+ int trigger_event)
+{
+ int i, j, x, y;
+
+ if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ return FALSE;
+
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ boolean change_element = FALSE;
+ int page = 0;
+
+ if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ continue;
+
+ for (j=0; j < element_info[element].num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change = &element_info[element].change_page[j];
+
+ if (change->sides & trigger_side &&
+ change->trigger_element == trigger_element)
+ {
+ change_element = TRUE;
+ page = j;
+
+ break;
+ }
+ }
+
+ if (!change_element)
+ continue;
+
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+#if 0
+ if (x == lx && y == ly) /* do not change trigger element itself */
+ continue;
+#endif
+
+ if (Feld[x][y] == element)
+ {
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, page);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
+ int trigger_event)
+{
+ return CheckTriggeredElementSideChange(lx, ly, trigger_element, CH_SIDE_ANY,
+ trigger_event);
+}
+
+static boolean CheckElementSideChange(int x, int y, int element, int side,
+ 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);
+ element = Feld[x][y];
+ }
+
+ if (page < 0)
+ page = element_info[element].event_page_nr[trigger_event];
+
+ if (!(element_info[element].change_page[page].sides & side))
+ return FALSE;
+
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, page);
+
+ return TRUE;
+}
+
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+ return CheckElementSideChange(x, y, element, CH_SIDE_ANY, trigger_event, -1);
+}
+
+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