#define USE_NEW_AMOEBA_CODE FALSE
/* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF TRUE * 1
+#define USE_NEW_STUFF (TRUE * 1)
-#define USE_NEW_MOVE_STYLE TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_MOVE_DELAY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_PUSH_DELAY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_BLOCK_STYLE TRUE * USE_NEW_STUFF * 1 * 1
-#define USE_NEW_SP_SLIPPERY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_RANDOMIZE TRUE * USE_NEW_STUFF * 1
+#define USE_NEW_MOVE_STYLE (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_MOVE_DELAY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_PUSH_DELAY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_BLOCK_STYLE (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_SP_SLIPPERY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_RANDOMIZE (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_CAN_MOVE_NOT_MOVING (TRUE * USE_NEW_STUFF * 1)
+#define USE_PREVIOUS_MOVE_DIR (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_PUSH_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+#if 0
+#define USE_BLOCK_DELAY_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+#endif
+#define USE_GRAVITY_BUGFIX_NEW (TRUE * USE_NEW_STUFF * 1)
+#define USE_GRAVITY_BUGFIX_OLD (TRUE * USE_NEW_STUFF * 0)
+
+#define USE_PENGUIN_COLLECT_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_IMPACT_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_HITTING_SOMETHING_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+#define USE_HIT_BY_SOMETHING_BUGFIX (TRUE * USE_NEW_STUFF * 1)
-#define USE_PUSH_BUGFIX TRUE * USE_NEW_STUFF * 1
/* for DigField() */
#define DF_NO_PUSH 0
{ EL_UNDEFINED, MV_NO_MOVING }
};
-static unsigned long trigger_events[MAX_NUM_ELEMENTS];
+static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
-#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \
- CH_EVENT_BIT(CE_DELAY))
+#define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY])
#define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
#define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \
IS_JUST_CHANGING(x, y))
level.block_last_field);
#if USE_NEW_BLOCK_STYLE
+#if 1
+
+ /* ---------- initialize player's last field block delay --------------- */
+
+ /* always start with reliable default value (no adjustment needed) */
+ player->block_delay_adjustment = 0;
+
+ /* special case 1: in Supaplex, Murphy blocks last field one more frame */
+ if (player->block_last_field && element == EL_SP_MURPHY)
+ player->block_delay_adjustment = 1;
+
+ /* special case 2: in game engines before 3.1.1, blocking was different */
+ if (game.use_block_last_field_bug)
+ player->block_delay_adjustment = (player->block_last_field ? -1 : 1);
+
+#if 0
+ /* blocking the last field when moving was corrected in version 3.1.1 */
+ if (game.use_block_last_field_bug)
+ {
+ /* even "not blocking" was blocking the last field for one frame */
+ level.block_delay = (level.block_last_field ? 7 : 1);
+ level.sp_block_delay = (level.sp_block_last_field ? 7 : 1);
+
+ level.block_last_field = TRUE;
+ level.sp_block_last_field = TRUE;
+ }
+#endif
+
+#if 0 /* !!! THIS IS NOT A LEVEL SETTING => REMOVED !!! */
+ level.block_delay = 8; /* when blocking, block 8 frames */
+ level.sp_block_delay = 9; /* SP indeed blocks 9 frames, not 8 */
+#endif
+
+#if 0
+ printf("::: %d, %d\n", level.block_delay, level.sp_block_delay);
+#endif
+
+#else
+
#if 1
player->block_delay = (player->block_last_field ?
(element == EL_SP_MURPHY ?
(player->block_last_field ? 7 : 1));
#endif
+#endif
+
#if 0
printf("::: block_last_field == %d, block_delay = %d\n",
player->block_last_field, player->block_delay);
DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
}
-inline void DrawGameValue_Keys(struct PlayerInfo *player)
+inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS])
{
int i;
- for (i = 0; i < MAX_KEYS; i++)
- if (player->key[i])
+ /* currently only 4 of 8 possible keys are displayed */
+ for (i = 0; i < STD_NUM_KEYS; i++)
+ if (key[i])
DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
el2edimg(EL_KEY_1 + i));
}
}
}
-void DrawGameDoorValues()
+void DrawAllGameValues(int emeralds, int dynamite, int score, int time,
+ int key_bits)
{
+ int key[MAX_NUM_KEYS];
int i;
+ for (i = 0; i < MAX_NUM_KEYS; i++)
+ key[i] = key_bits & (1 << i);
+
DrawGameValue_Level(level_nr);
- for (i = 0; i < MAX_PLAYERS; i++)
- DrawGameValue_Keys(&stored_player[i]);
+ DrawGameValue_Emeralds(emeralds);
+ DrawGameValue_Dynamite(dynamite);
+ DrawGameValue_Score(score);
+ DrawGameValue_Time(time);
+
+ DrawGameValue_Keys(key);
+}
+
+void DrawGameDoorValues()
+{
+ int i;
+
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ {
+ DrawGameDoorValues_EM();
+
+ return;
+ }
+
+ DrawGameValue_Level(level_nr);
DrawGameValue_Emeralds(local_player->gems_still_needed);
DrawGameValue_Dynamite(local_player->inventory_size);
DrawGameValue_Score(local_player->score);
DrawGameValue_Time(TimeLeft);
-}
-void DrawGameDoorValues_EM(int emeralds, int dynamite, int score, int time)
-{
- DrawGameValue_Emeralds(emeralds);
- DrawGameValue_Dynamite(dynamite);
- DrawGameValue_Score(score);
- DrawGameValue_Time(time);
+ for (i = 0; i < MAX_PLAYERS; i++)
+ DrawGameValue_Keys(stored_player[i].key);
}
static void resolve_group_element(int group_element, int recursion_depth)
static void InitGameEngine()
{
- int i, j, k;
+ int i, j, k, l;
/* set game engine from tape file when re-playing, else from level file */
game.engine_version = (tape.playing ? tape.engine_version :
/* ---------------------------------------------------------------------- */
/*
- Type of bug/change:
+ Summary of bugfix/change:
+ Fixed handling for custom elements that change when pushed by the player.
+
+ Fixed/changed in version:
+ 3.1.0
+
+ Description:
Before 3.1.0, custom elements that "change when pushing" changed directly
after the player started pushing them (until then handled in "DigField()").
Since 3.1.0, these custom elements are not changed until the "pushing"
Machine" by Juergen Bonhagen.
*/
- game.use_bug_change_when_pushing =
+ game.use_change_when_pushing_bug =
(game.engine_version < VERSION_IDENT(3,1,0,0) &&
!(tape.playing &&
tape.game_version >= VERSION_IDENT(3,1,0,0) &&
tape.game_version < VERSION_IDENT(3,1,1,0)));
+ /*
+ Summary of bugfix/change:
+ Fixed handling for blocking the field the player leaves when moving.
+
+ Fixed/changed in version:
+ 3.1.1
+
+ Description:
+ Before 3.1.1, when "block last field when moving" was enabled, the field
+ the player is leaving when moving was blocked for the time of the move,
+ and was directly unblocked afterwards. This resulted in the last field
+ being blocked for exactly one less than the number of frames of one player
+ move. Additionally, even when blocking was disabled, the last field was
+ blocked for exactly one frame.
+ Since 3.1.1, due to changes in player movement handling, the last field
+ is not blocked at all when blocking is disabled. When blocking is enabled,
+ the last field is blocked for exactly the number of frames of one player
+ move. Additionally, if the player is Murphy, the hero of Supaplex, the
+ last field is blocked for exactly one more than the number of frames of
+ one player move.
+
+ Affected levels/tapes:
+ (!!! yet to be determined -- probably many !!!)
+ */
+
+ game.use_block_last_field_bug =
+ (game.engine_version < VERSION_IDENT(3,1,1,0));
+
/* ---------------------------------------------------------------------- */
/* dynamically adjust element properties according to game engine version */
ei->change->delay_frames = 1;
}
- ei->change_events = CE_BITMASK_DEFAULT;
for (j = 0; j < NUM_CHANGE_EVENTS; j++)
{
+ ei->has_change_event[j] = FALSE;
+
ei->event_page_nr[j] = 0;
ei->event_page[j] = &ei->change_page[0];
}
ei->change->change_function = ch_delay->change_function;
ei->change->post_change_function = ch_delay->post_change_function;
- ei->change_events |= CH_EVENT_BIT(CE_DELAY);
+ ei->has_change_event[CE_DELAY] = TRUE;
#if 1
SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
for (k = 0; k < NUM_CHANGE_EVENTS; k++)
{
/* only add event page for the first page found with this event */
- if (ei->change_page[j].events & CH_EVENT_BIT(k) &&
- !(ei->change_events & CH_EVENT_BIT(k)))
+ if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k]))
{
- ei->change_events |= CH_EVENT_BIT(k);
+ ei->has_change_event[k] = TRUE;
+
ei->event_page_nr[k] = j;
ei->event_page[k] = &ei->change_page[j];
}
/* only add custom elements that change after fixed/random frame delay */
if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
- element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY);
+ element_info[element].has_change_event[CE_DELAY] = TRUE;
}
#endif
/* initialize trigger events information */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
- trigger_events[i] = EP_BITMASK_DEFAULT;
+ for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+ trigger_events[i][j] = FALSE;
#if 1
/* add trigger events from element change event properties */
if (!ei->change_page[j].can_change)
continue;
- if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
+ if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION])
{
int trigger_element = ei->change_page[j].trigger_element;
- if (IS_GROUP_ELEMENT(trigger_element))
+ for (k = 0; k < NUM_CHANGE_EVENTS; k++)
{
- struct ElementGroupInfo *group = element_info[trigger_element].group;
+ if (ei->change_page[j].has_event[k])
+ {
+ if (IS_GROUP_ELEMENT(trigger_element))
+ {
+ struct ElementGroupInfo *group =
+ element_info[trigger_element].group;
- for (k = 0; k < group->num_elements_resolved; k++)
- trigger_events[group->element_resolved[k]]
- |= ei->change_page[j].events;
+ for (l = 0; l < group->num_elements_resolved; l++)
+ trigger_events[group->element_resolved[l]][k] = TRUE;
+ }
+ else
+ trigger_events[trigger_element][k] = TRUE;
+ }
}
- else
- trigger_events[trigger_element] |= ei->change_page[j].events;
}
}
}
/* add trigger events from element change event properties */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
- trigger_events[element_info[i].change->trigger_element] |=
- element_info[i].change->events;
+ for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+ if (element_info[i].change->has_event[j])
+ trigger_events[element_info[i].change->trigger_element][j] = TRUE;
#endif
/* ---------- initialize push delay -------------------------------------- */
player->lights_still_needed = 0;
player->friends_still_needed = 0;
- for (j = 0; j < MAX_KEYS; j++)
+ for (j = 0; j < MAX_NUM_KEYS; j++)
player->key[j] = FALSE;
player->dynabomb_count = 0;
player->use_murphy_graphic = FALSE;
player->block_last_field = FALSE; /* initialized in InitPlayerField() */
- player->block_delay = -1; /* initialized in InitPlayerField() */
+ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */
player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
#endif
ZX = ZY = -1;
+ ExitX = ExitY = -1;
FrameCounter = 0;
TimeFrames = 0;
Stop[x][y] = FALSE;
Pushed[x][y] = FALSE;
- Changed[x][y] = CE_BITMASK_DEFAULT;
- ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+ Changed[x][y] = FALSE;
+ ChangeEvent[x][y] = -1;
ExplodePhase[x][y] = 0;
ExplodeDelay[x][y] = 0;
#endif
#if USE_NEW_BLOCK_STYLE
- player->block_last_field = some_player->block_last_field;
- player->block_delay = some_player->block_delay;
+ player->block_last_field = some_player->block_last_field;
+ player->block_delay_adjustment = some_player->block_delay_adjustment;
#endif
StorePlayer[jx][jy] = player->element_nr;
#endif
}
+void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y)
+{
+ /* this is used for non-R'n'D game engines to update certain engine values */
+
+ /* needed to determine if sounds are played within the visible screen area */
+ scroll_x = actual_scroll_x;
+ scroll_y = actual_scroll_y;
+}
+
void InitMovDir(int x, int y)
{
int i, element = Feld[x][y];
}
/* close exit door after last player */
- if ((Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
- Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN) && AllPlayersGone)
+ if (AllPlayersGone && ExitX >= 0 && ExitY >= 0 &&
+ (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
+ Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN))
{
int element = Feld[ExitX][ExitY];
}
/* Hero disappears */
- DrawLevelField(ExitX, ExitY);
+ if (ExitX >= 0 && ExitY >= 0)
+ DrawLevelField(ExitX, ExitY);
+
BackToFront();
if (tape.playing)
return position;
}
+inline static int getElementMoveStepsize(int x, int y)
+{
+ int element = Feld[x][y];
+ int direction = MovDir[x][y];
+ int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+ int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+ int horiz_move = (dx != 0);
+ int sign = (horiz_move ? dx : dy);
+ int step = sign * element_info[element].move_stepsize;
+
+ /* special values for move stepsize for spring and things on conveyor belt */
+ if (horiz_move)
+ {
+#if 0
+ if (element == EL_SPRING)
+ step = sign * MOVE_STEPSIZE_NORMAL * 2;
+ else if (CAN_FALL(element) && !CAN_MOVE(element) &&
+ y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+ step = sign * MOVE_STEPSIZE_NORMAL / 2;
+#else
+ if (CAN_FALL(element) &&
+ y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+ step = sign * MOVE_STEPSIZE_NORMAL / 2;
+ else if (element == EL_SPRING)
+ step = sign * MOVE_STEPSIZE_NORMAL * 2;
+#endif
+ }
+
+ return step;
+}
+
void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
{
if (player->GfxAction != action || player->GfxDir != dir)
if (!WasJustMoving[x][y] || direction != MovDir[x][y])
ResetGfxAnimation(x, y);
+#if USE_CAN_MOVE_NOT_MOVING
+
+ MovDir[x][y] = direction;
+ GfxDir[x][y] = direction;
+ GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
+ ACTION_FALLING : ACTION_MOVING);
+
+ if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
+ {
+ if (Feld[newx][newy] == EL_EMPTY)
+ Feld[newx][newy] = EL_BLOCKED;
+
+ MovDir[newx][newy] = MovDir[x][y];
+ GfxFrame[newx][newy] = GfxFrame[x][y];
+ GfxRandom[newx][newy] = GfxRandom[x][y];
+ GfxAction[newx][newy] = GfxAction[x][y];
+ GfxDir[newx][newy] = GfxDir[x][y];
+ }
+
+#else
+
MovDir[newx][newy] = MovDir[x][y] = direction;
GfxDir[x][y] = direction;
GfxRandom[newx][newy] = GfxRandom[x][y];
GfxAction[newx][newy] = GfxAction[x][y];
GfxDir[newx][newy] = GfxDir[x][y];
+#endif
}
void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
player->index_bit, leave_side);
CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
- CE_OTHER_GETS_LEFT,
+ CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
#endif
player->index_bit, enter_side);
CheckTriggeredElementChangeByPlayer(jx, jy, element,
- CE_OTHER_GETS_ENTERED,
+ CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
#endif
}
return;
#endif
+#if 1
+ if (mode == EX_TYPE_NORMAL ||
+ mode == EX_TYPE_CENTER ||
+ mode == EX_TYPE_CROSS)
+ PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
+#else
if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
+#endif
/* remove things displayed in background while burning dynamite */
if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
continue;
#endif
-#if 1
+ /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy
+ behaviour, for example when touching a yamyam that explodes to rocks
+ with active deadly shield, a rock is created under the player !!! */
+ /* (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) */
+#if 0
if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
(game.engine_version < VERSION_IDENT(3,1,0,0) ||
(x == ex && y == ey && mode != EX_TYPE_BORDER)))
break;
}
- CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING);
+ CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X);
}
void SplashAcid(int x, int y)
Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
DrawLevelField(x, y);
+
+ /* uncrumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
}
else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
element == EL_INVISIBLE_WALL_ACTIVE ||
Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
DrawLevelField(x, y);
+
+ /* re-crumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
}
}
}
Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
}
-inline static int getElementMoveStepsize(int x, int y)
-{
- int element = Feld[x][y];
- int direction = MovDir[x][y];
- int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
- int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
- int horiz_move = (dx != 0);
- int sign = (horiz_move ? dx : dy);
- int step = sign * element_info[element].move_stepsize;
-
- /* special values for move stepsize for spring and things on conveyor belt */
- if (horiz_move)
- {
-#if 0
- if (element == EL_SPRING)
- step = sign * MOVE_STEPSIZE_NORMAL * 2;
- else if (CAN_FALL(element) && !CAN_MOVE(element) &&
- y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
- step = sign * MOVE_STEPSIZE_NORMAL / 2;
-#else
- if (CAN_FALL(element) &&
- y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
- step = sign * MOVE_STEPSIZE_NORMAL / 2;
- else if (element == EL_SPRING)
- step = sign * MOVE_STEPSIZE_NORMAL * 2;
-#endif
- }
-
- return step;
-}
-
void Impact(int x, int y)
{
boolean lastline = (y == lev_fieldy-1);
int element = Feld[x][y];
int smashed = EL_STEELWALL;
+#if 0
+ printf("IMPACT!\n");
+#endif
+
if (!lastline) /* check if element below was hit */
{
if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
CheckElementChangeBySide(x, y + 1, smashed, element,
CE_SWITCHED, CH_SIDE_TOP);
CheckTriggeredElementChangeBySide(x, y + 1, smashed,
- CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
+ CE_SWITCH_OF_X, CH_SIDE_TOP);
#else
CheckTriggeredElementChangeBySide(x, y + 1, smashed,
- CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
+ CE_SWITCH_OF_X, CH_SIDE_TOP);
CheckElementChangeBySide(x, y + 1, smashed, element,
CE_SWITCHED, CH_SIDE_TOP);
#endif
boolean can_turn_right =
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+#if USE_CAN_MOVE_NOT_MOVING
+ if (element_info[element].move_stepsize == 0) /* not moving */
+ return;
+#endif
+
if (move_pattern == MV_TURNING_LEFT)
MovDir[x][y] = left_dir;
else if (move_pattern == MV_TURNING_RIGHT)
boolean first_horiz = RND(2);
int new_move_dir = MovDir[x][y];
+#if USE_CAN_MOVE_NOT_MOVING
+ if (element_info[element].move_stepsize == 0) /* not moving */
+ {
+ first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y));
+ MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+
+ return;
+ }
+#endif
+
MovDir[x][y] =
new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
+#if USE_IMPACT_BUGFIX
+ (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
+ CAN_FALL(element) && WasJustFalling[x][y] &&
+ (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
+
+ (game.engine_version < VERSION_IDENT(2,2,0,7) &&
+ CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
+ (Feld[x][y + 1] == EL_BLOCKED)))
+#else
(game.engine_version >= VERSION_IDENT(3,0,7,0) &&
CAN_SMASH(element) && WasJustFalling[x][y] &&
(Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
(game.engine_version < VERSION_IDENT(2,2,0,7) &&
CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
(Feld[x][y + 1] == EL_BLOCKED)))
+#endif
#else
#if 1
WasJustMoving[x][y],
HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
- HAS_ANY_CHANGE_EVENT(element, CE_OTHER_IS_HITTING),
- HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
+ HAS_ANY_CHANGE_EVENT(element, CE_HITTING_X),
+ HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_X));
#endif
#if 1
#endif
Store[x][y] = EL_EMPTY;
- MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+ MovPos[x][y] = 0;
+ MovDir[x][y] = 0;
+ MovDelay[x][y] = 0;
MovDelay[newx][newy] = 0;
if (CAN_CHANGE(element))
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
- Changed[x][y] = CE_BITMASK_DEFAULT;
- ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+ Changed[x][y] = FALSE;
+ ChangeEvent[x][y] = -1;
/* copy animation control values to new field */
GfxFrame[newx][newy] = GfxFrame[x][y];
Pushed[x][y] = Pushed[newx][newy] = FALSE;
+#if 0
+ /* do this after checking for left-behind element */
ResetGfxAnimation(x, y); /* reset animation values for old field */
+#endif
#if 1
/* some elements can leave other elements behind after moving */
int move_leave_element = ei->move_leave_element;
Feld[x][y] = move_leave_element;
+
+#if USE_PREVIOUS_MOVE_DIR
+ if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+ MovDir[x][y] = direction;
+#endif
+
InitField(x, y, FALSE);
if (GFX_CRUMBLED(Feld[x][y]))
ei->can_leave_element = FALSE;
#endif
+#if 1
+ /* do this after checking for left-behind element */
+ ResetGfxAnimation(x, y); /* reset animation values for old field */
+#endif
+
#if 0
/* 2.1.1 (does not work correctly for spring) */
if (!CAN_MOVE(element))
/* give the player one last chance (one more frame) to move away */
if (CAN_FALL(element) && direction == MV_DOWN &&
(newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
- (!IS_PLAYER(x, newy + 1) ||
+ ((newy < lev_fieldy - 1 && !IS_PLAYER(x, newy + 1)) ||
game.engine_version < VERSION_IDENT(3,1,1,0)))
Impact(x, newy);
#else
#if USE_PUSH_BUGFIX
#if 1
- if (pushed_by_player && !game.use_bug_change_when_pushing)
+ if (pushed_by_player && !game.use_change_when_pushing_bug)
#else
if (pushed_by_player && game.engine_version >= VERSION_IDENT(3,1,0,0))
#endif
CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(newx,newy,element,CE_OTHER_GETS_PUSHED,
+ CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
}
#endif
CE_HIT_BY_SOMETHING, opposite_direction);
if (IS_CUSTOM_ELEMENT(hitting_element) &&
- HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
+ HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X))
{
for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
{
&element_info[hitting_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
+ change->has_event[CE_HITTING_X] &&
change->trigger_side & touched_side &&
change->trigger_element == touched_element)
{
CheckElementChangeByPage(newx, newy, hitting_element,
- touched_element, CE_OTHER_IS_HITTING,i);
+ touched_element, CE_HITTING_X, i);
break;
}
}
}
if (IS_CUSTOM_ELEMENT(touched_element) &&
- HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
+ HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X))
{
for (i = 0; i < element_info[touched_element].num_change_pages; i++)
{
&element_info[touched_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
+ change->has_event[CE_HIT_BY_X] &&
change->trigger_side & hitting_side &&
change->trigger_element == hitting_element)
{
CheckElementChangeByPage(nextx, nexty, touched_element,
- hitting_element, CE_OTHER_GETS_HIT, i);
+ hitting_element, CE_HIT_BY_X,i);
break;
}
}
RelocatePlayer(x, y, target_element);
#if 1
+ Changed[x][y] = TRUE; /* ignore all further changes in this frame */
+#else
Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
#endif
int old_element = Feld[x][y];
/* always use default change event to prevent running into a loop */
- if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT)
- ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY);
+ if (ChangeEvent[x][y] == -1)
+ ChangeEvent[x][y] = CE_DELAY;
- if (ChangeEvent[x][y] == CH_EVENT_BIT(CE_DELAY))
+ if (ChangeEvent[x][y] == CE_DELAY)
{
/* reset actual trigger element and player */
change->actual_trigger_element = EL_EMPTY;
change->actual_trigger_player = EL_PLAYER_1;
}
- /* do not change already changed elements with same change event */
-#if 0
- if (Changed[x][y] & ChangeEvent[x][y])
+#if 1
+ /* do not change any elements that have already changed in this frame */
+ if (Changed[x][y])
return FALSE;
#else
- if (Changed[x][y])
+ /* do not change already changed elements with same change event */
+ if (Changed[x][y] & ChangeEvent[x][y])
return FALSE;
#endif
+#if 1
+ Changed[x][y] = TRUE; /* ignore all further changes in this frame */
+#else
Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
+#endif
#if 0
/* !!! indirect change before direct change !!! */
- CheckTriggeredElementChangeByPage(x,y,Feld[x][y], CE_OTHER_IS_CHANGING,page);
+ CheckTriggeredElementChangeByPage(x, y, Feld[x][y], CE_CHANGE_OF_X, page);
#endif
if (change->explode)
#if 1
/* this uses direct change before indirect change */
- CheckTriggeredElementChangeByPage(x,y,old_element,CE_OTHER_IS_CHANGING,page);
+ CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page);
#endif
return TRUE;
int i, j, x, y;
int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
- if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ if (!(trigger_events[trigger_element][trigger_event]))
return FALSE;
for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
struct ElementChangeInfo *change = &element_info[element].change_page[j];
if (change->can_change &&
- change->events & CH_EVENT_BIT(trigger_event) &&
+ change->has_event[trigger_event] &&
change->trigger_side & trigger_side &&
change->trigger_player & trigger_player &&
change->trigger_page & trigger_page_bits &&
IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))
{
#if 0
- if (!(change->events & CH_EVENT_BIT(trigger_event)))
+ if (!(change->has_event[trigger_event]))
printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n",
trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event);
#endif
if (Feld[x][y] == element)
{
ChangeDelay[x][y] = 1;
- ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeEvent[x][y] = trigger_event;
ChangeElement(x, y, page);
}
}
struct ElementChangeInfo *change = &element_info[element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(trigger_event) &&
+ change->has_event[trigger_event] &&
change->trigger_side & trigger_side &&
change->trigger_player & trigger_player)
{
#endif
ChangeDelay[x][y] = 1;
- ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeEvent[x][y] = trigger_event;
ChangeElement(x, y, trigger_page);
return TRUE;
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
{
- Changed[x][y] = CE_BITMASK_DEFAULT;
- ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+ Changed[x][y] = FALSE;
+ ChangeEvent[x][y] = -1;
#if USE_NEW_BLOCK_STYLE
/* this must be handled before main playfield loop */
return (IN_LEV_FIELD(jx, jy + 1) &&
(IS_FREE(jx, jy + 1) ||
+#if USE_NEW_BLOCK_STYLE
+#if USE_GRAVITY_BUGFIX_OLD
+ Feld[jx][jy + 1] == EL_PLAYER_IS_LEAVING ||
+#endif
+#endif
(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]));
/* check if DigField() has caused relocation of the player */
if (player->jx != jx || player->jy != jy)
- return MF_NO_ACTION;
+ return MF_NO_ACTION; /* <-- !!! CHECK THIS [-> MF_ACTION ?] !!! */
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
#if 0
if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
{
- CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_OTHER_GETS_LEFT,
+ CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_PLAYER_LEAVES_X,
leave_side);
CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side);
}
if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
{
CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
- CE_OTHER_GETS_ENTERED, enter_side);
+ CE_PLAYER_ENTERS_X, enter_side);
CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
CE_ENTERED_BY_PLAYER, enter_side);
}
player->index_bit, leave_side);
CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
- CE_OTHER_GETS_LEFT,
+ CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
if (IS_CUSTOM_ELEMENT(new_element))
player->index_bit, enter_side);
CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
- CE_OTHER_GETS_ENTERED,
+ CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
#endif
printf("::: ALERT! block_delay == %d\n", player->block_delay);
#endif
- if (player->block_delay > 0 &&
+ if ((player->block_last_field || player->block_delay_adjustment > 0) &&
Feld[last_jx][last_jy] == EL_EMPTY)
{
+ int last_field_block_delay = 0; /* start with no blocking at all */
+ int block_delay_adjustment = player->block_delay_adjustment;
+
+ /* if player blocks last field, add delay for exactly one move */
+ if (player->block_last_field)
+ {
+ last_field_block_delay += player->move_delay_value;
+
+#if USE_GRAVITY_BUGFIX_NEW
+ /* when blocking enabled, prevent moving up despite gravity */
+ if (game.gravity && player->MovDir == MV_UP)
+ block_delay_adjustment = -1;
+#endif
+ }
+
+ /* add block delay adjustment (also possible when not blocking) */
+ last_field_block_delay += block_delay_adjustment;
+
+#if 0
+#if USE_BLOCK_DELAY_BUGFIX
+ /* when blocking enabled, correct block delay for fast movement */
+ if (player->block_last_field &&
+ player->move_delay_value < MOVE_DELAY_NORMAL_SPEED)
+ last_field_block_delay =
+ player->move_delay_value + player->block_delay_adjustment;
+#endif
+#endif
+
+#if 0
+#if USE_GRAVITY_BUGFIX_NEW
+ /* when blocking enabled, correct block delay for gravity movement */
+ if (player->block_last_field &&
+ game.gravity && player->MovDir == MV_UP)
+ last_field_block_delay = player->move_delay_value - 1;
+#endif
+#endif
+
Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
- MovDelay[last_jx][last_jy] = player->block_delay + 1;
+ MovDelay[last_jx][last_jy] = last_field_block_delay + 1;
}
#else
#if USE_NEW_MOVE_STYLE
player->index_bit, leave_side);
CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
- CE_OTHER_GETS_LEFT,
+ CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
if (IS_CUSTOM_ELEMENT(new_element))
player->index_bit, enter_side);
CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
- CE_OTHER_GETS_ENTERED,
+ CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
#endif
CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, border_side);
CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
- CE_OTHER_GETS_TOUCHED,
+ CE_PLAYER_TOUCHES_X,
player->index_bit, border_side);
#else
CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
- CE_OTHER_GETS_TOUCHED,
+ CE_PLAYER_TOUCHES_X,
player->index_bit, border_side);
CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, border_side);
CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, center_side);
CheckTriggeredElementChangeByPlayer(x, y, center_element,
- CE_OTHER_GETS_TOUCHED,
+ CE_PLAYER_TOUCHES_X,
player->index_bit, center_side);
#else
CheckTriggeredElementChangeByPlayer(x, y, center_element,
- CE_OTHER_GETS_TOUCHED,
+ CE_PLAYER_TOUCHES_X,
player->index_bit, center_side);
CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, center_side);
/* 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) &&
+ HAS_ANY_CHANGE_EVENT(center_element, CE_TOUCHING_X) &&
!change_center_element)
{
for (j = 0; j < element_info[center_element].num_change_pages; j++)
&element_info[center_element].change_page[j];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ change->has_event[CE_TOUCHING_X] &&
change->trigger_side & border_side &&
#if 1
IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element)
/* check for change of border element */
if (IS_CUSTOM_ELEMENT(border_element) &&
- HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
+ HAS_ANY_CHANGE_EVENT(border_element, CE_TOUCHING_X))
{
for (j = 0; j < element_info[border_element].num_change_pages; j++)
{
&element_info[border_element].change_page[j];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ change->has_event[CE_TOUCHING_X] &&
change->trigger_side & center_side &&
#if 1
IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
#endif
CheckElementChangeByPage(xx, yy, border_element, center_element,
- CE_OTHER_IS_TOUCHING, j);
+ CE_TOUCHING_X, j);
break;
}
}
#endif
CheckElementChangeByPage(x, y, center_element, border_trigger_element,
- CE_OTHER_IS_TOUCHING, center_element_change_page);
+ CE_TOUCHING_X, center_element_change_page);
}
}
touched_element = (IN_LEV_FIELD(hitx, hity) ?
MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
+#if !USE_HITTING_SOMETHING_BUGFIX
+ /* "hitting something" is also true when hitting the playfield border */
CheckElementChangeBySide(x, y, hitting_element, touched_element,
CE_HITTING_SOMETHING, direction);
+#endif
if (IN_LEV_FIELD(hitx, hity))
{
{
int i;
+#if !USE_HIT_BY_SOMETHING_BUGFIX
CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
CE_HIT_BY_SOMETHING, opposite_direction);
+#endif
if (IS_CUSTOM_ELEMENT(hitting_element) &&
- HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
+ HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X))
{
for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
{
&element_info[hitting_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
+ change->has_event[CE_HITTING_X] &&
change->trigger_side & touched_side &&
#if 1
)
{
CheckElementChangeByPage(x, y, hitting_element, touched_element,
- CE_OTHER_IS_HITTING, i);
+ CE_HITTING_X, i);
break;
}
}
}
if (IS_CUSTOM_ELEMENT(touched_element) &&
- HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
+ HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X))
{
for (i = 0; i < element_info[touched_element].num_change_pages; i++)
{
&element_info[touched_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
+ change->has_event[CE_HIT_BY_X] &&
change->trigger_side & hitting_side &&
#if 1
IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
)
{
CheckElementChangeByPage(hitx, hity, touched_element,
- hitting_element, CE_OTHER_GETS_HIT, i);
+ hitting_element, CE_HIT_BY_X, i);
break;
}
}
}
+
+#if USE_HIT_BY_SOMETHING_BUGFIX
+ CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
+ CE_HIT_BY_SOMETHING, opposite_direction);
+#endif
}
}
+
+#if USE_HITTING_SOMETHING_BUGFIX
+ /* "hitting something" is also true when hitting the playfield border */
+ CheckElementChangeBySide(x, y, hitting_element, touched_element,
+ CE_HITTING_SOMETHING, direction);
+#endif
}
#if 0
&element_info[hitting_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_SMASHING) &&
+ change->has_event[CE_OTHER_IS_SMASHING] &&
change->trigger_side & touched_side &&
#if 1
&element_info[touched_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_GETS_SMASHED) &&
+ change->has_event[CE_OTHER_GETS_SMASHED] &&
change->trigger_side & hitting_side &&
#if 1
IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
return MF_NO_ACTION; /* player cannot walk here due to gravity */
#endif
- if (IS_GATE(element))
+ if (IS_RND_GATE(element))
{
- if (!player->key[element - EL_GATE_1])
+ if (!player->key[RND_GATE_NR(element)])
return MF_NO_ACTION;
}
- else if (IS_GATE_GRAY(element))
+ else if (IS_RND_GATE_GRAY(element))
{
- if (!player->key[element - EL_GATE_1_GRAY])
+ if (!player->key[RND_GATE_GRAY_NR(element)])
return MF_NO_ACTION;
}
else if (element == EL_EXIT_OPEN ||
if (IS_EM_GATE(element))
{
- if (!player->key[element - EL_EM_GATE_1])
+ if (!player->key[EM_GATE_NR(element)])
return MF_NO_ACTION;
}
else if (IS_EM_GATE_GRAY(element))
{
- if (!player->key[element - EL_EM_GATE_1_GRAY])
+ if (!player->key[EM_GATE_GRAY_NR(element)])
return MF_NO_ACTION;
}
else if (IS_SP_PORT(element))
PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
- CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_DIGGED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
player->index_bit, dig_side);
#if 1
{
player->dynabomb_xl = TRUE;
}
- else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
- (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
+ else if (IS_KEY(element))
{
- int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
- element - EL_KEY_1 : element - EL_EM_KEY_1);
-
- player->key[key_nr] = TRUE;
+ player->key[KEY_NR(element)] = TRUE;
- DrawGameValue_Keys(player);
+ DrawGameValue_Keys(player->key);
redraw_mask |= REDRAW_DOOR_1;
}
if (is_player)
CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_OTHER_GETS_COLLECTED,
+ CE_PLAYER_COLLECTS_X,
player->index_bit, dig_side);
#if 1
#if USE_PUSH_BUGFIX
/* now: check for element change _after_ element has been pushed! */
#if 1
- if (game.use_bug_change_when_pushing)
+ if (game.use_change_when_pushing_bug)
#else
if (game.engine_version < VERSION_IDENT(3,1,0,0))
#endif
{
CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x,y,element,CE_OTHER_GETS_PUSHED,
+ CheckTriggeredElementChangeByPlayer(x,y, element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
}
/* !!! TEST ONLY !!! */
CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
#else
- CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
if (PLAYER_SWITCHING(player, x, y))
{
CheckTriggeredElementChangeByPlayer(x,y, element,
- CE_OTHER_GETS_PRESSED,
+ CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
return MF_ACTION;
Feld[x][y] = EL_LAMP_ACTIVE;
local_player->lights_still_needed--;
+ ResetGfxAnimation(x, y);
DrawLevelField(x, y);
}
else if (element == EL_TIME_ORB_FULL)
TimeLeft += 10;
DrawGameValue_Time(TimeLeft);
+ ResetGfxAnimation(x, y);
DrawLevelField(x, y);
#if 0
}
CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_OTHER_IS_SWITCHING,
+ CE_SWITCH_OF_X,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
return MF_ACTION;
CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
player->index_bit, dig_side);
CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_OTHER_IS_SWITCHING,
+ CE_SWITCH_OF_X,
player->index_bit, dig_side);
#else
CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_OTHER_IS_SWITCHING,
+ CE_SWITCH_OF_X,
player->index_bit, dig_side);
CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
player->index_bit, dig_side);
/* !!! TEST ONLY !!! (this breaks "machine", level 000) */
CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
#else
- CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
player->index_bit, dig_side);
player->push_delay = 0;
#endif
- if (Feld[x][y] != element) /* really digged/collected something */
- player->is_collecting = !player->is_digging;
+#if USE_PENGUIN_COLLECT_BUGFIX
+ if (is_player) /* function can also be called by EL_PENGUIN */
+#endif
+ {
+ if (Feld[x][y] != element) /* really digged/collected something */
+ player->is_collecting = !player->is_digging;
+ }
return MF_MOVING;
}
#if 1
/* needed if previous element just changed to "empty" in the last frame */
- Changed[dropx][dropy] = 0; /* allow another change */
+ Changed[dropx][dropy] = FALSE; /* allow another change */
#endif
#if 1
CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
player->index_bit, drop_side);
CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
- CE_OTHER_GETS_DROPPED,
+ CE_PLAYER_DROPS_X,
player->index_bit, drop_side);
#else
CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
- CE_OTHER_GETS_DROPPED,
+ CE_PLAYER_DROPS_X,
player->index_bit, drop_side);
CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
player->index_bit, drop_side);
nexty = dropy + GET_DY_FROM_DIR(move_direction);
#if 1
- Changed[dropx][dropy] = 0; /* allow another change */
+ Changed[dropx][dropy] = FALSE; /* allow another change */
CheckCollision[dropx][dropy] = 2;
#else
/* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */
else
{
- Changed[dropx][dropy] = 0; /* allow another change */
+ Changed[dropx][dropy] = FALSE; /* allow another change */
#if 1
TestIfElementHitsCustomElement(dropx, dropy, move_direction);
PlayMusic(MAP_NOCONF_MUSIC(level_nr)); /* from music dir */
}
-void PlayLevelSound_EM(int x, int y, int element, int action)
+void PlayLevelSound_EM(int x, int y, int element_em, int sample)
{
- PlayLevelSoundElementAction(x, y, element, action);
+ int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
+
+#if 0
+ if (sample == SAMPLE_bug)
+ printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample);
+#endif
+
+ switch (sample)
+ {
+ case SAMPLE_blank:
+ PlayLevelSoundElementAction(x, y, element, ACTION_WALKING);
+ break;
+
+ case SAMPLE_roll:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+ break;
+
+ case SAMPLE_stone:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_nut:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_crack:
+ PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+ break;
+
+ case SAMPLE_bug:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_tank:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_android_clone:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_android_move:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_spring:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_slurp:
+ PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ break;
+
+ case SAMPLE_eater:
+ PlayLevelSoundElementAction(x, y, element, ACTION_WAITING);
+ break;
+
+ case SAMPLE_eater_eat:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+ break;
+
+ case SAMPLE_alien:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_collect:
+ PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
+ break;
+
+ case SAMPLE_diamond:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_squash:
+ /* !!! CHECK THIS !!! */
+#if 1
+ PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+#else
+ PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK);
+#endif
+ break;
+
+ case SAMPLE_wonderfall:
+ PlayLevelSoundElementAction(x, y, element, ACTION_FILLING);
+ break;
+
+ case SAMPLE_drip:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_push:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+ break;
+
+ case SAMPLE_dirt:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+ break;
+
+ case SAMPLE_acid:
+ PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING);
+ break;
+
+ case SAMPLE_ball:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_grow:
+ PlayLevelSoundElementAction(x, y, element, ACTION_GROWING);
+ break;
+
+ case SAMPLE_wonder:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_door:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+ break;
+
+ case SAMPLE_exit_open:
+ PlayLevelSoundElementAction(x, y, element, ACTION_OPENING);
+ break;
+
+ case SAMPLE_exit_leave:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+ break;
+
+ case SAMPLE_dynamite:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_tick:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_press:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
+ break;
+
+ case SAMPLE_wheel:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_boom:
+ PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
+ break;
+
+ case SAMPLE_die:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
+ break;
+
+ case SAMPLE_time:
+ PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+ break;
+
+ default:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT);
+ break;
+ }
}
void RaiseScore(int value)
case EL_KEY_2:
case EL_KEY_3:
case EL_KEY_4:
+ case EL_EM_KEY_1:
+ case EL_EM_KEY_2:
+ case EL_EM_KEY_3:
+ case EL_EM_KEY_4:
+ case EL_EMC_KEY_5:
+ case EL_EMC_KEY_6:
+ case EL_EMC_KEY_7:
+ case EL_EMC_KEY_8:
RaiseScore(level.score[SC_KEY]);
break;
default: