X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=b1254556955778c3d660d44bc45a19d023a1c171;hb=f5665efaa42ea2570819237740046ff1360c4ef6;hp=6e8c99afe00b802289370fd0c1c12c3ecd3ff7ce;hpb=63203a78d8643ed30964afe3f1bfe72d17562e88;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 6e8c99af..b1254556 100644 --- a/src/game.c +++ b/src/game.c @@ -111,6 +111,9 @@ ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e)) +#define CAN_GROW_INTO(e) \ + (e == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) + #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition))) @@ -996,9 +999,10 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) /* this case is in fact a combination of not less than three bugs: first, it calls InitMovDir() for elements that can move, although this is already done by InitField(); then, it checks the element that was at this - field _before_ the call to InitField() (which can change it) - - */ + field _before_ the call to InitField() (which can change it); lastly, it + was not called for "mole with direction" elements, which were treated as + "cannot move" due to (fixed) wrong element initialization in "src/init.c" + */ } inline void DrawGameValue_Emeralds(int value) @@ -1486,6 +1490,7 @@ void InitGame() player->is_waiting = FALSE; player->is_moving = FALSE; + player->is_auto_moving = FALSE; player->is_digging = FALSE; player->is_snapping = FALSE; player->is_collecting = FALSE; @@ -3415,12 +3420,16 @@ void DynaExplode(int ex, int ey) Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER); +#if 1 + if (element != EL_EMPTY && element != EL_EXPLOSION && + !CAN_GROW_INTO(element) && !dynabomb_xl) + break; +#else /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ - if (element != EL_EMPTY && - element != EL_SAND && - element != EL_EXPLOSION && - !dynabomb_xl) + if (element != EL_EMPTY && element != EL_EXPLOSION && + element != EL_SAND && !dynabomb_xl) break; +#endif } } } @@ -5800,6 +5809,7 @@ void StartMoving(int x, int y) void ContinueMoving(int x, int y) { int element = Feld[x][y]; + int stored = Store[x][y]; struct ElementInfo *ei = &element_info[element]; int direction = MovDir[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); @@ -5904,7 +5914,7 @@ void ContinueMoving(int x, int y) { element = Feld[newx][newy] = EL_ACID; } -#if 1 +#if 0 else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || @@ -5948,6 +5958,22 @@ void ContinueMoving(int x, int y) ResetGfxAnimation(x, y); /* reset animation values for old field */ +#if 1 + if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && + ei->move_leave_element != EL_EMPTY && + (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || + stored != EL_EMPTY)) + { + /* some elements can leave other elements behind after moving */ + + Feld[x][y] = ei->move_leave_element; + InitField(x, y, FALSE); + + if (GFX_CRUMBLED(Feld[x][y])) + DrawLevelFieldCrumbledSandNeighbours(x, y); + } +#endif + #if 0 /* some elements can leave other elements behind after moving */ if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) && @@ -6431,6 +6457,15 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) return; +#if 1 + if (IS_FREE(x, y) || + CAN_GROW_INTO(Feld[x][y]) || + Feld[x][y] == EL_QUICKSAND_EMPTY) + { + newax = x; + neway = y; + } +#else /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ if (IS_FREE(x, y) || Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY) @@ -6438,6 +6473,7 @@ void AmoebeAbleger(int ax, int ay) newax = x; neway = y; } +#endif if (newax == ax && neway == ay) return; @@ -6456,6 +6492,16 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) continue; +#if 1 + if (IS_FREE(x, y) || + CAN_GROW_INTO(Feld[x][y]) || + Feld[x][y] == EL_QUICKSAND_EMPTY) + { + newax = x; + neway = y; + break; + } +#else /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ if (IS_FREE(x, y) || Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY) @@ -6464,6 +6510,7 @@ void AmoebeAbleger(int ax, int ay) neway = y; break; } +#endif else if (IS_PLAYER(x, y)) waiting_for_player = TRUE; } @@ -6601,6 +6648,20 @@ void Life(int ax, int ay) changed = TRUE; } } +#if 1 + else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy])) + { /* free border field */ + if (nachbarn >= life[2] && nachbarn <= life[3]) + { + Feld[xx][yy] = element; + MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); + if (!Stop[xx][yy]) + DrawLevelField(xx, yy); + Stop[xx][yy] = TRUE; + changed = TRUE; + } + } +#else /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND) { /* free border field */ @@ -6614,6 +6675,7 @@ void Life(int ax, int ay) changed = TRUE; } } +#endif } if (changed) @@ -8297,6 +8359,21 @@ void GameActions() #endif element = Feld[x][y]; +#if 1 + if (!IS_PLAYER(x,y) && + (element == EL_EMPTY || + CAN_GROW_INTO(element) || + element == EL_QUICKSAND_EMPTY || + element == EL_ACID_SPLASH_LEFT || + element == EL_ACID_SPLASH_RIGHT)) + { + if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) || + (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) || + (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) || + (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) + Feld[x][y] = EL_AMOEBA_DROP; + } +#else /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ if (!IS_PLAYER(x,y) && (element == EL_EMPTY || @@ -8311,6 +8388,7 @@ void GameActions() (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET)) Feld[x][y] = EL_AMOEBA_DROP; } +#endif random = random * 129 + 1; } @@ -8617,6 +8695,33 @@ static boolean canEnterSupaplexPort(int x, int y, int dx, int dy) } #endif +static boolean canFallDown(struct PlayerInfo *player) +{ + int jx = player->jx, jy = player->jy; + + return (IN_LEV_FIELD(jx, jy + 1) && + (IS_FREE(jx, jy + 1) || + (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])); +} + +static boolean canPassField(int x, int y, int move_dir) +{ + int opposite_dir = MV_DIR_OPPOSITE(move_dir); + int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); + int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); + int nextx = x + dx; + int nexty = y + dy; + int element = Feld[x][y]; + + return (IS_PASSABLE_FROM(element, opposite_dir) && + !CAN_MOVE(element) && + IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) && + IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) && + (level.can_pass_to_walkable || IS_FREE(nextx, nexty))); +} + static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) { int opposite_dir = MV_DIR_OPPOSITE(move_dir); @@ -8624,10 +8729,17 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); int newx = x + dx; int newy = y + dy; +#if 0 int nextx = newx + dx; int nexty = newy + dy; - boolean next_field_must_be_free = TRUE; +#endif +#if 1 + return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && + (IS_DIGGABLE(Feld[newx][newy]) || + IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || + canPassField(newx, newy, move_dir))); +#else return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) && (IS_DIGGABLE(Feld[newx][newy]) || IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) || @@ -8635,7 +8747,8 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) !CAN_MOVE(Feld[newx][newy]) && IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) && IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) && - !(next_field_must_be_free && !IS_FREE(nextx, nexty))))); + (level.can_pass_to_walkable || IS_FREE(nextx, nexty))))); +#endif } static void CheckGravityMovement(struct PlayerInfo *player) @@ -8649,6 +8762,7 @@ static void CheckGravityMovement(struct PlayerInfo *player) int move_dir_horizontal = player->action & MV_HORIZONTAL; int move_dir_vertical = player->action & MV_VERTICAL; #endif + #if 1 boolean player_is_snapping = player->effective_action & JOY_BUTTON_1; #else @@ -8657,7 +8771,6 @@ static void CheckGravityMovement(struct PlayerInfo *player) int jx = player->jx, jy = player->jy; - boolean player_is_moving_to_valid_field = (!player_is_snapping && (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) || @@ -8679,15 +8792,22 @@ static void CheckGravityMovement(struct PlayerInfo *player) #endif #if 1 + +#if 1 + boolean player_can_fall_down = canFallDown(player); +#else boolean player_can_fall_down = (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1) || (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid))); +#endif + #else boolean player_can_fall_down = (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1))); #endif + #if 0 boolean player_is_moving_to_valid_field = ( @@ -8713,9 +8833,11 @@ static void CheckGravityMovement(struct PlayerInfo *player) ); #endif +#if 0 boolean player_is_standing_on_valid_field = (IS_WALKABLE_INSIDE(Feld[jx][jy]) || (IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN))); +#endif #if 0 printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n", @@ -8728,7 +8850,9 @@ static void CheckGravityMovement(struct PlayerInfo *player) #endif if (player_can_fall_down && +#if 0 !player_is_standing_on_valid_field && +#endif !player_is_moving_to_valid_field) { #if 0 @@ -8923,6 +9047,9 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) #endif + /* store if player is automatically moved to next field */ + player->is_auto_moving = (player->programmed_action != MV_NO_MOVING); + /* remove the last programmed player action */ player->programmed_action = 0; @@ -10308,12 +10435,19 @@ int DigField(struct PlayerInfo *player, if (!ACCESS_FROM(element, opposite_direction)) return MF_NO_ACTION; /* field not accessible from this direction */ - if (element >= EL_GATE_1 && element <= EL_GATE_4) +#if 1 + if (element == EL_EMPTY_SPACE && + game.gravity && !player->is_auto_moving && + canFallDown(player) && move_direction != MV_DOWN) + return MF_NO_ACTION; /* player cannot walk here due to gravity */ +#endif + + if (IS_GATE(element)) { if (!player->key[element - EL_GATE_1]) return MF_NO_ACTION; } - else if (element >= EL_GATE_1_GRAY && element <= EL_GATE_4_GRAY) + else if (IS_GATE_GRAY(element)) { if (!player->key[element - EL_GATE_1_GRAY]) return MF_NO_ACTION; @@ -10339,12 +10473,15 @@ int DigField(struct PlayerInfo *player, } else if (IS_PASSABLE(element)) { - boolean next_field_must_be_free = TRUE; +#if 1 + if (!canPassField(x, y, move_direction)) + return MF_NO_ACTION; +#else #if 1 if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) || !IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) || - (next_field_must_be_free && !IS_FREE(nextx, nexty))) + (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty))) return MF_NO_ACTION; #else if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) @@ -10365,12 +10502,14 @@ int DigField(struct PlayerInfo *player, return MF_NO_ACTION; #endif - if (element >= EL_EM_GATE_1 && element <= EL_EM_GATE_4) +#endif + + if (IS_EM_GATE(element)) { if (!player->key[element - EL_EM_GATE_1]) return MF_NO_ACTION; } - else if (element >= EL_EM_GATE_1_GRAY && element <= EL_EM_GATE_4_GRAY) + else if (IS_EM_GATE_GRAY(element)) { if (!player->key[element - EL_EM_GATE_1_GRAY]) return MF_NO_ACTION; @@ -10973,11 +11112,20 @@ boolean DropElement(struct PlayerInfo *player) Changed[jx][jy] = 0; /* allow another change */ #endif +#if 1 + /* !!! TEST ONLY !!! */ + CheckElementChangePlayer(jx, jy, new_element, CE_DROPPED_BY_PLAYER, + player->index_bit, drop_side); + CheckTriggeredElementChangePlayer(jx, jy, new_element, + CE_OTHER_GETS_DROPPED, + player->index_bit, drop_side); +#else CheckTriggeredElementChangePlayer(jx, jy, new_element, CE_OTHER_GETS_DROPPED, player->index_bit, drop_side); CheckElementChangePlayer(jx, jy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); +#endif TestIfElementTouchesCustomElement(jx, jy); }