+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int center_side = trigger_sides[i][0];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_PLAYER(x, y))
+ {
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ if (game.engine_version < VERSION_IDENT(3,0,7,0))
+ border_element = Feld[xx][yy]; /* may be moving! */
+ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+ border_element = Feld[xx][yy];
+ else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */
+ border_element = MovingOrBlocked2Element(xx, yy);
+ else
+ continue; /* center and border element do not touch */
+
+#if 1
+ /* !!! TEST ONLY !!! */
+ CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
+ player->index_bit, border_side);
+ CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+ CE_OTHER_GETS_TOUCHED,
+ player->index_bit, border_side);
+#else
+ CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+ CE_OTHER_GETS_TOUCHED,
+ player->index_bit, border_side);
+ CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
+ player->index_bit, border_side);
+#endif
+ }
+ else if (IS_PLAYER(xx, yy))
+ {
+ struct PlayerInfo *player = PLAYERINFO(xx, yy);
+
+ if (game.engine_version >= VERSION_IDENT(3,0,7,0))
+ {
+ if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
+ continue; /* center and border element do not touch */
+ }
+
+#if 1
+ /* !!! TEST ONLY !!! */
+ CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
+ player->index_bit, center_side);
+ CheckTriggeredElementChangeByPlayer(x, y, center_element,
+ CE_OTHER_GETS_TOUCHED,
+ player->index_bit, center_side);
+#else
+ CheckTriggeredElementChangeByPlayer(x, y, center_element,
+ CE_OTHER_GETS_TOUCHED,
+ player->index_bit, center_side);
+ CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
+ player->index_bit, center_side);
+#endif
+
+ break;
+ }
+ }
+}
+
+void TestIfElementTouchesCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_sides[4][2] =
+ {
+ /* center side border side */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */
+ };
+ static int touch_dir[4] =
+ {
+ MV_LEFT | MV_RIGHT,
+ MV_UP | MV_DOWN,
+ MV_UP | MV_DOWN,
+ MV_LEFT | MV_RIGHT
+ };
+ boolean change_center_element = FALSE;
+ int center_element_change_page = 0;
+ int center_element = Feld[x][y]; /* should always be non-moving! */
+ int border_trigger_element;
+ int i, j;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int center_side = trigger_sides[i][0];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (game.engine_version < VERSION_IDENT(3,0,7,0))
+ border_element = Feld[xx][yy]; /* may be moving! */
+ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+ border_element = Feld[xx][yy];
+ else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */
+ border_element = MovingOrBlocked2Element(xx, yy);
+ else
+ continue; /* center and border element do not touch */
+
+ /* check for change of center element (but change it only once) */
+ if (IS_CUSTOM_ELEMENT(center_element) &&
+ HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) &&
+ !change_center_element)
+ {
+ for (j = 0; j < element_info[center_element].num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change =
+ &element_info[center_element].change_page[j];
+
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ change->trigger_side & border_side &&
+#if 1
+ IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element)
+#else
+ change->trigger_element == border_element
+#endif
+ )
+ {
+ change_center_element = TRUE;
+ center_element_change_page = j;
+ border_trigger_element = border_element;
+
+ break;
+ }
+ }
+ }
+
+ /* check for change of border element */
+ if (IS_CUSTOM_ELEMENT(border_element) &&
+ HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
+ {
+ for (j = 0; j < element_info[border_element].num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change =
+ &element_info[border_element].change_page[j];
+
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ change->trigger_side & center_side &&
+#if 1
+ IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
+#else
+ change->trigger_element == center_element
+#endif
+ )
+ {
+#if 0
+ printf("::: border_element %d, %d\n", x, y);
+#endif
+
+ CheckElementChangeByPage(xx, yy, border_element, center_element,
+ CE_OTHER_IS_TOUCHING, j);
+ break;
+ }
+ }
+ }
+ }
+
+ if (change_center_element)
+ {
+#if 0
+ printf("::: center_element %d, %d\n", x, y);
+#endif
+
+ CheckElementChangeByPage(x, y, center_element, border_trigger_element,
+ CE_OTHER_IS_TOUCHING, center_element_change_page);
+ }
+}
+
+void TestIfElementHitsCustomElement(int x, int y, int direction)
+{
+ int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+ int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+ int hitx = x + dx, hity = y + dy;
+ int hitting_element = Feld[x][y];
+ int touched_element;
+#if 0
+ boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
+ !IS_FREE(hitx, hity) &&
+ (!IS_MOVING(hitx, hity) ||
+ MovDir[hitx][hity] != direction ||
+ ABS(MovPos[hitx][hity]) <= TILEY / 2));
+#endif
+
+ if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
+ return;
+