#define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1)
#define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1)
#define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1)
+#define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1)
+#define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1)
#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0)
#define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \
RND((c)->delay_random))
+#if 1
+#define GET_VALID_RUNTIME_ELEMENT(e) \
+ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e))
+#else
+#define GET_VALID_FILE_ELEMENT(e) \
+ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e))
+#endif
+
#define GET_TARGET_ELEMENT(e, ch) \
- ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
- (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e))
+ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \
+ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
+ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : (e))
#define CAN_GROW_INTO(e) \
((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
#define ANDROID_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT)
+#define ANDROID_CAN_CLONE_FIELD(x, y) \
+ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \
+ CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT)))
+
#define ENEMY_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
(IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \
Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
+#if 0
#define GROUP_NR(e) ((e) - EL_GROUP_START)
-#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE)
#define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
#define IS_EQUAL_OR_IN_GROUP(e, ge) \
(IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
+#endif
+
+#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
#endif
static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
#define CheckTriggeredElementChange(x, y, e, ev) \
},
{
EL_DIAGONAL_SHRINKING,
- EL_EMPTY,
+ EL_UNDEFINED,
0,
NULL,
NULL,
},
{
EL_DIAGONAL_GROWING,
- EL_EMPTY,
+ EL_UNDEFINED,
0,
NULL,
NULL,
else
{
stored_player[0].use_murphy = TRUE;
+
+ if (!level.use_artwork_element[0])
+ stored_player[0].artwork_element = EL_SP_MURPHY;
}
Feld[x][y] = EL_PLAYER_1;
MovDelay[x][y] = 96;
break;
+ case EL_EM_DYNAMITE_ACTIVE:
+ MovDelay[x][y] = 32;
+ break;
+
case EL_LAMP:
local_player->lights_still_needed++;
break;
DrawGameValue_Keys(stored_player[i].key);
}
+#if 0
static void resolve_group_element(int group_element, int recursion_depth)
{
static int group_nr;
}
}
}
-
+#endif
/*
=============================================================================
printf(" => game.engine_version == %06d\n", game.engine_version);
#endif
+#if 0
/* ---------- recursively resolve group elements ------------------------- */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
resolve_group_element(EL_GROUP_START + i, 0);
+#endif
/* ---------- initialize player's initial move delay --------------------- */
game.envelope_active = FALSE;
+ game.centered_player_nr = game.centered_player_nr_next = -1; /* focus all */
+
for (i = 0; i < NUM_BELTS; i++)
{
game.belt_dir[i] = MV_NONE;
if (tape.playing)
{
- /* when playing a tape, eliminate all players which do not participate */
+ /* when playing a tape, eliminate all players who do not participate */
for (i = 0; i < MAX_PLAYERS; i++)
{
BackToFront();
+#if 0
+ if (tape.playing)
+ printf("::: TAPE PLAYING -> DO NOT SAVE SCORE\n");
+ else
+ printf("::: NO TAPE PLAYING -> SAVING SCORE\n");
+#endif
+
if (tape.playing)
return;
static void ResetGfxAnimation(int x, int y)
{
+#if 0
+ int element, graphic;
+#endif
+
GfxFrame[x][y] = 0;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MovDir[x][y];
+
+#if 0
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
void InitMovingField(int x, int y, int direction)
{
int element = Feld[x][y];
+#if 0
+ int graphic;
+#endif
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int newx = x + dx;
GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
ACTION_FALLING : ACTION_MOVING);
+#if 0
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
+
/* this is needed for CEs with property "can move" / "not moving" */
if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
Bang(x, y);
}
-void DrawRelocatePlayer(struct PlayerInfo *player)
+void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation)
{
boolean ffwd_delay = (tape.playing && tape.fast_forward);
boolean no_delay = (tape.warp_forward);
int jx = player->jx;
int jy = player->jy;
- if (level.instant_relocation)
+ if (quick_relocation)
{
int offset = (setup.scroll_delay ? 3 : 0);
if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
{
- scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
- local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
- local_player->jx - MIDPOSX);
+ scroll_x = (player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ player->jx - MIDPOSX);
- scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
- local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
- local_player->jy - MIDPOSY);
+ scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ player->jy - MIDPOSY);
}
else
{
int dx = 0, dy = 0;
int fx = FX, fy = FY;
- scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
- local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
- local_player->jx - MIDPOSX);
+ scroll_xx = (player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ player->jx - MIDPOSX);
- scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
- local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
- local_player->jy - MIDPOSY);
+ scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ player->jy - MIDPOSY);
dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
InitField(jx, jy, FALSE);
}
+#if 1
+ /* only visually relocate centered player */
+ if (player->index_nr == game.centered_player_nr)
+ DrawRelocatePlayer(player, level.instant_relocation);
+#else
if (player == local_player) /* only visually relocate local player */
- DrawRelocatePlayer(player);
+ DrawRelocatePlayer(player, level.instant_relocation);
+#endif
TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
Feld[x][y] = EL_EXPLOSION;
GfxElement[x][y] = artwork_element;
+#if 0
+ printf(":: setting gfx(%d,%d) to %d ['%s']\n",
+ x, y, artwork_element, EL_NAME(artwork_element));
+#endif
+
ExplodePhase[x][y] = 1;
ExplodeDelay[x][y] = last_phase;
#endif
#if 1
+#if 1
+ /* this can happen if the player leaves an explosion just in time */
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ GfxElement[x][y] = EL_EMPTY;
+#else
if (GfxElement[x][y] == EL_UNDEFINED)
{
printf("\n\n");
GfxElement[x][y] = EL_EMPTY;
}
+#endif
+
#endif
border_element = Store2[x][y];
{ -1, +1, MV_LEFT | MV_DOWN },
{ -1, 0, MV_LEFT },
};
- int check_order = (RND(2) ? -1 : +1);
- int start_pos = check_pos[MovDir[x][y] & 0x0f];
+ int start_pos, check_order;
+ boolean can_clone = FALSE;
int i;
- MovDelay[x][y] = level.android_move_time * 8 + 1;
+ /* check if there is any free field around current position */
+ for (i = 0; i < 8; i++)
+ {
+ int newx = x + check_xy[i].dx;
+ int newy = y + check_xy[i].dy;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+
+ if (can_clone) /* randomly find an element to clone */
+ {
+ can_clone = FALSE;
- if (start_pos < 0) /* (should never happen) */
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+
+ if (ANDROID_CAN_CLONE_FIELD(newx, newy))
+ {
+ element_info[element].move_leave_type = LEAVE_TYPE_LIMITED;
+ element_info[element].move_leave_element = EL_TRIGGER_ELEMENT;
+
+ Store[x][y] = Feld[newx][newy];
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* randomly find a direction to move */
+ {
+ can_clone = FALSE;
+
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+ int new_move_dir = check_xy[pos].dir;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_clone_time * 8 + 1;
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* cloning and moving successful */
return;
+ /* cannot clone -- try to move towards player */
+
+ start_pos = check_pos[MovDir[x][y] & 0x0f];
+ check_order = (RND(2) ? -1 : +1);
+
for (i = 0; i < 3; i++)
{
/* first check start_pos, then previous/next or (next/previous) pos */
int new_move_dir = check_xy[pos].dir;
if (IS_PLAYER(newx, newy))
- return;
+ break;
if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
{
MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_move_time * 8 + 1;
- return;
+ break;
}
}
}
static void TurnRound(int x, int y)
{
int direction = MovDir[x][y];
+#if 1
+ int element, graphic;
+#endif
TurnRoundExt(x, y);
if (MovDelay[x][y])
GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
static boolean JustBeingPushed(int x, int y)
else if (CAN_MOVE_INTO_ACID(element) &&
IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+ !IS_MV_DIAGONAL(MovDir[x][y]) &&
(MovDir[x][y] == MV_DOWN ||
game.engine_version >= VERSION_IDENT(3,1,0,0)))
{
}
else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy))
{
- if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL &&
- ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ if (Store[x][y] != EL_EMPTY)
{
- int diagonal_move_dir = MovDir[x][y];
- int change_delay = 8;
- int graphic;
+ boolean can_clone = FALSE;
+ int xx, yy;
+
+ /* check if element to clone is still there */
+ for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++)
+ {
+ if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y])
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
- /* android is moving diagonally */
+ /* cannot clone or target field not free anymore -- do not clone */
+ if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ Store[x][y] = EL_EMPTY;
+ }
- CreateField(x, y, EL_DIAGONAL_SHRINKING);
+ if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ {
+ if (IS_MV_DIAGONAL(MovDir[x][y]))
+ {
+ int diagonal_move_dir = MovDir[x][y];
+ int stored = Store[x][y];
+ int change_delay = 8;
+ int graphic;
- GfxElement[x][y] = EL_EMC_ANDROID;
- GfxAction[x][y] = ACTION_SHRINKING;
- GfxDir[x][y] = diagonal_move_dir;
- ChangeDelay[x][y] = change_delay;
+ /* android is moving diagonally */
- graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
- GfxDir[x][y]);
+ CreateField(x, y, EL_DIAGONAL_SHRINKING);
- DrawLevelGraphicAnimation(x, y, graphic);
- PlayLevelSoundAction(x, y, ACTION_SHRINKING);
+ Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored);
+ GfxElement[x][y] = EL_EMC_ANDROID;
+ GfxAction[x][y] = ACTION_SHRINKING;
+ GfxDir[x][y] = diagonal_move_dir;
+ ChangeDelay[x][y] = change_delay;
-#if 0
- CheckTriggeredElementChangeBySide(x, y, element,
- CE_MOVE_OF_X, new_move_dir);
+ graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
+ GfxDir[x][y]);
- TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+ DrawLevelGraphicAnimation(x, y, graphic);
+ PlayLevelSoundAction(x, y, ACTION_SHRINKING);
- TestIfElementHitsCustomElement(newx, newy, new_move_dir);
- TestIfElementTouchesCustomElement(newx, newy);
-#endif
+ if (Feld[newx][newy] == EL_ACID)
+ {
+ SplashAcid(newx, newy);
- CreateField(newx, newy, EL_DIAGONAL_GROWING);
+ return;
+ }
- Store[newx][newy] = EL_EMC_ANDROID;
- GfxElement[newx][newy] = EL_EMC_ANDROID;
- GfxAction[newx][newy] = ACTION_GROWING;
- GfxDir[newx][newy] = diagonal_move_dir;
- ChangeDelay[newx][newy] = change_delay;
+ CreateField(newx, newy, EL_DIAGONAL_GROWING);
- graphic = el_act_dir2img(GfxElement[newx][newy], GfxAction[newx][newy],
- GfxDir[newx][newy]);
+ Store[newx][newy] = EL_EMC_ANDROID;
+ GfxElement[newx][newy] = EL_EMC_ANDROID;
+ GfxAction[newx][newy] = ACTION_GROWING;
+ GfxDir[newx][newy] = diagonal_move_dir;
+ ChangeDelay[newx][newy] = change_delay;
- DrawLevelGraphicAnimation(newx, newy, graphic);
- PlayLevelSoundAction(newx, newy, ACTION_GROWING);
+ graphic = el_act_dir2img(GfxElement[newx][newy],
+ GfxAction[newx][newy], GfxDir[newx][newy]);
- return;
- }
- else if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
- {
- Feld[newx][newy] = EL_EMPTY;
- DrawLevelField(newx, newy);
+ DrawLevelGraphicAnimation(newx, newy, graphic);
+ PlayLevelSoundAction(newx, newy, ACTION_GROWING);
- PlayLevelSoundAction(x, y, ACTION_DIGGING);
+ return;
+ }
+ else
+ {
+ Feld[newx][newy] = EL_EMPTY;
+ DrawLevelField(newx, newy);
+
+ PlayLevelSoundAction(x, y, ACTION_DIGGING);
+ }
}
else if (!IS_FREE(newx, newy))
{
Pushed[x][y] = Pushed[newx][newy] = FALSE;
/* some elements can leave other elements behind after moving */
+#if 1
+ if (ei->move_leave_element != EL_EMPTY &&
+ (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
+ (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#else
if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
(ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
(!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#endif
{
int move_leave_element = ei->move_leave_element;
+#if 1
#if 1
+ /* this makes it possible to leave the removed element again */
+ if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+ move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored);
+#else
/* this makes it possible to leave the removed element again */
if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
move_leave_element = stored;
+#endif
#else
/* this makes it possible to leave the removed element again */
if (ei->move_leave_type == LEAVE_TYPE_LIMITED &&
TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+#if 0
+ if (ChangePage[newx][newy] != -1) /* delayed change */
+ {
+ int page = ChangePage[newx][newy];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+
+ ChangePage[newx][newy] = -1;
+
+ if (change->can_change)
+ {
+ if (ChangeElement(newx, newy, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(newx, newy);
+ }
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(newx, newy, element, page);
+ }
+#endif
+
TestIfElementHitsCustomElement(newx, newy, direction);
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0], yy = y + xy[i][1];
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
- if (IS_PLAYER(xx, yy))
+ if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
{
PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
- action_arg == CA_ARG_ELEMENT_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
- action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_ce_value :
+ action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
+ action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
+ action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element :
+ action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element :
-1);
int action_arg_number_old =
CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
+#if 0
+ printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
+#endif
}
#endif
static void CreateElementFromChange(int x, int y, int element)
{
+ element = GET_VALID_RUNTIME_ELEMENT(element);
+
+#if USE_STOP_CHANGED_ELEMENTS
+ if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+ {
+ int old_element = Feld[x][y];
+
+ /* prevent changed element from moving in same engine frame
+ unless both old and new element can either fall or move */
+ if ((!CAN_FALL(old_element) || !CAN_FALL(element)) &&
+ (!CAN_MOVE(old_element) || !CAN_MOVE(element)))
+ Stop[x][y] = TRUE;
+ }
+#endif
+
CreateFieldExt(x, y, element, TRUE);
}
{
target_element = GET_TARGET_ELEMENT(change->target_element, change);
- if (element == EL_DIAGONAL_GROWING)
+ if (element == EL_DIAGONAL_GROWING ||
+ element == EL_DIAGONAL_SHRINKING)
+ {
target_element = Store[x][y];
+ Store[x][y] = EL_EMPTY;
+ }
+
CreateElementFromChange(x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
element = Feld[x][y];
}
- if (Feld[x][y] != element) /* check if element has already changed */
+#if 0
+ /* check if element has already changed */
+ if (Feld[x][y] != element)
return FALSE;
+#else
+ /* check if element has already changed or is about to change after moving */
+ if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
+ Feld[x][y] != element) ||
+
+ (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+ (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+ ChangePage[x][y] != -1)))
+ return FALSE;
+#endif
for (p = 0; p < element_info[element].num_change_pages; p++)
{
InitPlayfieldScanModeVars();
+ if (ScreenMovPos == 0) /* screen currently aligned at tile position */
+ {
+ struct PlayerInfo *player;
+ int player_nr = game.centered_player_nr_next;
+
+ if (game.centered_player_nr_next == -1)
+ player_nr = local_player->index_nr;
+
+ player = &stored_player[player_nr];
+
+ if (!player->active)
+ game.centered_player_nr_next = game.centered_player_nr;
+
+ if (game.centered_player_nr != game.centered_player_nr_next)
+ {
+ DrawRelocatePlayer(player, setup.quick_switch);
+
+ game.centered_player_nr = game.centered_player_nr_next;
+ }
+ }
+
#if USE_ONE_MORE_CHANGE_PER_FRAME
if (game.engine_version >= VERSION_IDENT(3,2,0,7))
{
#endif
}
+#if 1
+ if (!options.network && game.centered_player_nr == -1 &&
+ !AllPlayersInSight(player, new_jx, new_jy))
+ return MP_NO_ACTION;
+#else
if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
return MP_NO_ACTION;
+#endif
#if !USE_FIXED_DONT_RUN_INTO
element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
jx = player->jx;
jy = player->jy;
+#if 1
+ if (moved & MP_MOVING && !ScreenMovPos &&
+ (player->index_nr == game.centered_player_nr ||
+ game.centered_player_nr == -1))
+#else
if (moved & MP_MOVING && !ScreenMovPos &&
(player == local_player || !options.network))
+#endif
{
int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
int offset = (setup.scroll_delay ? 3 : 0);
if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
{
+#if 1
+ if (!options.network && game.centered_player_nr == -1 &&
+ !AllPlayersInVisibleScreen())
+ {
+ scroll_x = old_scroll_x;
+ scroll_y = old_scroll_y;
+ }
+ else
+#else
if (!options.network && !AllPlayersInVisibleScreen())
{
scroll_x = old_scroll_x;
scroll_y = old_scroll_y;
}
else
+#endif
{
ScrollScreen(player, SCROLL_INIT);
ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
}
}
+#if USE_ELEMENT_TOUCHING_BUGFIX
+
void TestIfElementTouchesCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_sides[4][2] =
+ {
+ /* center side border side */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */
+ };
+ static int touch_dir[4] =
+ {
+ MV_LEFT | MV_RIGHT,
+ MV_UP | MV_DOWN,
+ MV_UP | MV_DOWN,
+ MV_LEFT | MV_RIGHT
+ };
+ boolean change_center_element = FALSE;
+ int center_element = Feld[x][y]; /* should always be non-moving! */
+ int border_element_old[NUM_DIRECTIONS];
+ int i;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_element;
+
+ border_element_old[i] = -1;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (game.engine_version < VERSION_IDENT(3,0,7,0))
+ border_element = Feld[xx][yy]; /* may be moving! */
+ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+ border_element = Feld[xx][yy];
+ else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */
+ border_element = MovingOrBlocked2Element(xx, yy);
+ else
+ continue; /* center and border element do not touch */
+
+ border_element_old[i] = border_element;
+ }
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int center_side = trigger_sides[i][0];
+ int border_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of border element */
+ CheckElementChangeBySide(xx, yy, border_element, center_element,
+ CE_TOUCHING_X, center_side);
+ }
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int border_side = trigger_sides[i][1];
+ int border_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of center element (but change it only once) */
+ if (!change_center_element)
+ change_center_element =
+ CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_TOUCHING_X, border_side);
+ }
+}
+
+#else
+
+void TestIfElementTouchesCustomElement_OLD(int x, int y)
{
static int xy[4][2] =
{
}
}
+#endif
+
void TestIfElementHitsCustomElement(int x, int y, int direction)
{
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
if (element == EL_SHIELD_DEADLY)
player->shield_deadly_time_left += level.shield_deadly_time;
}
- else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED)
+ else if (element == EL_DYNAMITE ||
+ element == EL_EM_DYNAMITE ||
+ element == EL_SP_DISK_RED)
{
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
if (new_element == EL_DYNAMITE)
new_element = EL_DYNAMITE_ACTIVE;
+ else if (new_element == EL_EM_DYNAMITE)
+ new_element = EL_EM_DYNAMITE_ACTIVE;
else if (new_element == EL_SP_DISK_RED)
new_element = EL_SP_DISK_RED_ACTIVE;
}
break;
case SAMPLE_slurp:
- PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_EATING);
break;
case SAMPLE_eater:
RaiseScore(level.score[SC_NUT]);
break;
case EL_DYNAMITE:
+ case EL_EM_DYNAMITE:
case EL_SP_DISK_RED:
case EL_DYNABOMB_INCREASE_NUMBER:
case EL_DYNABOMB_INCREASE_SIZE: