X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=7b225c5eac9621eb61e6ee2dc195b16d6a4b4c76;hb=0ae305660baec1a7568ac7df7f296b695904d59a;hp=1f3b8e02fb64939b490c64c05318e8f3220ce748;hpb=e1feae09b7599525167992970fcc1c731214cc97;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 1f3b8e02..7b225c5e 100644 --- a/src/game.c +++ b/src/game.c @@ -101,11 +101,20 @@ #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ (element_info[e].move_delay_random)) +#if 1 +#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \ + (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ + (condition) || \ + (DONT_COLLIDE_WITH(e) && \ + IS_PLAYER(x, y) && \ + !PLAYER_PROTECTED(x, y)))) +#else #define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition) || \ (DONT_COLLIDE_WITH(e) && \ IS_FREE_OR_PLAYER(x, y)))) +#endif #define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ @@ -144,6 +153,7 @@ Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_ACID)) +#if 0 #if 1 #define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \ (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) @@ -152,6 +162,32 @@ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ IS_FOOD_DARK_YAMYAM(Feld[x][y]))) #endif +#endif + +#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)) + +#if 1 +#define CE_ENTER_FIELD_COND(e, x, y) \ + (!IS_PLAYER(x, y) && \ + (Feld[x][y] == EL_ACID || \ + IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))) +#else +#define CE_ENTER_FIELD_COND(e, x, y) \ + (!IS_PLAYER(x, y) && \ + (Feld[x][y] == EL_ACID || \ + Feld[x][y] == MOVE_ENTER_EL(e) || \ + (IS_GROUP_ELEMENT(MOVE_ENTER_EL(e)) && \ + IS_IN_GROUP_EL(Feld[x][y], MOVE_ENTER_EL(e))))) +#endif + +#define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) #define MOLE_CAN_ENTER_FIELD(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition))) @@ -609,6 +645,18 @@ static void InitField(int x, int y, boolean init_game) InitPlayerField(x, y, element, init_game); break; + case EL_SOKOBAN_FIELD_PLAYER: + element = Feld[x][y] = EL_PLAYER_1; + InitField(x, y, init_game); + + element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY; + InitField(x, y, init_game); + break; + + case EL_SOKOBAN_FIELD_EMPTY: + local_player->sokobanfields_still_needed++; + break; + case EL_STONEBLOCK: if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID) Feld[x][y] = EL_ACID_POOL_TOPLEFT; @@ -686,10 +734,6 @@ static void InitField(int x, int y, boolean init_game) local_player->lights_still_needed++; break; - case EL_SOKOBAN_FIELD_EMPTY: - local_player->sokobanfields_still_needed++; - break; - case EL_PENGUIN: local_player->friends_still_needed++; break; @@ -766,9 +810,22 @@ static void InitField(int x, int y, boolean init_game) else if (IS_GROUP_ELEMENT(element)) { struct ElementGroupInfo *group = element_info[element].group; - int random_pos = RND(group->num_elements_resolved); + int last_anim_random_frame = gfx.anim_random_frame; + int element_pos; + + if (group->choice_mode == ANIM_RANDOM) + gfx.anim_random_frame = RND(group->num_elements_resolved); + + element_pos = getAnimationFrame(group->num_elements_resolved, 1, + group->choice_mode, 0, + group->choice_pos); + + if (group->choice_mode == ANIM_RANDOM) + gfx.anim_random_frame = last_anim_random_frame; - Feld[x][y] = group->element_resolved[random_pos]; + group->choice_pos++; + + Feld[x][y] = group->element_resolved[element_pos]; InitField(x, y, init_game); } @@ -817,8 +874,10 @@ static void resolve_group_element(int group_element, int recursion_depth) if (recursion_depth == 0) /* initialization */ { group = element_info[group_element].group; - group->num_elements_resolved = 0; group_nr = group_element - EL_GROUP_START; + + group->num_elements_resolved = 0; + group->choice_pos = 0; } for (i = 0; i < actual_group->num_elements; i++) @@ -1004,7 +1063,16 @@ static void InitGameEngine() { int trigger_element = ei->change_page[j].trigger_element; - trigger_events[trigger_element] |= ei->change_page[j].events; + 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; + } + else + trigger_events[trigger_element] |= ei->change_page[j].events; } } } @@ -1052,6 +1120,14 @@ static void InitGameEngine() element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; } + /* ---------- initialize move dig/leave ---------------------------------- */ + + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + { + element_info[i].can_leave_element = FALSE; + element_info[i].can_leave_element_last = FALSE; + } + /* ---------- initialize gem count --------------------------------------- */ /* initialize gem count values for each element */ @@ -1345,7 +1421,9 @@ void InitGame() { player->present = TRUE; player->active = TRUE; + some_player->present = FALSE; + some_player->active = FALSE; StorePlayer[jx][jy] = player->element_nr; player->jx = player->last_jx = jx; @@ -1359,7 +1437,7 @@ void InitGame() if (tape.playing) { - /* when playing a tape, eliminate all players who do not participate */ + /* when playing a tape, eliminate all players which do not participate */ for (i = 0; i < MAX_PLAYERS; i++) { @@ -1390,6 +1468,8 @@ void InitGame() int jx = player->jx, jy = player->jy; player->active = FALSE; + player->present = FALSE; + StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } @@ -1690,23 +1770,37 @@ void InitMovDir(int x, int y) default: if (IS_CUSTOM_ELEMENT(element)) { - if (element_info[element].move_direction_initial != MV_NO_MOVING) - MovDir[x][y] = element_info[element].move_direction_initial; - else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS || - element_info[element].move_pattern == MV_TURNING_LEFT || - element_info[element].move_pattern == MV_TURNING_RIGHT || - element_info[element].move_pattern == MV_TURNING_LEFT_RIGHT || - element_info[element].move_pattern == MV_TURNING_RIGHT_LEFT || - element_info[element].move_pattern == MV_TURNING_RANDOM) + struct ElementInfo *ei = &element_info[element]; + int move_direction_initial = ei->move_direction_initial; + int move_pattern = ei->move_pattern; + + if (move_direction_initial == MV_PREVIOUS) + { + if (MovDir[x][y] != MV_NO_MOVING) + return; + + move_direction_initial = MV_AUTOMATIC; + } + + if (move_direction_initial == MV_RANDOM) MovDir[x][y] = 1 << RND(4); - else if (element_info[element].move_pattern == MV_HORIZONTAL) + else if (move_direction_initial & MV_ANY_DIRECTION) + MovDir[x][y] = move_direction_initial; + else if (move_pattern == MV_ALL_DIRECTIONS || + move_pattern == MV_TURNING_LEFT || + move_pattern == MV_TURNING_RIGHT || + move_pattern == MV_TURNING_LEFT_RIGHT || + move_pattern == MV_TURNING_RIGHT_LEFT || + move_pattern == MV_TURNING_RANDOM) + MovDir[x][y] = 1 << RND(4); + else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); - else if (element_info[element].move_pattern == MV_VERTICAL) + else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); - else if (element_info[element].move_pattern & MV_ANY_DIRECTION) + else if (move_pattern & MV_ANY_DIRECTION) MovDir[x][y] = element_info[element].move_pattern; - else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE || - element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE) + else if (move_pattern == MV_ALONG_LEFT_SIDE || + move_pattern == MV_ALONG_RIGHT_SIDE) { for (i = 0; i < 4; i++) { @@ -1715,7 +1809,7 @@ void InitMovDir(int x, int y) if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1)) { - if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE) + if (move_pattern == MV_ALONG_RIGHT_SIDE) MovDir[x][y] = direction[0][i]; else MovDir[x][y] = direction[1][i]; @@ -2424,17 +2518,17 @@ void Explode(int ex, int ey, int phase, int mode) switch(StorePlayer[ex][ey]) { case EL_PLAYER_2: - Store[x][y] = EL_EMERALD_RED; + Store[x][y] = EL_PLAYER_IS_EXPLODING_2; break; case EL_PLAYER_3: - Store[x][y] = EL_EMERALD; + Store[x][y] = EL_PLAYER_IS_EXPLODING_3; break; case EL_PLAYER_4: - Store[x][y] = EL_EMERALD_PURPLE; + Store[x][y] = EL_PLAYER_IS_EXPLODING_4; break; case EL_PLAYER_1: default: - Store[x][y] = EL_EMERALD_YELLOW; + Store[x][y] = EL_PLAYER_IS_EXPLODING_1; break; } @@ -2581,6 +2675,17 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = Store2[x][y] = 0; GfxElement[x][y] = EL_UNDEFINED; + /* player can escape from explosions and might therefore be still alive */ + if (element >= EL_PLAYER_IS_EXPLODING_1 && + element <= EL_PLAYER_IS_EXPLODING_4) + Feld[x][y] = (stored_player[element - EL_PLAYER_IS_EXPLODING_1].active ? + EL_EMPTY : + element == EL_PLAYER_IS_EXPLODING_1 ? EL_EMERALD_YELLOW : + element == EL_PLAYER_IS_EXPLODING_2 ? EL_EMERALD_RED : + element == EL_PLAYER_IS_EXPLODING_3 ? EL_EMERALD : + EL_EMERALD_PURPLE); + + /* restore probably existing indestructible background element */ if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y])) element = Feld[x][y] = Back[x][y]; Back[x][y] = 0; @@ -2591,8 +2696,11 @@ void Explode(int ex, int ey, int phase, int mode) ChangePage[x][y] = -1; InitField(x, y, FALSE); +#if 1 + /* !!! not needed !!! */ if (CAN_MOVE(element)) InitMovDir(x, y); +#endif DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); @@ -3258,11 +3366,13 @@ void Impact(int x, int y) return; } } - else if ((element == EL_SP_INFOTRON || - element == EL_SP_ZONK) && - (smashed == EL_SP_SNIKSNAK || - smashed == EL_SP_ELECTRON || - smashed == EL_SP_DISK_ORANGE)) + else if (((element == EL_SP_INFOTRON || + element == EL_SP_ZONK) && + (smashed == EL_SP_SNIKSNAK || + smashed == EL_SP_ELECTRON || + smashed == EL_SP_DISK_ORANGE)) || + (element == EL_SP_INFOTRON && + smashed == EL_SP_DISK_YELLOW)) { Bang(x, y + 1); return; @@ -3793,8 +3903,10 @@ inline static void TurnRoundExt(int x, int y) move_pattern == MV_TURNING_RANDOM || move_pattern == MV_ALL_DIRECTIONS) { - boolean can_turn_left = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); - boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); + boolean can_turn_left = + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); + boolean can_turn_right = + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; @@ -3838,9 +3950,9 @@ inline static void TurnRoundExt(int x, int y) } else if (move_pattern == MV_ALONG_LEFT_SIDE) { - if (ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) + if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; - else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) + else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) @@ -3848,9 +3960,9 @@ inline static void TurnRoundExt(int x, int y) } else if (move_pattern == MV_ALONG_RIGHT_SIDE) { - if (ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) + if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; - else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) + else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = left_dir; if (MovDir[x][y] != old_move_dir) @@ -3910,14 +4022,14 @@ inline static void TurnRoundExt(int x, int y) new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy)) + if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy)) + if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) return; MovDir[x][y] = old_move_dir; @@ -3931,8 +4043,7 @@ inline static void TurnRoundExt(int x, int y) MovDelay[x][y] = 0; } - else if (move_pattern & MV_MAZE_RUNNER_STYLE || - element == EL_MAZE_RUNNER) + else if (move_pattern & MV_MAZE_RUNNER_STYLE) { static int test_xy[7][2] = { @@ -3976,7 +4087,7 @@ inline static void TurnRoundExt(int x, int y) break; } - if (!MAZE_RUNNER_CAN_ENTER_FIELD(xx, yy)) + if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy)) continue; move_dir_preference = -1 * RunnerVisit[xx][yy]; @@ -4580,6 +4691,7 @@ void StartMoving(int x, int y) { #if 1 TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]); + return; #else /* player killed by element which is deadly when colliding with */ @@ -4638,6 +4750,7 @@ void StartMoving(int x, int y) DrawPlayerField(x, y); else DrawLevelField(x, y); + return; } } @@ -4661,42 +4774,80 @@ void StartMoving(int x, int y) DrawPlayerField(x, y); else DrawLevelField(x, y); + return; } } - else if ((move_pattern & MV_MAZE_RUNNER_STYLE || - element == EL_MAZE_RUNNER) && IN_LEV_FIELD(newx, newy)) - { + #if 1 - if (IS_FREE(newx, newy)) -#else - if (IS_FOOD_DARK_YAMYAM(Feld[newx][newy])) + + /* + else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy)) + */ + + else if (IS_CUSTOM_ELEMENT(element) && + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy) + +#if 0 + && + !IS_FREE(newx, newy) +#endif + +) + { + int new_element = Feld[newx][newy]; + +#if 0 + printf("::: '%s' digs '%s' [%d]\n", + element_info[element].token_name, + element_info[Feld[newx][newy]].token_name, + StorePlayer[newx][newy]); #endif + + if (!IS_FREE(newx, newy)) { + int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING : + IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING : + ACTION_BREAKING); + + /* no element can dig solid indestructible elements */ + if (IS_INDESTRUCTIBLE(new_element) && + !IS_DIGGABLE(new_element) && + !IS_COLLECTIBLE(new_element)) + return; + + if (AmoebaNr[newx][newy] && + (new_element == EL_AMOEBA_FULL || + new_element == EL_BD_AMOEBA || + new_element == EL_AMOEBA_GROWING)) + { + AmoebaCnt[AmoebaNr[newx][newy]]--; + AmoebaCnt2[AmoebaNr[newx][newy]]--; + } + if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); else { - Feld[newx][newy] = EL_EMPTY; + RemoveField(newx, newy); DrawLevelField(newx, newy); } - PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING); + PlayLevelSoundAction(x, y, action); } - else if (!IS_FREE(newx, newy)) + + if (new_element == element_info[element].move_enter_element) + element_info[element].can_leave_element = TRUE; + + if (move_pattern & MV_MAZE_RUNNER_STYLE) { -#if 0 - if (IS_PLAYER(x, y)) - DrawPlayerField(x, y); - else - DrawLevelField(x, y); -#endif - return; + RunnerVisit[x][y] = FrameCounter; + PlayerVisit[x][y] /= 8; /* expire player visit path */ } - - RunnerVisit[x][y] = FrameCounter; - PlayerVisit[x][y] /= 8; /* expire player visit path */ } + +#endif + else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy)) { if (!IS_FREE(newx, newy)) @@ -4804,6 +4955,7 @@ void StartMoving(int x, int y) DrawLevelField(x, y); MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ + return; /* wait for shrinking amoeba */ } else /* element == EL_PACMAN */ @@ -4867,6 +5019,7 @@ void StartMoving(int x, int y) void ContinueMoving(int x, int y) { int element = Feld[x][y]; + struct ElementInfo *ei = &element_info[element]; int direction = MovDir[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); @@ -4983,6 +5136,24 @@ void ContinueMoving(int x, int y) ResetGfxAnimation(x, y); /* reset animation values for old field */ +#if 1 + /* some elements can leave other elements behind after moving */ + if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && + ei->move_leave_element != EL_EMPTY && + (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || + ei->can_leave_element_last)) + { + Feld[x][y] = ei->move_leave_element; + InitField(x, y, FALSE); + + if (GFX_CRUMBLED(Feld[x][y])) + DrawLevelFieldCrumbledSandNeighbours(x, y); + } + + ei->can_leave_element_last = ei->can_leave_element; + ei->can_leave_element = FALSE; +#endif + #if 0 /* 2.1.1 (does not work correctly for spring) */ if (!CAN_MOVE(element)) @@ -5042,7 +5213,7 @@ void ContinueMoving(int x, int y) Impact(x, newy); #if 1 - TestIfElementTouchesCustomElement(x, y); /* for empty space */ + TestIfElementTouchesCustomElement(x, y); /* empty or new element */ #endif #if 0 @@ -6034,6 +6205,8 @@ static void ChangeActiveTrap(int x, int y) static void ChangeElementNowExt(int x, int y, int target_element) { + int previous_move_direction = MovDir[x][y]; + /* check if element under player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y) && @@ -6051,6 +6224,9 @@ static void ChangeElementNowExt(int x, int y, int target_element) ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); + if (element_info[Feld[x][y]].move_direction_initial == MV_PREVIOUS) + MovDir[x][y] = previous_move_direction; + InitField(x, y, FALSE); if (CAN_MOVE(Feld[x][y])) InitMovDir(x, y); @@ -6290,7 +6466,12 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, change->events & CH_EVENT_BIT(trigger_event) && #endif change->sides & trigger_side && - change->trigger_element == trigger_element) +#if 1 + IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element) +#else + change->trigger_element == trigger_element +#endif + ) { #if 0 if (!(change->events & CH_EVENT_BIT(trigger_event))) @@ -7369,6 +7550,38 @@ void ScrollLevel(int dx, int dy) redraw_mask |= REDRAW_FIELD; } +static boolean canEnterSupaplexPort(int x, int y, int dx, int dy) +{ + int nextx = x + dx, nexty = y + dy; + int element = Feld[x][y]; + + if ((dx == -1 && + element != EL_SP_PORT_LEFT && + element != EL_SP_GRAVITY_PORT_LEFT && + element != EL_SP_PORT_HORIZONTAL && + element != EL_SP_PORT_ANY) || + (dx == +1 && + element != EL_SP_PORT_RIGHT && + element != EL_SP_GRAVITY_PORT_RIGHT && + element != EL_SP_PORT_HORIZONTAL && + element != EL_SP_PORT_ANY) || + (dy == -1 && + element != EL_SP_PORT_UP && + element != EL_SP_GRAVITY_PORT_UP && + element != EL_SP_PORT_VERTICAL && + element != EL_SP_PORT_ANY) || + (dy == +1 && + element != EL_SP_PORT_DOWN && + element != EL_SP_GRAVITY_PORT_DOWN && + element != EL_SP_PORT_VERTICAL && + element != EL_SP_PORT_ANY) || + !IN_LEV_FIELD(nextx, nexty) || + !IS_FREE(nextx, nexty)) + return FALSE; + + return TRUE; +} + static void CheckGravityMovement(struct PlayerInfo *player) { if (game.gravity && !player->programmed_action) @@ -7388,7 +7601,9 @@ static void CheckGravityMovement(struct PlayerInfo *player) boolean player_is_moving_to_valid_field = (IN_LEV_FIELD(new_jx, new_jy) && (Feld[new_jx][new_jy] == EL_SP_BASE || - Feld[new_jx][new_jy] == EL_SAND)); + Feld[new_jx][new_jy] == EL_SAND || + (IS_SP_PORT(Feld[new_jx][new_jy]) && + canEnterSupaplexPort(new_jx, new_jy, dx, dy)))); /* !!! extend EL_SAND to anything diggable !!! */ if (field_under_player_is_free && @@ -8019,7 +8234,12 @@ void TestIfElementTouchesCustomElement(int x, int y) if (change->can_change && change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && change->sides & border_side && - change->trigger_element == border_element) +#if 1 + IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element) +#else + change->trigger_element == border_element +#endif + ) { change_center_element = TRUE; center_element_change_page = j; @@ -8041,7 +8261,12 @@ void TestIfElementTouchesCustomElement(int x, int y) if (change->can_change && change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && change->sides & center_side && - change->trigger_element == center_element) +#if 1 + IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element) +#else + change->trigger_element == center_element +#endif + ) { CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY, CE_OTHER_IS_TOUCHING, j); @@ -8121,7 +8346,13 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) if (change->can_change && change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) && change->sides & touched_side && - change->trigger_element == touched_element) + +#if 1 + IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element) +#else + change->trigger_element == touched_element +#endif + ) { CheckElementSideChange(x, y, hitting_element, CH_SIDE_ANY, CE_OTHER_IS_HITTING, i); @@ -8141,7 +8372,12 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) if (change->can_change && change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) && change->sides & hitting_side && - change->trigger_element == hitting_element) +#if 1 + IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element) +#else + change->trigger_element == hitting_element +#endif + ) { CheckElementSideChange(hitx, hity, touched_element, CH_SIDE_ANY, CE_OTHER_GETS_HIT, i); @@ -8570,6 +8806,10 @@ int DigField(struct PlayerInfo *player, case EL_SP_GRAVITY_PORT_RIGHT: case EL_SP_GRAVITY_PORT_UP: case EL_SP_GRAVITY_PORT_DOWN: +#if 1 + if (!canEnterSupaplexPort(x, y, dx, dy)) + return MF_NO_ACTION; +#else if ((dx == -1 && element != EL_SP_PORT_LEFT && element != EL_SP_GRAVITY_PORT_LEFT && @@ -8593,6 +8833,7 @@ int DigField(struct PlayerInfo *player, !IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) return MF_NO_ACTION; +#endif if (element == EL_SP_GRAVITY_PORT_LEFT || element == EL_SP_GRAVITY_PORT_RIGHT || @@ -9294,7 +9535,7 @@ boolean DropElement(struct PlayerInfo *player) int move_stepsize = element_info[new_element].move_stepsize; int direction, dx, dy, nextx, nexty; - if (element_info[new_element].move_direction_initial == MV_NO_MOVING) + if (element_info[new_element].move_direction_initial == MV_AUTOMATIC) MovDir[jx][jy] = player->MovDir; direction = MovDir[jx][jy];