#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)
-#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_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)
+#define USE_PUSH_BUGFIX (TRUE * USE_NEW_STUFF * 1)
#if 0
-#define USE_BLOCK_DELAY_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+#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_GRAVITY_BUGFIX_NEW (TRUE * USE_NEW_STUFF * 1)
+#define USE_GRAVITY_BUGFIX_OLD (TRUE * USE_NEW_STUFF * 0)
-#define USE_PENGUIN_COLLECT_BUG (TRUE * USE_NEW_STUFF * 1)
+#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_DROP_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_CHANGE_TO_TRIGGERED (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_BACK_WALKABLE_BUGFIX (TRUE * USE_NEW_STUFF * 1)
/* for DigField() */
RND(element_info[e].move_delay_random))
#define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
(element_info[e].move_delay_random))
+#define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \
+ RND((c)->delay_random * (c)->delay_frames))
#define GET_TARGET_ELEMENT(e, ch) \
((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
{ 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))
/* 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));
+ else
+ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+ DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS,
+ MINI_TILEX, MINI_TILEY, DX_KEYS + i * MINI_TILEX, DY_KEYS);
+ }
}
inline void DrawGameValue_Score(int value)
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 :
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->switch_x = -1;
player->switch_y = -1;
+#if USE_DROP_BUGFIX
+ player->drop_x = -1;
+ player->drop_y = -1;
+#endif
+
player->show_envelope = 0;
player->move_delay = game.initial_move_delay;
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
}
- CloseDoor(DOOR_CLOSE_1);
+ if (!game.restart_level)
+ CloseDoor(DOOR_CLOSE_1);
/* !!! FIX THIS (START) !!! */
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
}
/* !!! FIX THIS (END) !!! */
- /* copy default game door content to main double buffer */
- BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
- DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+ if (!game.restart_level)
+ {
+ /* copy default game door content to main double buffer */
+ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+ DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+ }
DrawGameDoorValues();
- UnmapGameButtons();
- UnmapTapeButtons();
- game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
- game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
- game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
- MapGameButtons();
- MapTapeButtons();
+ if (!game.restart_level)
+ {
+ UnmapGameButtons();
+ UnmapTapeButtons();
+ game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
+ game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
+ game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
+ MapGameButtons();
+ MapTapeButtons();
- /* copy actual game door content to door double buffer for OpenDoor() */
- BlitBitmap(drawto, bitmap_db_door,
- DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+ /* copy actual game door content to door double buffer for OpenDoor() */
+ BlitBitmap(drawto, bitmap_db_door,
+ DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
- OpenDoor(DOOR_OPEN_ALL);
+ OpenDoor(DOOR_OPEN_ALL);
- PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
+ PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
- if (setup.sound_music)
- PlayLevelMusic();
+ if (setup.sound_music)
+ PlayLevelMusic();
- KeyboardAutoRepeatOffUnlessAutoplay();
+ KeyboardAutoRepeatOffUnlessAutoplay();
- if (options.debug)
- {
- for (i = 0; i < MAX_PLAYERS; i++)
- printf("Player %d %sactive.\n",
- i + 1, (stored_player[i].active ? "" : "not "));
+ if (options.debug)
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ printf("Player %d %sactive.\n",
+ i + 1, (stored_player[i].active ? "" : "not "));
+ }
}
+ game.restart_level = FALSE;
+
#if 0
printf("::: starting game [%d]\n", FrameCounter);
#endif
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
}
break;
}
- CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING);
+ CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X);
}
void SplashAcid(int x, int y)
void Impact(int x, int y)
{
- boolean lastline = (y == lev_fieldy-1);
+ boolean last_line = (y == lev_fieldy - 1);
boolean object_hit = FALSE;
- boolean impact = (lastline || object_hit);
+ boolean impact = (last_line || object_hit);
int element = Feld[x][y];
int smashed = EL_STEELWALL;
- if (!lastline) /* check if element below was hit */
+#if 0
+ printf("IMPACT!\n");
+#endif
+
+ if (!last_line) /* check if element below was hit */
{
if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
return;
if (object_hit)
smashed = MovingOrBlocked2Element(x, y + 1);
- impact = (lastline || object_hit);
+ impact = (last_line || object_hit);
}
- if (!lastline && smashed == EL_ACID) /* element falls into acid */
+ if (!last_line && smashed == EL_ACID) /* element falls into acid */
{
SplashAcid(x, y + 1);
return;
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
}
/* play sound of magic wall / mill */
- if (!lastline &&
+ if (!last_line &&
(Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
{
}
/* play sound of object that hits the ground */
- if (lastline || object_hit)
+ if (last_line || object_hit)
PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
}
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
#if 1
Store[newx][newy] = EL_EMPTY;
if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
+ {
+#if USE_CHANGE_TO_TRIGGERED
+ int move_leave_element = element_info[element].move_leave_element;
+
+ Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ?
+ new_element : move_leave_element);
+#else
Store[newx][newy] = element_info[element].move_leave_element;
+#endif
+ }
#else
Store[newx][newy] = EL_EMPTY;
if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) ||
ContinueMoving(x, y);
}
+void dummy()
+{
+}
+
void ContinueMoving(int x, int y)
{
int element = Feld[x][y];
#else
boolean pushed_by_player = Pushed[x][y];
#endif
+ boolean last_line = (newy == lev_fieldy - 1);
MovPos[x][y] += getElementMoveStepsize(x, y);
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];
{
int move_leave_element = ei->move_leave_element;
+#if USE_CHANGE_TO_TRIGGERED
+ if (ei->move_leave_type == LEAVE_TYPE_LIMITED &&
+ ei->move_leave_element == EL_TRIGGER_ELEMENT)
+ move_leave_element = stored;
+#endif
+
Feld[x][y] = move_leave_element;
#if USE_PREVIOUS_MOVE_DIR
#if USE_NEW_MOVE_STYLE
#if 0
if (CAN_FALL(element) && direction == MV_DOWN &&
- (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
- IS_PLAYER(x, newy + 1))
+ !last_line && IS_PLAYER(x, newy + 1))
printf("::: we would now kill the player [%d]\n", FrameCounter);
#endif
/* 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) ||
- game.engine_version < VERSION_IDENT(3,1,1,0)))
+ (last_line || (!IS_FREE(x, newy + 1) &&
+ (!IS_PLAYER(x, newy + 1) ||
+ game.engine_version < VERSION_IDENT(3,1,1,0)))))
Impact(x, newy);
#else
if (CAN_FALL(element) && direction == MV_DOWN &&
- (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)))
+ (last_line || !IS_FREE(x, newy + 1)))
Impact(x, newy);
#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;
}
}
DrawLevelFieldCrumbledSand(x, y);
}
-static void ChangeElementNowExt(int x, int y, int target_element)
+static int getSpecialActionElement(int element, int number, int base_element)
+{
+ return (element != EL_EMPTY ? element :
+ number != -1 ? base_element + number - 1 :
+ EL_EMPTY);
+}
+
+static int getModifiedActionNumber(int value_old, int value_min, int value_max,
+ int operator, int operand)
+{
+ int value_new = (operator == CA_MODE_ADD ? value_old + operand :
+ operator == CA_MODE_SUBTRACT ? value_old - operand :
+ operator == CA_MODE_MULTIPLY ? value_old * operand :
+ operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) :
+ operator == CA_MODE_SET ? operand :
+ value_old);
+
+ return (value_new < value_min ? value_min :
+ value_new > value_max ? value_max :
+ value_new);
+}
+
+static void ExecuteCustomElementAction(int element, int page)
+{
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+ int action_type = change->action_type;
+ int action_mode = change->action_mode;
+ int action_arg = change->action_arg;
+ int i;
+
+ /* ---------- determine action paramater values ---------- */
+
+ int action_arg_element =
+ (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player :
+ action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element :
+ action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element :
+ EL_EMPTY);
+
+ int action_arg_number =
+ (action_arg <= CA_ARG_MAX ? action_arg :
+ action_arg == CA_ARG_NUMBER_MIN ? CA_ARG_MIN :
+ action_arg == CA_ARG_NUMBER_MAX ? CA_ARG_MAX :
+ action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
+ action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count :
+ action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) :
+ -1);
+
+ /* (for explicit player choice, set invalid value to "no player") */
+ int action_arg_player_bits =
+ (action_arg == CA_ARG_PLAYER_ANY ? action_arg - CA_ARG_PLAYER :
+ action_arg >= CA_ARG_PLAYER_1 &&
+ action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER :
+ action_arg >= CA_ARG_1 &&
+ action_arg <= CA_ARG_PLAYER_4 ? (1 << (action_arg - 1)) :
+ action_arg_element >= EL_PLAYER_1 &&
+ action_arg_element <= EL_PLAYER_4 ?
+ (1 << (action_arg_element - EL_PLAYER_1)) :
+ 0);
+
+ /* (for implicit player choice, set invalid value to "all players") */
+ int trigger_player_bits =
+ (change->actual_trigger_player >= EL_PLAYER_1 &&
+ change->actual_trigger_player <= EL_PLAYER_4 ?
+ (1 << (change->actual_trigger_player - EL_PLAYER_1)) :
+ PLAYER_BITS_ANY);
+
+ /* ---------- execute action ---------- */
+
+ switch(action_type)
+ {
+ case CA_NO_ACTION:
+ {
+ return;
+ }
+
+ case CA_EXIT_PLAYER:
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (action_arg_player_bits & (1 << i))
+ stored_player[i].LevelSolved = stored_player[i].GameOver = TRUE;
+
+ break;
+ }
+
+ case CA_KILL_PLAYER:
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (action_arg_player_bits & (1 << i))
+ KillHero(&stored_player[i]);
+
+ break;
+ }
+
+ case CA_RESTART_LEVEL:
+ {
+ game.restart_level = TRUE;
+
+ break;
+ }
+
+ case CA_SHOW_ENVELOPE:
+ {
+ int element = getSpecialActionElement(action_arg_element,
+ action_arg_number, EL_ENVELOPE_1);
+
+ if (IS_ENVELOPE(element))
+ local_player->show_envelope = element;
+
+ break;
+ }
+
+ case CA_ADD_KEY:
+ {
+ int element = getSpecialActionElement(action_arg_element,
+ action_arg_number, EL_KEY_1);
+
+ if (IS_KEY(element))
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (trigger_player_bits & (1 << i))
+ {
+ stored_player[i].key[KEY_NR(element)] = TRUE;
+
+ DrawGameValue_Keys(stored_player[i].key);
+
+ redraw_mask |= REDRAW_DOOR_1;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case CA_DEL_KEY:
+ {
+ int element = getSpecialActionElement(action_arg_element,
+ action_arg_number, EL_KEY_1);
+
+ if (IS_KEY(element))
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (trigger_player_bits & (1 << i))
+ {
+ stored_player[i].key[KEY_NR(element)] = FALSE;
+
+ DrawGameValue_Keys(stored_player[i].key);
+
+ redraw_mask |= REDRAW_DOOR_1;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case CA_SET_PLAYER_SPEED:
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (trigger_player_bits & (1 << i))
+ {
+ if (action_arg == CA_ARG_NUMBER_RESET)
+ stored_player[i].move_delay_value = game.initial_move_delay_value;
+ else if (action_arg == CA_ARG_NUMBER_NORMAL)
+ stored_player[i].move_delay_value = MOVE_DELAY_NORMAL_SPEED;
+ else if (action_arg == CA_ARG_NUMBER_MIN)
+ stored_player[i].move_delay_value = 16;
+ else if (action_arg == CA_ARG_NUMBER_MAX)
+ stored_player[i].move_delay_value = MOVE_DELAY_HIGH_SPEED;
+ else
+ {
+#if 0
+ if (action_mode == CA_MODE_ADD)
+ {
+ action_mode = CA_MODE_DIVIDE;
+ action_arg_number = (1 << action_arg_number);
+ }
+ else if (action_mode == CA_MODE_SUBTRACT)
+ {
+ action_mode = CA_MODE_MULTIPLY;
+ action_arg_number = (1 << action_arg_number);
+ }
+
+ int mode = (action_mode == CA_MODE_MULTIPLY ? CA_MODE_DIVIDE :
+ action_mode == CA_MODE_DIVIDE ? CA_MODE_MULTIPLY :
+ action_mode);
+
+ stored_player[i].move_delay_value =
+ getModifiedActionNumber(stored_player[i].move_delay_value,
+ 1, 16,
+ action_mode, action_arg_number);
+#endif
+ }
+ }
+ }
+
+ break;
+ }
+
+ case CA_SET_GEMS:
+ {
+ local_player->gems_still_needed =
+ getModifiedActionNumber(local_player->gems_still_needed, 0, 999,
+ action_mode, action_arg_number);
+
+ DrawGameValue_Emeralds(local_player->gems_still_needed);
+
+ break;
+ }
+
+ case CA_SET_TIME:
+ {
+ if (level.time > 0) /* only modify limited time value */
+ {
+ TimeLeft = getModifiedActionNumber(TimeLeft, 0, 9999,
+ action_mode, action_arg_number);
+
+ DrawGameValue_Time(TimeLeft);
+ }
+
+ break;
+ }
+
+ case CA_SET_SCORE:
+ {
+ local_player->score =
+ getModifiedActionNumber(local_player->score, 0, 99999,
+ action_mode, action_arg_number);
+
+ DrawGameValue_Score(local_player->score);
+
+ break;
+ }
+
+ case CA_SET_CE_SCORE:
+ {
+ printf("::: CA_SET_CE_SCORE -- not yet implemented\n");
+
+ break;
+ }
+
+ case CA_SET_CE_COUNT:
+ {
+ printf("::: CA_SET_CE_COUNT -- not yet implemented\n");
+
+ break;
+ }
+
+ case CA_SET_DYNABOMB_NUMBER:
+ {
+ printf("::: CA_SET_DYNABOMB_NUMBER -- not yet implemented\n");
+
+ break;
+ }
+
+ case CA_SET_DYNABOMB_SIZE:
+ {
+ printf("::: CA_SET_DYNABOMB_SIZE -- not yet implemented\n");
+
+ break;
+ }
+
+ case CA_SET_DYNABOMB_POWER:
+ {
+ printf("::: CA_SET_DYNABOMB_POWER -- not yet implemented\n");
+
+ break;
+ }
+
+ case CA_TOGGLE_PLAYER_GRAVITY:
+ {
+ game.gravity = !game.gravity;
+
+ break;
+ }
+
+ case CA_ENABLE_PLAYER_GRAVITY:
+ {
+ game.gravity = TRUE;
+
+ break;
+ }
+
+ case CA_DISABLE_PLAYER_GRAVITY:
+ {
+ game.gravity = FALSE;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+static void ChangeElementNowExt(struct ElementChangeInfo *change,
+ int x, int y, int target_element)
{
int previous_move_direction = MovDir[x][y];
#if 1
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
TestIfPlayerTouchesCustomElement(x, y);
TestIfElementTouchesCustomElement(x, y);
#endif
+
+#if 0
+ if (change->use_action)
+ ExecuteCustomElementAction(...);
+#endif
}
static boolean ChangeElementNow(int x, int y, int element, int page)
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 */
+ /* reset actual trigger element, trigger player and action element */
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)
content_element = change->target_content[xx][yy];
target_element = GET_TARGET_ELEMENT(content_element, change);
- ChangeElementNowExt(ex, ey, target_element);
+ ChangeElementNowExt(change, ex, ey, target_element);
something_has_changed = TRUE;
{
target_element = GET_TARGET_ELEMENT(change->target_element, change);
- ChangeElementNowExt(x, y, target_element);
+ ChangeElementNowExt(change, x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
}
#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;
if (ChangeDelay[x][y] == 0) /* initialize element change */
{
+#if 1
+ ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1;
+#else
ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames +
RND(change->delay_random * change->delay_frames)) + 1;
+#endif
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
return;
}
+#if 1
+ if (change->use_action)
+ ExecuteCustomElementAction(element, page);
+#endif
+
if (ChangeElementNow(x, y, element, page))
{
if (change->post_change_function)
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 */
#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
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)
if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
+#if USE_BACK_WALKABLE_BUGFIX
+
+ /* in case of element dropped at player position, check background */
+ else if (Back[jx][jy] != EL_EMPTY &&
+ game.engine_version >= VERSION_IDENT(2,2,0,0))
+ old_element = Back[jx][jy];
+#endif
#endif
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
}
if (element == EL_SPEED_PILL)
+ {
player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+ }
else if (element == EL_EXTRA_TIME && level.time > 0)
{
TimeLeft += 10;
if (is_player)
CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_OTHER_GETS_COLLECTED,
+ CE_PLAYER_COLLECTS_X,
player->index_bit, dig_side);
#if 1
{
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;
}
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 USE_PENGUIN_COLLECT_BUG
+#if USE_PENGUIN_COLLECT_BUGFIX
if (is_player) /* function can also be called by EL_PENGUIN */
#endif
{
EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
EL_UNDEFINED);
+#if USE_DROP_BUGFIX
+ /* do not drop an element on top of another element; when holding drop key
+ pressed without moving, dropped element must move away before the next
+ 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;
+#endif
+
if (IS_THROWABLE(drop_element))
{
dropx += GET_DX_FROM_DIR(drop_direction);
#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);
player->is_dropping = TRUE;
+#if USE_DROP_BUGFIX
+ player->drop_x = dropx;
+ player->drop_y = dropy;
+#endif
return TRUE;
}