#define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1)
#define USE_NEW_SNAP_DELAY (USE_NEW_STUFF * 1)
#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1)
+#define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1)
+#define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1)
+#define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1)
+#define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1)
+#define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1)
+
#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0)
/* for DigField() */
#define DF_SNAP 2
/* for MovePlayer() */
-#define MF_NO_ACTION 0
-#define MF_MOVING 1
-#define MF_ACTION 2
+#define MP_NO_ACTION 0
+#define MP_MOVING 1
+#define MP_ACTION 2
+#define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION)
/* for ScrollPlayer() */
#define SCROLL_INIT 0
#define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \
RND((c)->delay_random))
+#if 1
+#define GET_VALID_RUNTIME_ELEMENT(e) \
+ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e))
+#else
+#define GET_VALID_FILE_ELEMENT(e) \
+ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e))
+#endif
+
#define GET_TARGET_ELEMENT(e, ch) \
- ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
- (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e))
+ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \
+ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
+ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : (e))
#define CAN_GROW_INTO(e) \
((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
#define SATELLITE_CAN_ENTER_FIELD(x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
+#define ANDROID_CAN_ENTER_FIELD(e, x, y) \
+ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT)
+
+#define ANDROID_CAN_CLONE_FIELD(x, y) \
+ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \
+ CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT)))
+
#define ENEMY_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
#define SPRING_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
+#define SPRING_CAN_BUMP_FROM_FIELD(x, y) \
+ (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \
+ Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
+
+#if 0
#define GROUP_NR(e) ((e) - EL_GROUP_START)
-#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE)
#define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
#define IS_EQUAL_OR_IN_GROUP(e, ge) \
(IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
+#endif
+
+#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
#endif
static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
#define CheckTriggeredElementChange(x, y, e, ev) \
static void InitMagicBallDelay(int, int);
static void ActivateMagicBall(int, int);
+static void InitDiagonalMovingElement(int, int);
+
struct ChangingElementInfo
{
int element;
NULL,
ActivateMagicBall
},
+ {
+ EL_EMC_SPRING_BUMPER_ACTIVE,
+ EL_EMC_SPRING_BUMPER,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_SHRINKING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_GROWING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ InitDiagonalMovingElement
+ },
{
EL_UNDEFINED,
InitPlayfieldScanModeVars();
}
+static int get_move_delay_from_stepsize(int move_stepsize)
+{
+ move_stepsize =
+ MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX);
+
+ /* make sure that stepsize value is always a power of 2 */
+ move_stepsize = (1 << log_2(move_stepsize));
+
+ return TILEX / move_stepsize;
+}
+
+static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize,
+ boolean init_game)
+{
+ int move_delay = get_move_delay_from_stepsize(move_stepsize);
+ boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE);
+
+ /* do no immediately change move delay -- the player might just be moving */
+ player->move_delay_value_next = move_delay;
+
+ /* information if player can move must be set separately */
+ player->cannot_move = cannot_move;
+
+ if (init_game)
+ {
+ player->move_delay = game.initial_move_delay;
+ player->move_delay_value = game.initial_move_delay_value;
+
+ player->move_delay_value_next = -1;
+
+ player->move_delay_reset_counter = 0;
+ }
+}
+
void GetPlayerConfig()
{
if (!audio.sound_available)
DrawGameValue_Keys(stored_player[i].key);
}
+#if 0
static void resolve_group_element(int group_element, int recursion_depth)
{
static int group_nr;
}
}
}
-
+#endif
/*
=============================================================================
printf(" => game.engine_version == %06d\n", game.engine_version);
#endif
+#if 0
/* ---------- recursively resolve group elements ------------------------- */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
resolve_group_element(EL_GROUP_START + i, 0);
+#endif
/* ---------- initialize player's initial move delay --------------------- */
+#if 1
+ /* dynamically adjust player properties according to level information */
+ game.initial_move_delay_value =
+ get_move_delay_from_stepsize(level.initial_player_stepsize);
+#else
/* dynamically adjust player properties according to level information */
game.initial_move_delay_value =
(level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
+#endif
/* dynamically adjust player properties according to game engine version */
game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
player->is_bored = FALSE;
player->is_sleeping = FALSE;
- player->cannot_move = FALSE;
-
player->frame_counter_bored = -1;
player->frame_counter_sleeping = -1;
player->show_envelope = 0;
+#if 1
+ SetPlayerMoveSpeed(player, level.initial_player_stepsize, TRUE);
+#else
player->move_delay = game.initial_move_delay;
player->move_delay_value = game.initial_move_delay_value;
player->move_delay_reset_counter = 0;
+ player->cannot_move = FALSE;
+#endif
+
player->push_delay = -1; /* initialized when pushing starts */
player->push_delay_value = game.initial_push_delay_value;
static void ResetGfxAnimation(int x, int y)
{
+#if 0
+ int element, graphic;
+#endif
+
GfxFrame[x][y] = 0;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MovDir[x][y];
+
+#if 0
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
void InitMovingField(int x, int y, int direction)
{
int element = Feld[x][y];
+#if 0
+ int graphic;
+#endif
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int newx = x + dx;
GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
ACTION_FALLING : ACTION_MOVING);
+#if 0
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
+
/* this is needed for CEs with property "can move" / "not moving" */
if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
{
int direction = MovDir[x][y];
+#if 1
+ int newx = x + (direction & MV_LEFT ? -1 : direction & MV_RIGHT ? +1 : 0);
+ int newy = y + (direction & MV_UP ? -1 : direction & MV_DOWN ? +1 : 0);
+#else
int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+#endif
*goes_to_x = newx;
*goes_to_y = newy;
}
else if (element == EL_SPRING)
{
+#if USE_NEW_SPRING_BUMPER
+ if (MovDir[x][y] & MV_HORIZONTAL)
+ {
+ if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) &&
+ !SPRING_CAN_ENTER_FIELD(element, x, y + 1))
+ {
+ Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE;
+ ResetGfxAnimation(move_x, move_y);
+ DrawLevelField(move_x, move_y);
+
+ MovDir[x][y] = back_dir;
+ }
+ else if (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
+ SPRING_CAN_ENTER_FIELD(element, x, y + 1))
+ MovDir[x][y] = MV_NONE;
+ }
+#else
if (MovDir[x][y] & MV_HORIZONTAL &&
(!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
MovDir[x][y] = MV_NONE;
+#endif
MovDelay[x][y] = 0;
}
else if (element == EL_ROBOT ||
element == EL_SATELLITE ||
- element == EL_PENGUIN)
+ element == EL_PENGUIN ||
+ element == EL_EMC_ANDROID)
{
int attr_x = -1, attr_y = -1;
new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
- if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
return;
MovDir[x][y] =
new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
- if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
return;
MovDir[x][y] = old_move_dir;
return;
}
}
- else /* (element == EL_SATELLITE) */
+ else if (element == EL_SATELLITE)
{
int newx, newy;
return;
}
}
+ else if (element == EL_EMC_ANDROID)
+ {
+ static int check_pos[16] =
+ {
+ -1, /* 0 => (invalid) */
+ 7, /* 1 => MV_LEFT */
+ 3, /* 2 => MV_RIGHT */
+ -1, /* 3 => (invalid) */
+ 1, /* 4 => MV_UP */
+ 0, /* 5 => MV_LEFT | MV_UP */
+ 2, /* 6 => MV_RIGHT | MV_UP */
+ -1, /* 7 => (invalid) */
+ 5, /* 8 => MV_DOWN */
+ 6, /* 9 => MV_LEFT | MV_DOWN */
+ 4, /* 10 => MV_RIGHT | MV_DOWN */
+ -1, /* 11 => (invalid) */
+ -1, /* 12 => (invalid) */
+ -1, /* 13 => (invalid) */
+ -1, /* 14 => (invalid) */
+ -1, /* 15 => (invalid) */
+ };
+ static struct
+ {
+ int dx, dy;
+ int dir;
+ } check_xy[8] =
+ {
+ { -1, -1, MV_LEFT | MV_UP },
+ { 0, -1, MV_UP },
+ { +1, -1, MV_RIGHT | MV_UP },
+ { +1, 0, MV_RIGHT },
+ { +1, +1, MV_RIGHT | MV_DOWN },
+ { 0, +1, MV_DOWN },
+ { -1, +1, MV_LEFT | MV_DOWN },
+ { -1, 0, MV_LEFT },
+ };
+ int start_pos, check_order;
+ boolean can_clone = FALSE;
+ int i;
+
+ /* check if there is any free field around current position */
+ for (i = 0; i < 8; i++)
+ {
+ int newx = x + check_xy[i].dx;
+ int newy = y + check_xy[i].dy;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+
+ if (can_clone) /* randomly find an element to clone */
+ {
+ can_clone = FALSE;
+
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+
+ if (ANDROID_CAN_CLONE_FIELD(newx, newy))
+ {
+ element_info[element].move_leave_type = LEAVE_TYPE_LIMITED;
+ element_info[element].move_leave_element = EL_TRIGGER_ELEMENT;
+
+ Store[x][y] = Feld[newx][newy];
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* randomly find a direction to move */
+ {
+ can_clone = FALSE;
+
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+ int new_move_dir = check_xy[pos].dir;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_clone_time * 8 + 1;
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* cloning and moving successful */
+ return;
+
+ /* cannot clone -- try to move towards player */
+
+ start_pos = check_pos[MovDir[x][y] & 0x0f];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 3; i++)
+ {
+ /* first check start_pos, then previous/next or (next/previous) pos */
+ int pos_raw = start_pos + (i < 2 ? i : -1) * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+ int new_move_dir = check_xy[pos].dir;
+
+ if (IS_PLAYER(newx, newy))
+ break;
+
+ if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ {
+ MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_move_time * 8 + 1;
+
+ break;
+ }
+ }
+ }
}
else if (move_pattern == MV_TURNING_LEFT ||
move_pattern == MV_TURNING_RIGHT ||
static void TurnRound(int x, int y)
{
int direction = MovDir[x][y];
+#if 1
+ int element, graphic;
+#endif
TurnRoundExt(x, y);
GfxFrame[x][y] = 0;
if (MovDelay[x][y])
- GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
+ GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
static boolean JustBeingPushed(int x, int y)
else if (CAN_MOVE_INTO_ACID(element) &&
IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+ !IS_MV_DIAGONAL(MovDir[x][y]) &&
(MovDir[x][y] == MV_DOWN ||
game.engine_version >= VERSION_IDENT(3,1,0,0)))
{
}
else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
{
- if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
+ if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
DrawLevelField(newx, newy);
else
GfxDir[x][y] = MovDir[x][y] = MV_NONE;
return;
}
}
+ else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy))
+ {
+ if (Store[x][y] != EL_EMPTY)
+ {
+ boolean can_clone = FALSE;
+ int xx, yy;
+
+ /* check if element to clone is still there */
+ for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++)
+ {
+ if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y])
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+
+ /* cannot clone or target field not free anymore -- do not clone */
+ if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ Store[x][y] = EL_EMPTY;
+ }
+
+ if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ {
+ if (IS_MV_DIAGONAL(MovDir[x][y]))
+ {
+ int diagonal_move_dir = MovDir[x][y];
+ int stored = Store[x][y];
+ int change_delay = 8;
+ int graphic;
+
+ /* android is moving diagonally */
+
+ CreateField(x, y, EL_DIAGONAL_SHRINKING);
+
+ Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored);
+ GfxElement[x][y] = EL_EMC_ANDROID;
+ GfxAction[x][y] = ACTION_SHRINKING;
+ GfxDir[x][y] = diagonal_move_dir;
+ ChangeDelay[x][y] = change_delay;
+
+ graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
+ GfxDir[x][y]);
+
+ DrawLevelGraphicAnimation(x, y, graphic);
+ PlayLevelSoundAction(x, y, ACTION_SHRINKING);
+
+ if (Feld[newx][newy] == EL_ACID)
+ {
+ SplashAcid(newx, newy);
+
+ return;
+ }
+
+ CreateField(newx, newy, EL_DIAGONAL_GROWING);
+
+ Store[newx][newy] = EL_EMC_ANDROID;
+ GfxElement[newx][newy] = EL_EMC_ANDROID;
+ GfxAction[newx][newy] = ACTION_GROWING;
+ GfxDir[newx][newy] = diagonal_move_dir;
+ ChangeDelay[newx][newy] = change_delay;
+
+ graphic = el_act_dir2img(GfxElement[newx][newy],
+ GfxAction[newx][newy], GfxDir[newx][newy]);
+
+ DrawLevelGraphicAnimation(newx, newy, graphic);
+ PlayLevelSoundAction(newx, newy, ACTION_GROWING);
+
+ return;
+ }
+ else
+ {
+ Feld[newx][newy] = EL_EMPTY;
+ DrawLevelField(newx, newy);
+
+ PlayLevelSoundAction(x, y, ACTION_DIGGING);
+ }
+ }
+ else if (!IS_FREE(newx, newy))
+ {
+#if 0
+ if (IS_PLAYER(x, y))
+ DrawPlayerField(x, y);
+ else
+ DrawLevelField(x, y);
+#endif
+
+ return;
+ }
+ }
else if (IS_CUSTOM_ELEMENT(element) &&
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
{
Pushed[x][y] = Pushed[newx][newy] = FALSE;
/* some elements can leave other elements behind after moving */
+#if 1
+ if (ei->move_leave_element != EL_EMPTY &&
+ (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
+ (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#else
if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
(ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
(!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#endif
{
int move_leave_element = ei->move_leave_element;
+#if 1
#if 1
+ /* this makes it possible to leave the removed element again */
+ if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+ move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored);
+#else
/* this makes it possible to leave the removed element again */
if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
move_leave_element = stored;
+#endif
#else
/* this makes it possible to leave the removed element again */
if (ei->move_leave_type == LEAVE_TYPE_LIMITED &&
player->index_bit, push_side);
}
+ if (element == EL_EMC_ANDROID && pushed_by_player) /* make another move */
+ MovDelay[newx][newy] = 1;
+
CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction);
TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+#if 0
+ if (ChangePage[newx][newy] != -1) /* delayed change */
+ {
+ int page = ChangePage[newx][newy];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+
+ ChangePage[newx][newy] = -1;
+
+ if (change->can_change)
+ {
+ if (ChangeElement(newx, newy, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(newx, newy);
+ }
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(newx, newy, element, page);
+ }
+#endif
+
TestIfElementHitsCustomElement(newx, newy, direction);
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
int element = Feld[ax][ay];
int graphic = el2img(element);
int newax = ax, neway = ay;
+ boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER);
static int xy[4][2] =
{
{ 0, -1 },
{ 0, +1 }
};
- if (!level.amoeba_speed)
+ if (!level.amoeba_speed && element != EL_EMC_DRIPPER)
{
Feld[ax][ay] = EL_AMOEBA_DEAD;
DrawLevelField(ax, ay);
return;
}
- if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
+ if (can_drop) /* EL_AMOEBA_WET or EL_EMC_DRIPPER */
{
int start = RND(4);
int x = ax + xy[start][0];
}
}
- if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
+ if (!can_drop || neway < ay || !IS_FREE(newax, neway) ||
(neway == lev_fieldy - 1 && newax != ax))
{
Feld[newax][neway] = EL_AMOEBA_GROWING; /* creation of new amoeba */
Store[newax][neway] = element;
}
- else if (neway == ay)
+ else if (neway == ay || element == EL_EMC_DRIPPER)
{
Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */
game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents;
}
+static void InitDiagonalMovingElement(int x, int y)
+{
+#if 0
+ MovDelay[x][y] = level.android_move_time;
+#endif
+}
+
void CheckExit(int x, int y)
{
if (local_player->gems_still_needed > 0 ||
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0], yy = y + xy[i][1];
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
- if (IS_PLAYER(xx, yy))
+ if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
{
PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
MV_NONE);
int action_arg_number_min =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN :
+ (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING :
CA_ARG_MIN);
int action_arg_number_max =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX :
+ (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER :
action_type == CA_SET_LEVEL_GEMS ? 999 :
action_type == CA_SET_LEVEL_TIME ? 9999 :
action_type == CA_SET_LEVEL_SCORE ? 99999 :
CA_ARG_MAX);
int action_arg_number_reset =
- (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value :
+ (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize :
action_type == CA_SET_LEVEL_GEMS ? level.gems_needed :
action_type == CA_SET_LEVEL_TIME ? level.time :
action_type == CA_SET_LEVEL_SCORE ? 0 :
action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
- action_arg == CA_ARG_ELEMENT_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
- action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_ce_value :
+ action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
+ action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
+ action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element :
+ action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element :
-1);
int action_arg_number_old =
{
int move_stepsize = TILEX / stored_player[i].move_delay_value;
- if (action_arg == CA_ARG_SPEED_SLOWER ||
- action_arg == CA_ARG_SPEED_FASTER)
+ if (action_arg == CA_ARG_SPEED_FASTER &&
+ stored_player[i].cannot_move)
+ {
+ action_arg_number = STEPSIZE_VERY_SLOW;
+ }
+ else if (action_arg == CA_ARG_SPEED_SLOWER ||
+ action_arg == CA_ARG_SPEED_FASTER)
{
action_arg_number = 2;
action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE :
action_arg_number_min,
action_arg_number_max);
+#if 1
+ SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE);
+#else
/* make sure that value is power of 2 */
move_stepsize = (1 << log_2(move_stepsize));
stored_player[i].cannot_move =
(action_arg == CA_ARG_SPEED_NOT_MOVING ? TRUE : FALSE);
+#endif
}
}
CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
+#if 0
+ printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
+#endif
}
#endif
static void CreateElementFromChange(int x, int y, int element)
{
+ element = GET_VALID_RUNTIME_ELEMENT(element);
+
+#if USE_STOP_CHANGED_ELEMENTS
+ if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+ {
+ int old_element = Feld[x][y];
+
+ /* prevent changed element from moving in same engine frame
+ unless both old and new element can either fall or move */
+ if ((!CAN_FALL(old_element) || !CAN_FALL(element)) &&
+ (!CAN_MOVE(old_element) || !CAN_MOVE(element)))
+ Stop[x][y] = TRUE;
+ }
+#endif
+
CreateFieldExt(x, y, element, TRUE);
}
{
target_element = GET_TARGET_ELEMENT(change->target_element, change);
+ if (element == EL_DIAGONAL_GROWING ||
+ element == EL_DIAGONAL_SHRINKING)
+ {
+ target_element = Store[x][y];
+
+ Store[x][y] = EL_EMPTY;
+ }
+
CreateElementFromChange(x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
element = Feld[x][y];
}
- if (Feld[x][y] != element) /* check if element has already changed */
+#if 0
+ /* check if element has already changed */
+ if (Feld[x][y] != element)
return FALSE;
+#else
+ /* check if element has already changed or is about to change after moving */
+ if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
+ Feld[x][y] != element) ||
+
+ (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+ (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+ ChangePage[x][y] != -1)))
+ return FALSE;
+#endif
for (p = 0; p < element_info[element].num_change_pages; p++)
{
/* ---------- main game synchronization point ---------- */
+ WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
+
InitPlayfieldScanModeVars();
- WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
+#if USE_ONE_MORE_CHANGE_PER_FRAME
+ if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+ {
+ SCAN_PLAYFIELD(x, y)
+ {
+ ChangeCount[x][y] = 0;
+ ChangeEvent[x][y] = -1;
+ }
+ }
+#endif
if (network_playing && !network_player_action_received)
{
GfxFrame[x][y]++;
/* reset finished pushing action (not done in ContinueMoving() to allow
- continous pushing animation for elements with zero push delay) */
+ continuous pushing animation for elements with zero push delay) */
if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
{
ResetGfxAnimation(x, y);
CheckForDragon(x, y);
else if (element == EL_EXPLOSION)
; /* drawing of correct explosion animation is handled separately */
- else if (element == EL_ELEMENT_SNAPPING)
+ else if (element == EL_ELEMENT_SNAPPING ||
+ element == EL_DIAGONAL_SHRINKING ||
+ element == EL_DIAGONAL_GROWING)
{
#if 1
graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]);
{
int jx = player->jx, jy = player->jy;
int new_jx = jx + dx, new_jy = jy + dy;
+#if !USE_FIXED_DONT_RUN_INTO
int element;
+#endif
int can_move;
+ boolean player_can_move = !player->cannot_move;
if (!player->active || (!dx && !dy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
player->MovDir = (dx < 0 ? MV_LEFT :
dx > 0 ? MV_RIGHT :
dy > 0 ? MV_DOWN : MV_NONE);
if (!IN_LEV_FIELD(new_jx, new_jy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
- if (player->cannot_move)
+ if (!player_can_move)
{
#if 1
if (player->MovPos == 0)
SnapField(player, 0, 0);
#endif
- return MF_NO_ACTION;
+#if 0
+ return MP_NO_ACTION;
+#endif
}
if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+#if !USE_FIXED_DONT_RUN_INTO
element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
- if (DONT_RUN_INTO(element))
+ /* (moved to DigField()) */
+ if (player_can_move && DONT_RUN_INTO(element))
{
if (element == EL_ACID && dx == 0 && dy == 1)
{
else
TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
- return MF_MOVING;
+ return MP_MOVING;
}
+#endif
can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
- if (can_move != MF_MOVING)
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+ if (can_move == MP_DONT_RUN_INTO)
+ return MP_MOVING;
+#endif
+#endif
+ if (can_move != MP_MOVING)
return can_move;
+#if USE_FIXED_DONT_RUN_INTO
+#endif
+
/* check if DigField() has caused relocation of the player */
if (player->jx != jx || player->jy != jy)
- return MF_NO_ACTION; /* <-- !!! CHECK THIS [-> MF_ACTION ?] !!! */
+ return MP_NO_ACTION; /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
ScrollPlayer(player, SCROLL_INIT);
- return MF_MOVING;
+ return MP_MOVING;
}
boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
{
int jx = player->jx, jy = player->jy;
int old_jx = jx, old_jy = jy;
- int moved = MF_NO_ACTION;
+ int moved = MP_NO_ACTION;
if (!player->active)
return FALSE;
jx = player->jx;
jy = player->jy;
- if (moved & MF_MOVING && !ScreenMovPos &&
+ if (moved & MP_MOVING && !ScreenMovPos &&
(player == local_player || !options.network))
{
int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
player->StepFrame = 0;
- if (moved & MF_MOVING)
+ if (moved & MP_MOVING)
{
if (old_jx != jx && old_jy == jy)
player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
}
}
+#if USE_ELEMENT_TOUCHING_BUGFIX
+
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 = Feld[x][y]; /* should always be non-moving! */
+ int border_element_old[NUM_DIRECTIONS];
+ int i;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_element;
+
+ border_element_old[i] = -1;
+
+ 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 */
+
+ border_element_old[i] = border_element;
+ }
+
+ 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_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of border element */
+ CheckElementChangeBySide(xx, yy, border_element, center_element,
+ CE_TOUCHING_X, center_side);
+ }
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int border_side = trigger_sides[i][1];
+ int border_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of center element (but change it only once) */
+ if (!change_center_element)
+ change_center_element =
+ CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_TOUCHING_X, border_side);
+ }
+}
+
+#else
+
+void TestIfElementTouchesCustomElement_OLD(int x, int y)
{
static int xy[4][2] =
{
}
}
+#endif
+
void TestIfElementHitsCustomElement(int x, int y, int direction)
{
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
{
int i, kill_x = -1, kill_y = -1;
+
int bad_element = -1;
static int test_xy[4][2] =
{
static void setFieldForSnapping(int x, int y, int element, int direction)
{
struct ElementInfo *ei = &element_info[element];
- int direction_bit = MV_DIR_BIT(direction);
+ int direction_bit = MV_DIR_TO_BIT(direction);
int graphic_snapping = ei->direction_graphic[ACTION_SNAPPING][direction_bit];
int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING :
IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING);
{
boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
boolean player_was_pushing = player->is_pushing;
+ boolean player_can_move = (!player->cannot_move && mode != DF_SNAP);
+ boolean player_can_move_or_snap = (!player->cannot_move || mode == DF_SNAP);
int jx = oldx, jy = oldy;
int dx = x - jx, dy = y - jy;
int nextx = x + dx, nexty = y + dy;
int opposite_direction = MV_DIR_OPPOSITE(move_direction);
int dig_side = MV_DIR_OPPOSITE(move_direction);
int old_element = Feld[jx][jy];
+#if USE_FIXED_DONT_RUN_INTO
+ int element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+#else
int element;
+#endif
int collect_count;
if (is_player) /* function can also be called by EL_PENGUIN */
player->is_switching = FALSE;
player->push_delay = -1;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
}
+#if !USE_FIXED_DONT_RUN_INTO
if (IS_MOVING(x, y) || IS_PLAYER(x, y))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+#endif
if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ if (element == EL_ACID && dx == 0 && dy == 1)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
+ }
+ else
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
+#if 1
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
- return MF_NO_ACTION; /* field has no opening in this direction */
+ return MP_NO_ACTION; /* field has no opening in this direction */
if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
- return MF_NO_ACTION; /* field has no opening in this direction */
-
- element = Feld[x][y];
-#if USE_NEW_CUSTOM_VALUE
+ return MP_NO_ACTION; /* field has no opening in this direction */
#if 1
- collect_count = element_info[element].collect_count_initial;
-#else
- collect_count = CustomValue[x][y];
-#endif
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
-#else
- collect_count = element_info[element].collect_count_initial;
+ return MP_DONT_RUN_INTO;
+ }
+#endif
#endif
#if 0
- if (element != EL_BLOCKED &&
- CustomValue[x][y] != element_info[element].collect_count_initial)
- printf("::: %d: %d != %d\n",
- element,
- CustomValue[x][y],
- element_info[element].collect_count_initial);
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ if (element == EL_ACID && dx == 0 && dy == 1)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
+ }
+ else
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
+#if USE_FIXED_DONT_RUN_INTO
+ if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+ return MP_NO_ACTION;
#endif
+#if !USE_FIXED_DONT_RUN_INTO
+ element = Feld[x][y];
+#endif
+
+ collect_count = element_info[element].collect_count_initial;
+
if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+
+ if (game.engine_version < VERSION_IDENT(2,2,0,0))
+ player_can_move = player_can_move_or_snap;
if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
game.engine_version >= VERSION_IDENT(2,2,0,0))
player->index_bit, dig_side);
if (Feld[x][y] != element) /* field changed by snapping */
- return MF_ACTION;
+ return MP_ACTION;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
if (game.gravity && is_player && !player->is_auto_moving &&
canFallDown(player) && move_direction != MV_DOWN &&
!canMoveToValidFieldWithGravity(jx, jy, move_direction))
- return MF_NO_ACTION; /* player cannot walk here due to gravity */
+ return MP_NO_ACTION; /* player cannot walk here due to gravity */
- if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
+ if (player_can_move &&
+ IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
{
int sound_element = SND_ELEMENT(element);
int sound_action = ACTION_WALKING;
if (IS_RND_GATE(element))
{
if (!player->key[RND_GATE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_RND_GATE_GRAY(element))
{
if (!player->key[RND_GATE_GRAY_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_RND_GATE_GRAY_ACTIVE(element))
{
if (!player->key[RND_GATE_GRAY_ACTIVE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (element == EL_EXIT_OPEN ||
element == EL_SP_EXIT_OPEN ||
else
PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action);
}
- else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
+ else if (player_can_move &&
+ IS_PASSABLE(element) && canPassField(x, y, move_direction))
{
if (!ACCESS_FROM(element, opposite_direction))
- return MF_NO_ACTION; /* field not accessible from this direction */
+ return MP_NO_ACTION; /* field not accessible from this direction */
if (CAN_MOVE(element)) /* only fixed elements can be passed! */
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (IS_EM_GATE(element))
{
if (!player->key[EM_GATE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_EM_GATE_GRAY(element))
{
if (!player->key[EM_GATE_GRAY_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_EM_GATE_GRAY_ACTIVE(element))
{
if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_SP_PORT(element))
{
PlayLevelSoundAction(x, y, ACTION_PASSING);
}
- else if (IS_DIGGABLE(element))
+ else if (player_can_move_or_snap && IS_DIGGABLE(element))
{
RemoveField(x, y);
player->index_bit, dig_side);
}
}
- else if (IS_COLLECTIBLE(element))
+ else if (player_can_move_or_snap && IS_COLLECTIBLE(element))
{
RemoveField(x, y);
player->index_bit, dig_side);
}
}
- else if (IS_PUSHABLE(element))
+ else if (player_can_move_or_snap && IS_PUSHABLE(element))
{
if (mode == DF_SNAP && element != EL_BD_ROCK)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_FALL(element) && dy)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
!(element == EL_SPRING && level.use_spring_bug))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
((move_direction & MV_VERTICAL &&
IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
(element_info[element].move_pattern & MV_DOWN &&
IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
/* do not push elements already moving away faster than player */
if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (game.engine_version >= VERSION_IDENT(3,1,0,0))
{
(IS_FREE(nextx, nexty) ||
(Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
IS_SB_ELEMENT(element)))))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (player->push_delay == -1) /* new pushing; restart delay */
player->push_delay = 0;
if (game.engine_version >= VERSION_IDENT(3,0,7,1))
player->move_delay = 0;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
if (IS_SB_ELEMENT(element))
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_ACTION;
+ return MP_ACTION;
}
player->is_switching = TRUE;
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_ACTION;
+ return MP_ACTION;
}
else
{
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
player->push_delay = -1;
player->is_collecting = !player->is_digging;
}
- return MF_MOVING;
+ return MP_MOVING;
}
boolean SnapField(struct PlayerInfo *player, int dx, int dy)
player->is_dropping = FALSE;
- if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
+ if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION)
return FALSE;
player->is_snapping = TRUE;
element can be dropped (this is especially important if the next element
is dynamite, which can be placed on background for historical reasons) */
if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY)
- return MF_ACTION;
+ return MP_ACTION;
if (IS_THROWABLE(drop_element))
{
break;
case SAMPLE_slurp:
- PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_SLURPING);
break;
case SAMPLE_eater: