/* EXPERIMENTAL STUFF */
#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_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_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_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)
+#define USE_NEW_COLLECT_COUNT (TRUE * USE_NEW_STUFF * 1)
/* for DigField() */
static void ChangeElement(int, int, int);
-static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
-#define CheckTriggeredElementChange(x, y, e, ev) \
- CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, \
- CH_SIDE_ANY, -1)
-#define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \
- CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
-#define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \
- CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
-#define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \
- CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, \
- CH_SIDE_ANY, p)
-
-static boolean CheckElementChangeExt(int, int, int, int, int, int, int, int);
+static boolean CheckTriggeredElementChangeExt(int, int, int,int,int);
+#define CheckTriggeredElementChange(e, ev) \
+ CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
+#define CheckTriggeredElementChangeByPlayer(e, ev, p, s) \
+ CheckTriggeredElementChangeExt(e, ev, p, s, -1)
+#define CheckTriggeredElementChangeBySide(e, ev, s) \
+ CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, s, -1)
+#define CheckTriggeredElementChangeByPage(e, ev, p) \
+ CheckTriggeredElementChangeExt(e, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
+
+static boolean CheckElementChangeExt(int, int, int, int, int, int, int);
#define CheckElementChange(x, y, e, te, ev) \
- CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
+ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY)
#define CheckElementChangeByPlayer(x, y, e, ev, p, s) \
- CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, -1)
+ CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s)
#define CheckElementChangeBySide(x, y, e, te, ev, s) \
- CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, -1)
-#define CheckElementChangeByPage(x, y, e, te, ev, p) \
- CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
+ CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s)
static void PlayLevelSound(int, int, int);
static void PlayLevelSoundNearest(int, int, int);
level.sp_block_last_field :
level.block_last_field);
-#if USE_NEW_BLOCK_STYLE
/* ---------- initialize player's last field block delay --------------- */
/* always start with reliable default value (no adjustment needed) */
/* 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);
-#endif
if (!options.network || player->connected)
{
}
break;
}
+
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = element_info[Feld[x][y]].collect_count_initial;
+#endif
}
static inline void InitField_WithBug1(int x, int y, boolean init_game)
/* ---------- initialize player's initial move delay --------------------- */
-#if USE_NEW_MOVE_DELAY
/* dynamically adjust player properties according to level information */
game.initial_move_delay_value =
(level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
/* dynamically adjust player properties according to game engine version */
game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
game.initial_move_delay_value : 0);
-#else
- /* dynamically adjust player properties according to game engine version */
- game.initial_move_delay =
- (game.engine_version <= VERSION_IDENT(2,0,1,0) ? INITIAL_MOVE_DELAY_ON :
- INITIAL_MOVE_DELAY_OFF);
-
- /* 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
/* ---------- initialize player's initial push delay --------------------- */
SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
}
+ /* ---------- initialize internal run-time variables ------------- */
+
+ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
+
+ for (j = 0; j < ei->num_change_pages; j++)
+ {
+ ei->change_page[j].can_change_or_has_action =
+ (ei->change_page[j].can_change |
+ ei->change_page[j].has_action);
+ }
+ }
+
/* add change events from custom element configuration */
for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
{
for (j = 0; j < ei->num_change_pages; j++)
{
- if (!ei->change_page[j].can_change)
+ if (!ei->change_page[j].can_change_or_has_action)
continue;
for (k = 0; k < NUM_CHANGE_EVENTS; k++)
}
}
- /* ---------- initialize internal run-time variables ------------- */
-
- for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
- {
- struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
-
- for (j = 0; j < ei->num_change_pages; j++)
- {
- ei->change_page[j].can_change_or_has_action =
- (ei->change_page[j].can_change |
- ei->change_page[j].has_action);
- }
- }
-
/* ---------- initialize run-time trigger player and element ------------- */
for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
for (j = 0; j < ei->num_change_pages; j++)
{
- if (!ei->change_page[j].can_change)
+ if (!ei->change_page[j].can_change_or_has_action)
continue;
if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION])
{
if (IS_SP_ELEMENT(i))
{
-#if USE_NEW_MOVE_STYLE
/* set SP push delay to just enough to push under a falling zonk */
int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6);
element_info[i].push_delay_fixed = delay;
element_info[i].push_delay_random = 0;
-#else
- element_info[i].push_delay_fixed = 6; /* just enough to escape ... */
- element_info[i].push_delay_random = 0; /* ... from falling zonk */
-#endif
}
}
}
element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
}
- /* ---------- initialize gem count --------------------------------------- */
+ /* ---------- initialize collect score ----------------------------------- */
+
+ /* initialize collect score values for custom elements from initial value */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (IS_CUSTOM_ELEMENT(i))
+ element_info[i].collect_score = element_info[i].collect_score_initial;
+
+ /* ---------- initialize collect count ----------------------------------- */
- /* initialize gem count values for each element */
+ /* initialize collect count values for non-custom elements */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
if (!IS_CUSTOM_ELEMENT(i))
- element_info[i].collect_count = 0;
+ element_info[i].collect_count_initial = 0;
- /* add gem count values for all elements from pre-defined list */
+ /* add collect count values for all elements from pre-defined list */
for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
- element_info[collect_count_list[i].element].collect_count =
+ element_info[collect_count_list[i].element].collect_count_initial =
collect_count_list[i].count;
/* ---------- initialize access direction -------------------------------- */
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_reset_counter = 0;
-#if USE_NEW_PUSH_DELAY
player->push_delay = -1; /* initialized when pushing starts */
player->push_delay_value = game.initial_push_delay_value;
-#else
- player->push_delay = 0;
- player->push_delay_value = game.initial_push_delay_value;
-#endif
player->drop_delay = 0;
MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = 0; /* initialized in InitField() */
+#endif
Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
AmoebaNr[x][y] = 0;
WasJustMoving[x][y] = 0;
player->element_nr = some_player->element_nr;
#endif
-#if USE_NEW_BLOCK_STYLE
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;
player->jx = player->last_jx = jx;
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);
+ /* this is needed for CEs with property "can move" / "not 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];
+
+#if USE_NEW_COLLECT_COUNT
+ Count[newx][newy] = Count[x][y];
+#endif
+
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;
-
- if (Feld[newx][newy] == EL_EMPTY)
- Feld[newx][newy] = EL_BLOCKED;
-
- if (direction == MV_DOWN && CAN_FALL(element))
- GfxAction[x][y] = ACTION_FALLING;
- else
- GfxAction[x][y] = ACTION_MOVING;
-
- GfxFrame[newx][newy] = GfxFrame[x][y];
- 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)
MovDir[x][y] = 0;
MovDelay[x][y] = 0;
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = 0;
+#endif
+
AmoebaNr[x][y] = 0;
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
ScrollPlayer(player, SCROLL_GO_ON);
ScrollScreen(NULL, SCROLL_GO_ON);
-#if USE_NEW_MOVE_DELAY
AdvanceFrameAndPlayerCounters(player->index_nr);
-#else
- FrameCounter++;
-#endif
DrawPlayer(player);
CE_LEFT_BY_PLAYER,
player->index_bit, leave_side);
- CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
- CE_PLAYER_LEAVES_X,
+ CheckTriggeredElementChangeByPlayer(old_element, CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
Feld[jx][jy] = el_player;
CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER,
player->index_bit, enter_side);
- CheckTriggeredElementChangeByPlayer(jx, jy, element,
- CE_PLAYER_ENTERS_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
}
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = 0;
+#endif
+
InitField_WithBug2(x, y, FALSE);
DrawLevelField(x, y);
break;
}
- CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X);
+ CheckTriggeredElementChange(element, CE_EXPLOSION_OF_X);
}
void SplashAcid(int x, int y)
CheckElementChangeBySide(x, y + 1, smashed, element,
CE_SWITCHED, CH_SIDE_TOP);
- CheckTriggeredElementChangeBySide(x, y + 1, smashed,
- CE_SWITCH_OF_X, CH_SIDE_TOP);
+ CheckTriggeredElementChangeBySide(smashed, CE_SWITCH_OF_X,
+ CH_SIDE_TOP);
}
}
else
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 */
+ if (element_info[element].move_stepsize == 0) /* "not moving" */
return;
-#endif
if (move_pattern == MV_TURNING_LEFT)
MovDir[x][y] = left_dir;
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 */
+ 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);
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
{
/* this is needed for a special case not covered by calling "Impact()"
from "ContinueMoving()": if an element moves to a tile directly below
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;
+ /* this makes it possible to leave the removed element again */
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
}
if (move_pattern & MV_MAZE_RUNNER_STYLE)
if (!game.magic_wall_active)
Feld[x][y] = EL_MAGIC_WALL_DEAD;
element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ InitField(newx, newy, FALSE);
+#endif
}
else if (element == EL_BD_MAGIC_WALL_FILLING)
{
if (!game.magic_wall_active)
Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ InitField(newx, newy, FALSE);
+#endif
}
else if (element == EL_AMOEBA_DROPPING)
{
MovPos[x][y] = 0;
MovDir[x][y] = 0;
MovDelay[x][y] = 0;
+
MovDelay[newx][newy] = 0;
if (CAN_CHANGE(element))
ChangePage[newx][newy] = ChangePage[x][y];
Changed[newx][newy] = Changed[x][y];
ChangeEvent[newx][newy] = ChangeEvent[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ Count[newx][newy] = Count[x][y];
+#endif
}
ChangeDelay[x][y] = 0;
Changed[x][y] = FALSE;
ChangeEvent[x][y] = -1;
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = 0;
+#endif
+
/* copy animation control values to new field */
GfxFrame[newx][newy] = GfxFrame[x][y];
GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */
{
int move_leave_element = ei->move_leave_element;
-#if USE_CHANGE_TO_TRIGGERED
+ /* this makes it possible to leave the removed element again */
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 (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = direction;
-#endif
InitField(x, y, FALSE);
else if (element == EL_PENGUIN)
TestIfFriendTouchesBadThing(newx, newy);
-#if USE_NEW_MOVE_STYLE
/* give the player one last chance (one more frame) to move away */
if (CAN_FALL(element) && direction == MV_DOWN &&
(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 &&
- (last_line || !IS_FREE(x, newy + 1)))
- Impact(x, newy);
-#endif
-#if USE_PUSH_BUGFIX
if (pushed_by_player && !game.use_change_when_pushing_bug)
-#else
- if (pushed_by_player)
-#endif
-
{
int dig_side = MV_DIR_OPPOSITE(direction);
struct PlayerInfo *player = PLAYERINFO(x, y);
CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
}
value_new);
}
-static void ExecuteCustomElementAction(int element, int page)
+static void ExecuteCustomElementAction(int x, int y, int element, int page)
{
struct ElementInfo *ei = &element_info[element];
struct ElementChangeInfo *change = &ei->change_page[page];
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 :
+#if USE_NEW_COLLECT_COUNT
+ action_arg == CA_ARG_NUMBER_CE_COUNT ? Count[x][y] :
+#else
+ action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count_initial :
+#endif
action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) :
-1);
case CA_SET_SCORE:
{
local_player->score =
- getModifiedActionNumber(local_player->score, 0, 99999,
+ getModifiedActionNumber(local_player->score, 0, 9999,
action_mode, action_arg_number);
DrawGameValue_Score(local_player->score);
case CA_SET_CE_SCORE:
{
- printf("::: CA_SET_CE_SCORE -- not yet implemented\n");
-
+ ei->collect_score =
+ getModifiedActionNumber(ei->collect_score, 0, 9999,
+ action_mode, action_arg_number);
break;
}
case CA_SET_CE_COUNT:
{
- printf("::: CA_SET_CE_COUNT -- not yet implemented\n");
+#if USE_NEW_COLLECT_COUNT
+ int count_last = Count[x][y];
+
+ Count[x][y] = getModifiedActionNumber(Count[x][y], 0, 9999,
+ action_mode, action_arg_number);
+
+#if 0
+ printf("::: Count == %d\n", Count[x][y]);
+#endif
+
+ if (Count[x][y] == 0 && count_last > 0)
+ {
+#if 0
+ printf("::: CE_COUNT_AT_ZERO\n");
+#endif
+
+ CheckElementChange(x, y, element, EL_UNDEFINED, CE_COUNT_AT_ZERO);
+ CheckTriggeredElementChange(element, CE_COUNT_AT_ZERO_OF_X);
+ }
+#endif
break;
}
}
/* this uses direct change before indirect change */
- CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page);
+ CheckTriggeredElementChangeByPage(old_element, CE_CHANGE_OF_X, page);
return TRUE;
}
}
}
-static boolean CheckTriggeredElementChangeExt(int lx, int ly,
- int trigger_element,
+static boolean CheckTriggeredElementChangeExt(int trigger_element,
int trigger_event,
int trigger_player,
int trigger_side,
int trigger_page)
{
- int i, j, x, y;
+ boolean change_done_any = FALSE;
int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
+ int i;
if (!(trigger_events[trigger_element][trigger_event]))
return FALSE;
for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
{
int element = EL_CUSTOM_START + i;
- boolean change_found = FALSE;
+ boolean change_done = FALSE;
+ int p;
if (!CAN_CHANGE_OR_HAS_ACTION(element) ||
!HAS_ANY_CHANGE_EVENT(element, trigger_event))
continue;
- for (j = 0; j < element_info[element].num_change_pages; j++)
+ for (p = 0; p < element_info[element].num_change_pages; p++)
{
- struct ElementChangeInfo *change = &element_info[element].change_page[j];
+ struct ElementChangeInfo *change = &element_info[element].change_page[p];
if (change->can_change_or_has_action &&
change->has_event[trigger_event] &&
change->actual_trigger_element = trigger_element;
change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
- if (change->can_change && !change_found)
+ if ((change->can_change && !change_done) || change->has_action)
{
- change_found = TRUE;
+ int x, y;
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
{
if (Feld[x][y] == element)
{
- ChangeDelay[x][y] = 1;
- ChangeEvent[x][y] = trigger_event;
- ChangeElement(x, y, j);
+ if (change->can_change && !change_done)
+ {
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = trigger_event;
+ ChangeElement(x, y, p);
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(x, y, element, p);
}
}
- }
- if (change->has_action)
- ExecuteCustomElementAction(element, j);
+ if (change->can_change)
+ {
+ change_done = TRUE;
+ change_done_any = TRUE;
+ }
+ }
}
}
}
- return TRUE;
+ return change_done_any;
}
static boolean CheckElementChangeExt(int x, int y,
int trigger_element,
int trigger_event,
int trigger_player,
- int trigger_side,
- int trigger_page)
+ int trigger_side)
{
- if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ boolean change_done = FALSE;
+ int p;
+
+ if (!CAN_CHANGE_OR_HAS_ACTION(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event))
return FALSE;
if (Feld[x][y] == EL_BLOCKED)
if (Feld[x][y] != element) /* check if element has already changed */
return FALSE;
- if (trigger_page < 0)
+ for (p = 0; p < element_info[element].num_change_pages; p++)
{
- boolean change_element = FALSE;
- int i;
+ struct ElementChangeInfo *change = &element_info[element].change_page[p];
- for (i = 0; i < element_info[element].num_change_pages; i++)
- {
- struct ElementChangeInfo *change = &element_info[element].change_page[i];
+ boolean check_trigger_element =
+ (trigger_event == CE_TOUCHING_X ||
+ trigger_event == CE_HITTING_X ||
+ trigger_event == CE_HIT_BY_X);
- boolean check_trigger_element =
- (trigger_event == CE_TOUCHING_X ||
- trigger_event == CE_HITTING_X ||
- trigger_event == CE_HIT_BY_X);
+ if (change->can_change_or_has_action &&
+ change->has_event[trigger_event] &&
+ change->trigger_side & trigger_side &&
+ change->trigger_player & trigger_player &&
+ (!check_trigger_element ||
+ IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)))
+ {
+ change->actual_trigger_element = trigger_element;
+ change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
- if (change->can_change &&
- change->has_event[trigger_event] &&
- change->trigger_side & trigger_side &&
- change->trigger_player & trigger_player &&
- (!check_trigger_element ||
- IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)))
+ if (change->can_change && !change_done)
{
- change_element = TRUE;
- trigger_page = i;
-
- change->actual_trigger_element = trigger_element;
- change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = trigger_event;
+ ChangeElement(x, y, p);
- break;
+ change_done = TRUE;
}
- }
- if (!change_element)
- return FALSE;
- }
- else
- {
- struct ElementInfo *ei = &element_info[element];
- struct ElementChangeInfo *change = &ei->change_page[trigger_page];
-
- change->actual_trigger_element = trigger_element;
- change->actual_trigger_player = EL_PLAYER_1; /* unused */
+ if (change->has_action)
+ ExecuteCustomElementAction(x, y, element, p);
+ }
}
- ChangeDelay[x][y] = 1;
- ChangeEvent[x][y] = trigger_event;
- ChangeElement(x, y, trigger_page);
-
- return TRUE;
+ return change_done;
}
static void PlayPlayerSound(struct PlayerInfo *player)
if (stored_player[i].MovPos != 0)
stored_player[i].StepFrame += move_frames;
-#if USE_NEW_MOVE_DELAY
if (stored_player[i].move_delay > 0)
stored_player[i].move_delay--;
-#endif
-#if USE_NEW_PUSH_DELAY
/* due to bugs in previous versions, counter must count up, not down */
if (stored_player[i].push_delay != -1)
stored_player[i].push_delay++;
-#endif
if (stored_player[i].drop_delay > 0)
stored_player[i].drop_delay--;
Changed[x][y] = FALSE;
ChangeEvent[x][y] = -1;
-#if USE_NEW_BLOCK_STYLE
/* this must be handled before main playfield loop */
if (Feld[x][y] == EL_PLAYER_IS_LEAVING)
{
if (MovDelay[x][y] <= 0)
RemoveField(x, y);
}
-#endif
#if DEBUG
if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1)
redraw_mask |= REDRAW_FPS;
}
-#if USE_NEW_MOVE_DELAY
AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */
-#else
- FrameCounter++;
- TimeFrames++;
-
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- int move_frames =
- MOVE_DELAY_NORMAL_SPEED / stored_player[i].move_delay_value;
-
- stored_player[i].Frame += move_frames;
-
- if (stored_player[i].MovPos != 0)
- stored_player[i].StepFrame += move_frames;
-
-#if USE_NEW_MOVE_DELAY
- if (stored_player[i].move_delay > 0)
- stored_player[i].move_delay--;
-#endif
-
- if (stored_player[i].drop_delay > 0)
- stored_player[i].drop_delay--;
- }
-#endif
if (local_player->show_envelope != 0 && local_player->MovPos == 0)
{
local_player->show_envelope = 0;
}
-#if USE_NEW_RANDOMIZE
/* use random number generator in every frame to make it less predictable */
if (game.engine_version >= VERSION_IDENT(3,1,1,0))
RND(1);
-#endif
}
static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
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]));
return FALSE;
}
-#if USE_NEW_MOVE_DELAY
if (player->move_delay > 0)
-#else
- if (!FrameReached(&player->move_delay, player->move_delay_value))
-#endif
- {
return FALSE;
- }
-#if USE_NEW_MOVE_DELAY
player->move_delay = -1; /* set to "uninitialized" value */
-#endif
/* store if player is automatically moved to next field */
player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
ScrollPlayer(player, SCROLL_GO_ON);
ScrollScreen(NULL, SCROLL_GO_ON);
-#if USE_NEW_MOVE_DELAY
AdvanceFrameAndPlayerCounters(player->index_nr);
-#else
- FrameCounter++;
-#endif
DrawAllPlayers();
BackToFront();
{
CheckGravityMovementWhenNotMoving(player);
- /*
- player->last_move_dir = MV_NO_MOVING;
- */
player->is_moving = FALSE;
-#if USE_NEW_MOVE_STYLE
- /* player is ALLOWED to move, but CANNOT move (something blocks his way) */
- /* ensure that the player is also allowed to move in the next frame */
- /* (currently, the player is forced to wait eight frames before he can try
- again!!!) */
+ /* at this point, the player is allowed to move, but cannot move right now
+ (e.g. because of something blocking the way) -- ensure that the player
+ is also allowed to move in the next frame (in old versions before 3.1.1,
+ the player was forced to wait again for eight frames before next try) */
if (game.engine_version >= VERSION_IDENT(3,1,1,0))
player->move_delay = 0; /* allow direct movement in the next frame */
-#endif
}
-#if USE_NEW_MOVE_DELAY
if (player->move_delay == -1) /* not yet initialized by DigField() */
player->move_delay = player->move_delay_value;
-#endif
if (game.engine_version < VERSION_IDENT(3,0,7,0))
{
player->actual_frame_counter = FrameCounter;
player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
-#if USE_NEW_BLOCK_STYLE
-
if ((player->block_last_field || player->block_delay_adjustment > 0) &&
Feld[last_jx][last_jy] == EL_EMPTY)
{
{
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) */
Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
MovDelay[last_jx][last_jy] = last_field_block_delay + 1;
}
-#else
-#if USE_NEW_MOVE_STYLE
- if ((game.engine_version < VERSION_IDENT(3,1,1,0) ||
- player->block_last_field) &&
- Feld[last_jx][last_jy] == EL_EMPTY)
- Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
-#else
- if (Feld[last_jx][last_jy] == EL_EMPTY)
- Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
-#endif
-#endif
return;
}
player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
-#if USE_NEW_BLOCK_STYLE
-#else
- if (!player->block_last_field &&
- Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
-
- RemoveField(last_jx, last_jy);
-#endif
-
/* before DrawPlayer() to draw correct player graphic for this case */
if (player->MovPos == 0)
CheckGravityMovement(player);
}
}
-#if USE_NEW_BLOCK_STYLE
-#else
- if (player->block_last_field &&
- Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
-
- RemoveField(last_jx, last_jy);
-#endif
-
player->last_jx = jx;
player->last_jy = jy;
CE_LEFT_BY_PLAYER,
player->index_bit, leave_side);
- CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
- CE_PLAYER_LEAVES_X,
+ CheckTriggeredElementChangeByPlayer(old_element, CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
if (IS_CUSTOM_ELEMENT(new_element))
CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
player->index_bit, enter_side);
- CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
- CE_PLAYER_ENTERS_X,
+ CheckTriggeredElementChangeByPlayer(new_element, CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
}
CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, border_side);
- CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
- CE_PLAYER_TOUCHES_X,
+ CheckTriggeredElementChangeByPlayer(border_element, CE_PLAYER_TOUCHES_X,
player->index_bit, border_side);
}
else if (IS_PLAYER(xx, yy))
CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
player->index_bit, center_side);
- CheckTriggeredElementChangeByPlayer(x, y, center_element,
- CE_PLAYER_TOUCHES_X,
+ CheckTriggeredElementChangeByPlayer(center_element, CE_PLAYER_TOUCHES_X,
player->index_bit, center_side);
break;
}
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 opposite_direction = MV_DIR_OPPOSITE(direction);
if (object_hit)
{
-#if !USE_HIT_BY_SOMETHING_BUGFIX
- CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
- CE_HIT_BY_SOMETHING, opposite_direction);
-#endif
-
CheckElementChangeBySide(x, y, hitting_element, touched_element,
CE_HITTING_X, touched_side);
CheckElementChangeBySide(hitx, hity, touched_element,
hitting_element, CE_HIT_BY_X, hitting_side);
-#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
int dig_side = MV_DIR_OPPOSITE(move_direction);
int old_element = Feld[jx][jy];
int element;
+ int collect_count;
if (is_player) /* function can also be called by EL_PENGUIN */
{
if (mode == DF_NO_PUSH) /* player just stopped pushing */
{
player->is_switching = FALSE;
-#if USE_NEW_PUSH_DELAY
player->push_delay = -1;
-#else
- player->push_delay = 0;
-#endif
return MF_NO_ACTION;
}
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
if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
return MF_NO_ACTION; /* field has no opening in this direction */
return MF_NO_ACTION; /* field has no opening in this direction */
element = Feld[x][y];
+#if USE_NEW_COLLECT_COUNT
+ collect_count = Count[x][y];
+#else
+ collect_count = element_info[element].collect_count_initial;
+#endif
+
+#if 0
+ if (element != EL_BLOCKED &&
+ Count[x][y] != element_info[element].collect_count_initial)
+ printf("::: %d: %d != %d\n",
+ element,
+ Count[x][y],
+ element_info[element].collect_count_initial);
+#endif
if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */
return MF_NO_ACTION;
PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_DIGS_X,
player->index_bit, dig_side);
if (mode == DF_SNAP)
{
int i;
- if (element_info[element].collect_count == 0)
+ if (collect_count == 0)
player->inventory_infinite_element = element;
else
- for (i = 0; i < element_info[element].collect_count; i++)
+ for (i = 0; i < collect_count; i++)
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
DrawGameValue_Dynamite(local_player->inventory_size);
}
- else if (element_info[element].collect_count > 0)
+ else if (collect_count > 0)
{
- local_player->gems_still_needed -=
- element_info[element].collect_count;
+ local_player->gems_still_needed -= collect_count;
if (local_player->gems_still_needed < 0)
local_player->gems_still_needed = 0;
PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
if (is_player)
- CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_PLAYER_COLLECTS_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_COLLECTS_X,
player->index_bit, dig_side);
if (mode == DF_SNAP)
if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
return MF_NO_ACTION;
-#if USE_NEW_PUSH_DELAY
if (player->push_delay == -1) /* new pushing; restart delay */
player->push_delay = 0;
-#else
- if (player->push_delay == 0) /* new pushing; restart delay */
- player->push_delay = FrameCounter;
-#endif
-#if USE_NEW_PUSH_DELAY
if (player->push_delay < player->push_delay_value &&
!(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
element != EL_SPRING && element != EL_BALLOON)
-#else
- if (!FrameReached(&player->push_delay, player->push_delay_value) &&
- !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
- element != EL_SPRING && element != EL_BALLOON)
-#endif
{
/* make sure that there is no move delay before next try to push */
-#if USE_NEW_MOVE_DELAY
if (game.engine_version >= VERSION_IDENT(3,0,7,1))
player->move_delay = 0;
-#else
- if (game.engine_version >= VERSION_IDENT(3,0,7,1))
- player->move_delay = INITIAL_MOVE_DELAY_OFF;
-#endif
return MF_NO_ACTION;
}
else
player->push_delay_value = -1; /* get new value later */
-#if USE_PUSH_BUGFIX
- /* now: check for element change _after_ element has been pushed! */
+ /* check for element change _after_ element has been pushed */
if (game.use_change_when_pushing_bug)
{
CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x,y, element, CE_PLAYER_PUSHES_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PUSHES_X,
player->index_bit, dig_side);
}
-
-#else
- /* check for element change _after_ element has been pushed! */
-#endif
}
else if (IS_SWITCHABLE(element))
{
if (PLAYER_SWITCHING(player, x, y))
{
- CheckTriggeredElementChangeByPlayer(x,y, element,
- CE_PLAYER_PRESSES_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
return MF_ACTION;
DrawLevelField(x, y);
}
- CheckTriggeredElementChangeByPlayer(x, y, element,
- CE_SWITCH_OF_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_SWITCH_OF_X,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
+ CheckTriggeredElementChangeByPlayer(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_SWITCH_OF_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_SWITCH_OF_X,
player->index_bit, dig_side);
}
CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
player->index_bit, dig_side);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
+ CheckTriggeredElementChangeByPlayer(element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
return MF_NO_ACTION;
}
-#if USE_NEW_PUSH_DELAY
player->push_delay = -1;
-#else
- player->push_delay = 0;
-#endif
-#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;
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))
{
CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
player->index_bit, drop_side);
- CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
- CE_PLAYER_DROPS_X,
+ CheckTriggeredElementChangeByPlayer(new_element, CE_PLAYER_DROPS_X,
player->index_bit, drop_side);
TestIfElementTouchesCustomElement(dropx, dropy);
player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
player->is_dropping = TRUE;
-#if USE_DROP_BUGFIX
player->drop_x = dropx;
player->drop_y = dropy;
-#endif
return TRUE;
}