+ 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];
+
+ 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)
+ {
+ if (change->only_complete && change->use_random_change &&
+ RND(change->random) != 0)
+ return;
+
+ 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(change->random) == 0))
+ {
+ ChangeElementNowExt(ex, ey, change->content[xx][yy]);
+
+ /* for symmetry reasons, stop newly created border elements */
+ if (ex != x || ey != y)
+ Stop[ex][ey] = TRUE;
+ }
+ }
+
+ return;
+ }
+ }
+
+ ChangeElementNowExt(x, y, change->target_element);
+}
+
+static void ChangeElement(int x, int y)
+{
+#if 1
+ int element = MovingOrBlocked2Element(x, y);
+#else
+ int element = Feld[x][y];
+#endif
+ struct ElementChangeInfo *change = &element_info[element].change;
+
+ if (ChangeDelay[x][y] == 0) /* initialize element change */
+ {
+#if 1
+ ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames +
+ RND(change->delay_random * change->delay_frames)) + 1;
+#else
+ ChangeDelay[x][y] = changing_element[element].change_delay + 1;
+
+ if (IS_CUSTOM_ELEMENT(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
+ {
+ int max_random_delay = element_info[element].change.delay_random;
+ int delay_frames = element_info[element].change.delay_frames;
+
+ ChangeDelay[x][y] += RND(max_random_delay * delay_frames);
+ }
+#endif
+
+ ResetGfxAnimation(x, y);
+ ResetRandomAnimationValue(x, y);
+
+#if 1
+ if (change->pre_change_function)
+ change->pre_change_function(x, y);
+#else
+ if (changing_element[element].pre_change_function)
+ changing_element[element].pre_change_function(x, y);
+#endif
+ }
+
+ 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 1
+ if (change->change_function)
+ change->change_function(x, y);
+#else
+ if (changing_element[element].change_function)
+ changing_element[element].change_function(x, y);
+#endif
+ }
+ else /* finish element change */
+ {
+#if 0
+ int next_element = changing_element[element].next_element;
+#endif
+
+ if (IS_MOVING(x, y)) /* never change a running system ;-) */
+ {
+ ChangeDelay[x][y] = 1; /* try change after next move step */
+
+ return;
+ }
+
+#if 1
+ ChangeElementNow(x, y, element);
+
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+#else
+ if (next_element != EL_UNDEFINED)
+ ChangeElementNow(x, y, next_element);
+ else
+ ChangeElementNow(x, y, element_info[element].change.target_element);
+
+ if (changing_element[element].post_change_function)
+ changing_element[element].post_change_function(x, y);
+#endif
+ }
+}
+
+static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
+ int trigger_event)
+{
+ int i, x, y;
+
+ if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ return FALSE;
+
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+ if (!CAN_CHANGE(i) || !HAS_CHANGE_EVENT(i, trigger_event) ||
+ element_info[i].change.trigger_element != trigger_element)
+ continue;
+
+ 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 (Feld[x][y] == i)
+ {
+ ChangeDelay[x][y] = 1;
+ ChangeElement(x, y);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+ if (!CAN_CHANGE(element) || !HAS_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);
+
+ return TRUE;
+}
+
+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, bombed = 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