((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
(e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e))
+#define GET_VALID_PLAYER_ELEMENT(e) \
+ ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? (e) : EL_PLAYER_1)
+
#define CAN_GROW_INTO(e) \
- (e == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
+ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
#define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
}
access_direction_list[] =
{
- { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
- { EL_TUBE_VERTICAL, MV_UP | MV_DOWN },
- { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT },
- { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN },
- { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN },
- { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP },
- { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN },
- { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP },
- { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN },
- { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP },
- { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN },
-
- { EL_SP_PORT_LEFT, MV_RIGHT },
- { EL_SP_PORT_RIGHT, MV_LEFT },
- { EL_SP_PORT_UP, MV_DOWN },
- { EL_SP_PORT_DOWN, MV_UP },
- { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT },
- { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN },
- { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
- { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT },
- { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT },
- { EL_SP_GRAVITY_PORT_UP, MV_DOWN },
- { EL_SP_GRAVITY_PORT_DOWN, MV_UP },
-
- { EL_UNDEFINED, MV_NO_MOVING }
+ { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL, MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT },
+ { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP },
+ { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN },
+ { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP },
+ { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN },
+ { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP },
+ { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN },
+
+ { EL_SP_PORT_LEFT, MV_RIGHT },
+ { EL_SP_PORT_RIGHT, MV_LEFT },
+ { EL_SP_PORT_UP, MV_DOWN },
+ { EL_SP_PORT_DOWN, MV_UP },
+ { EL_SP_PORT_HORIZONTAL, MV_LEFT | MV_RIGHT },
+ { EL_SP_PORT_VERTICAL, MV_UP | MV_DOWN },
+ { EL_SP_PORT_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_SP_GRAVITY_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_PORT_DOWN, MV_UP },
+ { EL_SP_GRAVITY_ON_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_ON_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_ON_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_ON_PORT_DOWN, MV_UP },
+ { EL_SP_GRAVITY_OFF_PORT_LEFT, MV_RIGHT },
+ { EL_SP_GRAVITY_OFF_PORT_RIGHT, MV_LEFT },
+ { EL_SP_GRAVITY_OFF_PORT_UP, MV_DOWN },
+ { EL_SP_GRAVITY_OFF_PORT_DOWN, MV_UP },
+
+ { EL_UNDEFINED, MV_NO_MOVING }
};
static unsigned long trigger_events[MAX_NUM_ELEMENTS];
{
#if 1
/* use random direction as default start direction */
- if (game.engine_version >= VERSION_IDENT(3,1,0,2))
+ if (game.engine_version >= VERSION_IDENT(3,1,0,0))
MovDir[x][y] = 1 << RND(4);
#endif
void RelocatePlayer(int jx, int jy, int el_player_raw)
{
+#if 1
+ int el_player = GET_VALID_PLAYER_ELEMENT(el_player_raw);
+#else
int el_player = (el_player_raw == EL_SP_MURPHY ? EL_PLAYER_1 :el_player_raw);
+#endif
struct PlayerInfo *player = &stored_player[el_player - EL_PLAYER_1];
boolean ffwd_delay = (tape.playing && tape.fast_forward);
boolean no_delay = (tape.warp_forward);
TestIfPlayerTouchesCustomElement(jx, jy);
#endif
-#if 1
+#if 0
+ printf("::: %d,%d: %d\n", jx, jy-1, Changed[jx][jy-1]);
+#endif
+
+#if 0
+#if 0
+ /* needed to allow change of walkable custom element by entering player */
+ if (!(Changed[jx][jy] & CH_EVENT_BIT(CE_ENTERED_BY_PLAYER)))
+ Changed[jx][jy] = 0; /* allow another change (but prevent loop) */
+#else
/* needed to allow change of walkable custom element by entering player */
Changed[jx][jy] = 0; /* allow another change */
#endif
+#endif
#if 0
printf("::: player entering %d, %d from %s ...\n", jx, jy,
continue;
#else
/* indestructible elements can only explode in center (but not flames) */
+#if 1
+ if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey ||
+ mode == EX_TYPE_BORDER)) ||
+ element == EL_FLAMES)
+ continue;
+#else
if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
element == EL_FLAMES)
continue;
#endif
+#endif
#else
if ((IS_INDESTRUCTIBLE(element) &&
#if 1
if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
(game.engine_version < VERSION_IDENT(3,1,0,0) ||
- (x == ex && y == ey)))
+ (x == ex && y == ey && mode != EX_TYPE_BORDER)))
#else
if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
#endif
Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY);
Store[x][y] = 0;
#endif
+
+#if 0
+ printf("::: %d,%d: %d %s [%d, %d]\n", x, y, Feld[x][y],
+ element_info[Feld[x][y]].token_name,
+ Store[x][y], Store2[x][y]);
+#endif
}
continue;
if (IS_INDESTRUCTIBLE(element))
Back[x][y] = element;
#else
+#if 1
#if 1
+ if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
+ (x != ex || y != ey || mode == EX_TYPE_BORDER))
+ Back[x][y] = element;
+#else
if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
(x != ex || y != ey))
Back[x][y] = element;
+#endif
#else
if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element))
Back[x][y] = element;
else
Store[x][y] = EL_EMPTY;
- if (x != ex || y != ey ||
- center_element == EL_AMOEBA_TO_DIAMOND || mode == EX_TYPE_BORDER)
+ if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
+ center_element == EL_AMOEBA_TO_DIAMOND)
Store2[x][y] = element;
+#if 0
+ printf("::: %d,%d: %d %s\n", x, y, Store2[x][y],
+ element_info[Store2[x][y]].token_name);
+#endif
+
#if 0
if (AmoebaNr[x][y] &&
(element == EL_AMOEBA_FULL ||
game.yamyam_content_nr =
(game.yamyam_content_nr + 1) % level.num_yamyam_contents;
+#if 0
+ printf("::: %d,%d: %d %s [%d]\n", ex + 1, ey, Feld[ex + 1][ey],
+ element_info[Feld[ex + 1][ey]].token_name, Store2[ex + 1][ey]);
+#endif
+
return;
}
border_element = StorePlayer[x][y];
#endif
+#if 0
+ printf("::: %d,%d: %d %s [%d]\n", x, y, border_element,
+ element_info[border_element].token_name, Store2[x][y]);
+#endif
+
#if 0
printf("::: phase == %d\n", phase);
#endif
}
else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
{
+#if 0
+ printf("::: %d,%d: %d %s\n", x, y, border_element,
+ element_info[border_element].token_name);
+#endif
+
Feld[x][y] = Store2[x][y];
Store2[x][y] = 0;
Bang(x, y);
#if 1
if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
- CheckCollision[x][y] && IN_LEV_FIELD_AND_NOT_FREE(newx, newy))
+ CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy))
#else
if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
DrawLevelFieldCrumbledSandNeighbours(x, y);
}
+#if 0
Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
+#endif
#if 0
TestIfBadThingTouchesHero(x, y);
TestIfElementTouchesCustomElement(x, y);
#endif
+ /* "Changed[][]" not set yet to allow "entered by player" change one time */
if (ELEM_IS_PLAYER(target_element))
RelocatePlayer(x, y, target_element);
+#if 1
+ Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
+#endif
+
#if 1
TestIfBadThingTouchesHero(x, y);
TestIfPlayerTouchesCustomElement(x, y);
continue;
}
+#if 0
+ if (Changed[ex][ey]) /* do not change already changed elements */
+ {
+ can_replace[xx][yy] = FALSE;
+ complete_replace = FALSE;
+
+ continue;
+ }
+#endif
+
e = Feld[ex][ey];
if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
#if 1
return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
+#if 0
(!IS_SP_PORT(Feld[newx][newy]) || move_dir == MV_UP) &&
+#endif
(IS_DIGGABLE(Feld[newx][newy]) ||
IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
canPassField(newx, newy, move_dir)));
TestIfHeroTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
#if 1
- TestIfElementTouchesCustomElement(jx, jy); /* for empty space */
+#if 1
+ /* needed because pushed element has not yet reached its destination,
+ so it would trigger a change event at its previous field location */
+ if (!player->is_pushing)
+#endif
+ TestIfElementTouchesCustomElement(jx, jy); /* for empty space */
#endif
if (!player->active)
element == EL_SP_GRAVITY_PORT_UP ||
element == EL_SP_GRAVITY_PORT_DOWN)
game.gravity = !game.gravity;
+ else if (element == EL_SP_GRAVITY_ON_PORT_LEFT ||
+ element == EL_SP_GRAVITY_ON_PORT_RIGHT ||
+ element == EL_SP_GRAVITY_ON_PORT_UP ||
+ element == EL_SP_GRAVITY_ON_PORT_DOWN)
+ game.gravity = TRUE;
+ else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT ||
+ element == EL_SP_GRAVITY_OFF_PORT_RIGHT ||
+ element == EL_SP_GRAVITY_OFF_PORT_UP ||
+ element == EL_SP_GRAVITY_OFF_PORT_DOWN)
+ game.gravity = FALSE;
}
/* automatically move to the next field with double speed */
nexty = dropy + GET_DY_FROM_DIR(move_direction);
#if 1
- Changed[dropx][dropy] = 0; /* allow another change */
- CheckCollision[dropx][dropy] = 2;
+ Changed[dropx][dropy] = 0; /* allow another change */
+ CheckCollision[dropx][dropy] = 2;
#else
- if (IN_LEV_FIELD(nextx, nexty) && IS_FREE(nextx, nexty))
+ if (IN_LEV_FIELD_AND_IS_FREE(nextx, nexty))
{
#if 0
WasJustMoving[dropx][dropy] = 3;
#endif
#endif
}
-#if 1
+#if 0
+ /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */
else
{
Changed[dropx][dropy] = 0; /* allow another change */