+2004-03-24
+ * fixed bug with movable elements not moving after left behind by CEs
+
2004-03-23
- * bug fixed with movable elements not moving anymore after falling down
+ * fixed bug with movable elements not moving anymore after falling down
2004-03-22
* fixed another bug with custom elements digging and leaving elements
-#define COMPILE_DATE_STRING "[2004-03-24 11:12]"
+#define COMPILE_DATE_STRING "[2004-03-25 03:08]"
#define GADGET_ID_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 8)
#define GADGET_ID_SP_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 9)
#define GADGET_ID_INSTANT_RELOCATION (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_CAN_FALL_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_CAN_MOVE_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_DONT_COLLIDE_WITH (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 27)
-#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 28)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 29)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 30)
-#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 31)
-#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 32)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 33)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 34)
+#define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_CAN_FALL_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_CAN_MOVE_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_DONT_COLLIDE_WITH (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 30)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 31)
+#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 32)
+#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 33)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 34)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 35)
/* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 35)
+#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 36)
#define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \
ED_NUM_ELEMENTLIST_BUTTONS - 1)
#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD 6
#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD 7
#define ED_CHECKBUTTON_ID_INSTANT_RELOCATION 8
-#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID 9
-#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID 10
-#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH 11
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 12
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 13
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 14
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 15
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 16
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 17
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 18
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 19
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 20
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 21
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 22
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 23
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 24
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 25
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY 26
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 27
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 28
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 29
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 30
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 31
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 32
-
-#define ED_NUM_CHECKBUTTONS 33
+#define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 9
+#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID 10
+#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID 11
+#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH 12
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 13
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 14
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 15
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 16
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 17
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 18
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 19
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 20
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 21
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 22
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 23
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 24
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 25
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 26
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY 27
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 28
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 29
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 30
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 31
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 32
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 33
+
+#define ED_NUM_CHECKBUTTONS 34
#define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_DOUBLE_SPEED
#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
NULL,
"no scrolling when relocating", "player gets relocated without delay"
},
+ {
+ ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(3),
+ GADGET_ID_CAN_PASS_TO_WALKABLE, GADGET_ID_NONE,
+ &level.can_pass_to_walkable,
+ NULL,
+ "can pass to walkable element", "player can pass to empty or walkable"
+ },
{
ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(0),
GADGET_ID_CAN_FALL_INTO_ACID, GADGET_ID_NONE,
ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
}
if (IS_GEM(properties_element))
#define CHUNK_SIZE_NONE -1 /* do not write chunk size */
#define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
#define LEVEL_HEADER_SIZE 80 /* size of level file header */
-#define LEVEL_HEADER_UNUSED 3 /* unused level header bytes */
+#define LEVEL_HEADER_UNUSED 2 /* unused level header bytes */
#define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
#define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
#define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */
level->block_last_field = FALSE;
level->sp_block_last_field = TRUE;
level->instant_relocation = FALSE;
+ level->can_pass_to_walkable = FALSE;
level->can_move_into_acid_bits = ~0; /* everything can move into acid */
level->dont_collide_with_bits = ~0; /* always deadly when colliding */
level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+ level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
putFile8Bit(file, (level->use_step_counter ? 1 : 0));
putFile8Bit(file, (level->instant_relocation ? 1 : 0));
+ putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
}
player->is_waiting = FALSE;
player->is_moving = FALSE;
+ player->is_auto_moving = FALSE;
player->is_digging = FALSE;
player->is_snapping = FALSE;
player->is_collecting = FALSE;
void ContinueMoving(int x, int y)
{
int element = Feld[x][y];
+ int stored = Store[x][y];
struct ElementInfo *ei = &element_info[element];
int direction = MovDir[x][y];
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
{
element = Feld[newx][newy] = EL_ACID;
}
-#if 1
+#if 0
else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
ei->move_leave_element != EL_EMPTY &&
(ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
ResetGfxAnimation(x, y); /* reset animation values for old field */
+#if 1
+ if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
+ ei->move_leave_element != EL_EMPTY &&
+ (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
+ stored != EL_EMPTY))
+ {
+ /* some elements can leave other elements behind after moving */
+
+ Feld[x][y] = ei->move_leave_element;
+ InitField(x, y, FALSE);
+
+ if (GFX_CRUMBLED(Feld[x][y]))
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
+ }
+#endif
+
#if 0
/* some elements can leave other elements behind after moving */
if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
}
#endif
+static boolean canFallDown(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+
+ return (IN_LEV_FIELD(jx, jy + 1) &&
+ (IS_FREE(jx, jy + 1) ||
+ (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
+ IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
+ !IS_WALKABLE_INSIDE(Feld[jx][jy]));
+}
+
+static boolean canPassField(int x, int y, int move_dir)
+{
+ int opposite_dir = MV_DIR_OPPOSITE(move_dir);
+ int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
+ int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
+ int nextx = x + dx;
+ int nexty = y + dy;
+ int element = Feld[x][y];
+
+ return (IS_PASSABLE_FROM(element, opposite_dir) &&
+ !CAN_MOVE(element) &&
+ IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
+ IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
+ (level.can_pass_to_walkable || IS_FREE(nextx, nexty)));
+}
+
static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir)
{
int opposite_dir = MV_DIR_OPPOSITE(move_dir);
int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
int newx = x + dx;
int newy = y + dy;
+#if 0
int nextx = newx + dx;
int nexty = newy + dy;
- boolean next_field_must_be_free = TRUE;
+#endif
+#if 1
+ return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
+ (IS_DIGGABLE(Feld[newx][newy]) ||
+ IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
+ canPassField(newx, newy, move_dir)));
+#else
return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
(IS_DIGGABLE(Feld[newx][newy]) ||
IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
!CAN_MOVE(Feld[newx][newy]) &&
IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
- !(next_field_must_be_free && !IS_FREE(nextx, nexty)))));
+ (level.can_pass_to_walkable || IS_FREE(nextx, nexty)))));
+#endif
}
static void CheckGravityMovement(struct PlayerInfo *player)
int jx = player->jx, jy = player->jy;
-
boolean player_is_moving_to_valid_field =
(!player_is_snapping &&
(canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) ||
#endif
#if 1
+
+#if 1
+ boolean player_can_fall_down = canFallDown(player);
+#else
boolean player_can_fall_down =
(IN_LEV_FIELD(jx, jy + 1) &&
(IS_FREE(jx, jy + 1) ||
(Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)));
+#endif
+
#else
boolean player_can_fall_down =
(IN_LEV_FIELD(jx, jy + 1) &&
);
#endif
+#if 0
boolean player_is_standing_on_valid_field =
(IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
(IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN)));
+#endif
#if 0
printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n",
#endif
if (player_can_fall_down &&
+#if 0
!player_is_standing_on_valid_field &&
+#endif
!player_is_moving_to_valid_field)
{
#if 0
#endif
+ /* store if player is automatically moved to next field */
+ player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
+
/* remove the last programmed player action */
player->programmed_action = 0;
if (!ACCESS_FROM(element, opposite_direction))
return MF_NO_ACTION; /* field not accessible from this direction */
+#if 1
+ if (element == EL_EMPTY_SPACE &&
+ game.gravity && !player->is_auto_moving &&
+ canFallDown(player) && move_direction != MV_DOWN)
+ return MF_NO_ACTION; /* player cannot walk here due to gravity */
+#endif
+
if (element >= EL_GATE_1 && element <= EL_GATE_4)
{
if (!player->key[element - EL_GATE_1])
}
else if (IS_PASSABLE(element))
{
- boolean next_field_must_be_free = TRUE;
+#if 1
+ if (!canPassField(x, y, move_direction))
+ return MF_NO_ACTION;
+#else
#if 1
if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) ||
!IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) ||
- (next_field_must_be_free && !IS_FREE(nextx, nexty)))
+ (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty)))
return MF_NO_ACTION;
#else
if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
return MF_NO_ACTION;
#endif
- if (element >= EL_EM_GATE_1 && element <= EL_EM_GATE_4)
+#endif
+
+ if (IS_EM_GATE(element))
{
if (!player->key[element - EL_EM_GATE_1])
return MF_NO_ACTION;
}
- else if (element >= EL_EM_GATE_1_GRAY && element <= EL_EM_GATE_4_GRAY)
+ else if (IS_EM_GATE_GRAY(element))
{
if (!player->key[element - EL_EM_GATE_1_GRAY])
return MF_NO_ACTION;
#define IS_ENVELOPE(e) ((e) >= EL_ENVELOPE_1 && \
(e) <= EL_ENVELOPE_4)
+#define IS_EM_GATE(e) ((e) >= EL_EM_GATE_1 && \
+ (e) <= EL_EM_GATE_4)
+
+#define IS_EM_GATE_GRAY(e) ((e) >= EL_EM_GATE_1_GRAY && \
+ (e) <= EL_EM_GATE_4_GRAY)
+
#define GFX_ELEMENT(e) (element_info[e].use_gfx_element ? \
element_info[e].gfx_element : e)
boolean is_waiting;
boolean is_moving;
+ boolean is_auto_moving;
boolean is_digging;
boolean is_snapping;
boolean is_collecting;
boolean sp_block_last_field; /* player blocks previous field while moving */
boolean use_spring_bug; /* for compatibility with old levels */
boolean instant_relocation; /* no visual delay when relocating player */
+ boolean can_pass_to_walkable; /* player can pass to empty or walkable tile */
/* ('int' instead of 'boolean' because used as selectbox value in editor) */
int use_step_counter; /* count steps instead of seconds for level */