X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=f5b3ab7b883d783c088bd11a20379611c4fc3a75;hb=ddaae9de458b7f07b05461101655a1da4c63b380;hp=1b6251b62491bf23a2f579e6764e536e0e7ec38e;hpb=720b0a62c8af0585e9517ed7a98ea336304c02e4;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 1b6251b6..f5b3ab7b 100644 --- a/src/game.c +++ b/src/game.c @@ -169,7 +169,7 @@ static void KillHeroUnlessProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); -static boolean CheckTriggeredElementChange(int, int); +static boolean CheckTriggeredElementChange(int, int, int, int); static boolean CheckElementChange(int, int, int, int); static void ChangeElementNow(int, int, int); @@ -1032,6 +1032,7 @@ void InitGame() game.switchgate_pos = 0; game.balloon_dir = MV_NO_MOVING; game.explosions_delayed = TRUE; + game.current_gravity = level.initial_gravity; for (i=0; i<4; i++) { @@ -1046,7 +1047,7 @@ void InitGame() { for (y=0; y= RELEASE_IDENT(2,2,0,7) && + center_element == EL_EMPTY && (mode == EX_NORMAL || mode == EX_CENTER)) + return; +#endif + + if (mode == EX_NORMAL || mode == EX_CENTER) + PlaySoundLevelAction(ex, ey, ACTION_EXPLODING); + /* remove things displayed in background while burning dynamite */ - if (!IS_INDESTRUCTIBLE(Back[ex][ey])) + if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) Back[ex][ey] = 0; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) @@ -1894,6 +1907,8 @@ void Explode(int ex, int ey, int phase, int mode) for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++) { + int xx = x - ex + 1; + int yy = y - ey + 1; int element; if (!IN_LEV_FIELD(x, y) || @@ -1906,12 +1921,23 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) { element = MovingOrBlocked2Element(x, y); - RemoveMovingField(x, y); + + if (!IS_EXPLOSION_PROOF(element)) + RemoveMovingField(x, y); } #if 1 + +#if 0 if (IS_EXPLOSION_PROOF(element)) continue; +#else + /* indestructible elements can only explode in center (but not flames) */ + if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) || + element == EL_FLAMES) + continue; +#endif + #else if ((IS_INDESTRUCTIBLE(element) && (game.engine_version < VERSION_IDENT(2,2,0) || @@ -1933,8 +1959,13 @@ void Explode(int ex, int ey, int phase, int mode) } /* save walkable background elements while explosion on same tile */ +#if 0 if (IS_INDESTRUCTIBLE(element)) Back[x][y] = element; +#else + if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element)) + Back[x][y] = element; +#endif /* ignite explodable elements reached by other explosion */ if (element == EL_EXPLOSION) @@ -1988,11 +2019,10 @@ void Explode(int ex, int ey, int phase, int mode) else if (center_element == EL_AMOEBA_TO_DIAMOND) Store[x][y] = level.amoeba_content; else if (center_element == EL_YAMYAM) - Store[x][y] = - level.yamyam_content[game.yamyam_content_nr][x - ex + 1][y - ey + 1]; - else if (IS_CUSTOM_ELEMENT(center_element)) - Store[x][y] = - element_info[center_element].content[x - ex + 1][y - ey + 1]; + Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy]; + else if (IS_CUSTOM_ELEMENT(center_element) && + element_info[center_element].content[xx][yy] != EL_EMPTY) + Store[x][y] = element_info[center_element].content[xx][yy]; else if (element == EL_WALL_EMERALD) Store[x][y] = EL_EMERALD; else if (element == EL_WALL_DIAMOND) @@ -2009,6 +2039,8 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_PEARL; else if (element == EL_WALL_CRYSTAL) Store[x][y] = EL_CRYSTAL; + else if (IS_CUSTOM_ELEMENT(element)) + Store[x][y] = element_info[element].content[1][1]; else Store[x][y] = EL_EMPTY; @@ -2105,6 +2137,9 @@ void Explode(int ex, int ey, int phase, int mode) InitMovDir(x, y); DrawLevelField(x, y); + if (CAN_BE_CRUMBLED(element)) + DrawLevelFieldCrumbledSandNeighbours(x, y); + if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present) StorePlayer[x][y] = 0; } @@ -2181,6 +2216,7 @@ void DynaExplode(int ex, int ey) Explode(x, y, EX_PHASE_START, EX_BORDER); + /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */ if (element != EL_EMPTY && element != EL_SAND && element != EL_EXPLOSION && @@ -2206,6 +2242,7 @@ void Bang(int x, int y) player->element_nr); } +#if 0 #if 1 PlaySoundLevelAction(x, y, ACTION_EXPLODING); #else @@ -2214,6 +2251,7 @@ void Bang(int x, int y) else PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING); #endif +#endif #if 0 if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */ @@ -2256,7 +2294,7 @@ void Bang(int x, int y) break; } - CheckTriggeredElementChange(element, CE_OTHER_IS_EXPLODING); + CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING); } void SplashAcid(int x, int y) @@ -2489,14 +2527,16 @@ static int getInvisibleActiveFromInvisibleElement(int element) { return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE : element == EL_INVISIBLE_WALL ? EL_INVISIBLE_WALL_ACTIVE : - EL_INVISIBLE_SAND_ACTIVE); + element == EL_INVISIBLE_SAND ? EL_INVISIBLE_SAND_ACTIVE : + element); } static int getInvisibleFromInvisibleActiveElement(int element) { return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL : element == EL_INVISIBLE_WALL_ACTIVE ? EL_INVISIBLE_WALL : - EL_INVISIBLE_SAND); + element == EL_INVISIBLE_SAND_ACTIVE ? EL_INVISIBLE_SAND : + element); } static void RedrawAllLightSwitchesAndInvisibleElements() @@ -2587,6 +2627,29 @@ static void ActivateTimegateSwitch(int x, int y) Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE; } +inline static int getElementMoveStepsize(int x, int y) +{ + int element = Feld[x][y]; + 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); + int horiz_move = (dx != 0); + int sign = (horiz_move ? dx : dy); + int step = sign * element_info[element].move_stepsize; + + /* special values for move stepsize for spring and things on conveyor belt */ + if (horiz_move) + { + if (CAN_FALL(element) && + y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1])) + step = sign * MOVE_STEPSIZE_NORMAL / 2; + else if (element == EL_SPRING) + step = sign * MOVE_STEPSIZE_NORMAL * 2; + } + + return step; +} + void Impact(int x, int y) { boolean lastline = (y == lev_fieldy-1); @@ -2603,6 +2666,12 @@ void Impact(int x, int y) object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) || MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); + + /* do not smash moving elements that left the smashed field in time */ + if (game.engine_version >= RELEASE_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && + ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) + object_hit = FALSE; + if (object_hit) smashed = MovingOrBlocked2Element(x, y + 1); @@ -2633,7 +2702,7 @@ void Impact(int x, int y) return; } #if 1 - else if (impact && CheckElementChange(x, y, element, ACTION_IMPACT)) + else if (impact && CheckElementChange(x, y, element, CE_IMPACT)) { PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT); @@ -2725,6 +2794,13 @@ void Impact(int x, int y) Bang(x, y + 1); return; } +#if 0 + else if (CAN_SMASH_ENEMIES(element) && IS_CLASSIC_ENEMY(smashed)) + { + Bang(x, y + 1); + return; + } +#endif else if (CAN_SMASH_EVERYTHING(element)) { if (IS_CLASSIC_ENEMY(smashed) || @@ -3374,7 +3450,9 @@ void StartMoving(int x, int y) if (Stop[x][y]) return; - GfxAction[x][y] = ACTION_DEFAULT; + /* !!! this should be handled more generic (not only for mole) !!! */ + if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING) + GfxAction[x][y] = ACTION_DEFAULT; if (CAN_FALL(element) && y < lev_fieldy - 1) { @@ -3578,31 +3656,47 @@ void StartMoving(int x, int y) element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE) #endif { - boolean left = (x>0 && IS_FREE(x-1, y) && - (IS_FREE(x-1, y + 1) || Feld[x-1][y + 1] == EL_ACID)); - boolean right = (x 0 && IS_FREE(x - 1, y) && + (IS_FREE(x - 1, y + 1) || + Feld[x - 1][y + 1] == EL_ACID)); + boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) && + (IS_FREE(x + 1, y + 1) || + Feld[x + 1][y + 1] == EL_ACID)); + boolean can_fall_any = (can_fall_left || can_fall_right); + boolean can_fall_both = (can_fall_left && can_fall_right); + + if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) + { + int slippery_type = element_info[Feld[x][y + 1]].slippery_type; + + if (slippery_type == SLIPPERY_ONLY_LEFT) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ONLY_RIGHT) + can_fall_left = FALSE; + else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) + can_fall_left = FALSE; + + can_fall_any = (can_fall_left || can_fall_right); + can_fall_both = (can_fall_left && can_fall_right); + } - if (left || right) + if (can_fall_any) { - if (left && right && + if (can_fall_both && (game.emulation != EMU_BOULDERDASH && element != EL_BD_ROCK && element != EL_BD_DIAMOND)) - left = !(right = RND(2)); + can_fall_left = !(can_fall_right = RND(2)); - InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT); + InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT); started_moving = TRUE; - -#if 0 - if (element == EL_BOMB) - printf("::: SLIP DOWN [%d]\n", FrameCounter); -#endif } } else if (IS_BELT_ACTIVE(Feld[x][y + 1])) { - boolean left_is_free = (x>0 && IS_FREE(x-1, y)); - boolean right_is_free = (x 0 && IS_FREE(x - 1, y)); + boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y)); int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]); int belt_dir = game.belt_dir[belt_nr]; @@ -3753,7 +3847,10 @@ void StartMoving(int x, int y) return; } - GfxAction[x][y] = ACTION_MOVING; + /* special case of "moving" animation of waiting elements (FIX THIS !!!); + for all other elements GfxAction will be set by InitMovingField() */ + if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY) + GfxAction[x][y] = ACTION_MOVING; } /* now make next step */ @@ -3937,6 +4034,11 @@ void StartMoving(int x, int y) { Feld[newx][newy] = EL_AMOEBA_SHRINKING; PlaySoundLevel(x, y, SND_MOLE_DIGGING); + + ResetGfxAnimation(x, y); + GfxAction[x][y] = ACTION_DIGGING; + DrawLevelField(x, y); + MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ return; /* wait for shrinking amoeba */ } @@ -3961,7 +4063,8 @@ void StartMoving(int x, int y) TurnRound(x, y); #if 1 - DrawLevelElementAnimation(x, y, element); + if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ + DrawLevelElementAnimation(x, y, element); #else if (element == EL_BUG || element == EL_SPACESHIP || @@ -4003,49 +4106,11 @@ void ContinueMoving(int x, int y) 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); - int horiz_move = (dx != 0); int newx = x + dx, newy = y + dy; int nextx = newx + dx, nexty = newy + dy; -#if 1 - int sign = (horiz_move ? dx : dy); - int step = sign * element_info[element].move_stepsize; -#else - int step = (horiz_move ? dx : dy) * MOVE_STEPSIZE_NORMAL; -#endif boolean pushed = Pushed[x][y]; -#if 1 - if (CAN_FALL(element) && horiz_move && - y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1])) - step = sign * MOVE_STEPSIZE_NORMAL / 2; - else if (element == EL_SPRING && horiz_move) - step = sign * MOVE_STEPSIZE_NORMAL * 2; -#else - if (element == EL_AMOEBA_DROP || element == EL_AMOEBA_DROPPING) - step /= 2; - else if (element == EL_QUICKSAND_FILLING || - element == EL_QUICKSAND_EMPTYING) - step /= 4; - else if (element == EL_MAGIC_WALL_FILLING || - element == EL_BD_MAGIC_WALL_FILLING || - element == EL_MAGIC_WALL_EMPTYING || - element == EL_BD_MAGIC_WALL_EMPTYING) - step /= 2; - else if (CAN_FALL(element) && horiz_move && - y < lev_fieldy-1 && IS_BELT_ACTIVE(Feld[x][y+1])) - step /= 2; - else if (element == EL_SPRING && horiz_move) - step *= 2; - else if (IS_CUSTOM_ELEMENT(element)) - step = SIGN(step) * element_info[element].move_stepsize; - -#if OLD_GAME_BEHAVIOUR - else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) - step*=2; -#endif -#endif - - MovPos[x][y] += step; + MovPos[x][y] += getElementMoveStepsize(x, y); if (pushed) /* special case: moving object pushed by player */ MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); @@ -4058,31 +4123,11 @@ void ContinueMoving(int x, int y) if (element == EL_MOLE) { - int i; - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; - Feld[x][y] = EL_SAND; - DrawLevelField(x, y); - - for(i=0; i<4; i++) - { - int xx, yy; - - xx = x + xy[i][0]; - yy = y + xy[i][1]; - if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_SAND) - DrawLevelField(xx, yy); /* for "crumbled sand" */ - } + DrawLevelFieldCrumbledSandNeighbours(x, y); } - - if (element == EL_QUICKSAND_FILLING) + else if (element == EL_QUICKSAND_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; @@ -4513,6 +4558,7 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) return; + /* !!! 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) { @@ -4537,6 +4583,7 @@ void AmoebeAbleger(int ax, int ay) if (!IN_LEV_FIELD(x, y)) continue; + /* !!! 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) { @@ -4681,6 +4728,7 @@ void Life(int ax, int ay) changed = TRUE; } } + /* !!! 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 */ if (nachbarn >= life[2] && nachbarn <= life[3]) @@ -5117,40 +5165,23 @@ static void ChangeElementNowExt(int x, int y, int target_element) DrawLevelField(x, y); if (CAN_BE_CRUMBLED(Feld[x][y])) - { - int sx = SCREENX(x), sy = SCREENY(y); - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; - int i; - - for(i=0; i<4; i++) - { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; - int sxx = sx + xy[i][0]; - int syy = sy + xy[i][1]; + DrawLevelFieldCrumbledSandNeighbours(x, y); - if (!IN_LEV_FIELD(xx, yy) || - !IN_SCR_FIELD(sxx, syy) || - !CAN_BE_CRUMBLED(Feld[xx][yy]) || - IS_MOVING(xx, yy)) - continue; - - DrawLevelField(xx, yy); - } - } + TestIfBadThingTouchesHero(x, y); + TestIfPlayerTouchesCustomElement(x, y); + TestIfElementTouchesCustomElement(x, y); } static void ChangeElementNow(int x, int y, int element) { struct ElementChangeInfo *change = &element_info[element].change; - CheckTriggeredElementChange(Feld[x][y], CE_OTHER_IS_CHANGING); + /* prevent CheckTriggeredElementChange() from looping */ + Changing[x][y] = TRUE; + + CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); + + Changing[x][y] = FALSE; if (change->explode) { @@ -5193,6 +5224,9 @@ static void ChangeElementNow(int x, int y, int element) e = Feld[ex][ey]; + if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) + e = MovingOrBlocked2Element(ex, ey); + half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e)); if ((change->power <= CP_NON_DESTRUCTIVE && !IS_FREE(ex, ey)) || @@ -5206,8 +5240,10 @@ static void ChangeElementNow(int x, int y, int element) if (!change->only_complete || complete_change) { + boolean something_has_changed = FALSE; + if (change->only_complete && change->use_random_change && - RND(change->random) != 0) + RND(100) < change->random) return; for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) @@ -5216,21 +5252,31 @@ static void ChangeElementNow(int x, int y, int element) int ey = y + yy - 1; if (can_change[xx][yy] && (!change->use_random_change || - RND(change->random) == 0)) + RND(100) < change->random)) { + if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) + RemoveMovingField(ex, ey); + ChangeElementNowExt(ex, ey, change->content[xx][yy]); + something_has_changed = TRUE; + /* for symmetry reasons, stop newly created border elements */ if (ex != x || ey != y) Stop[ex][ey] = TRUE; } } - return; + if (something_has_changed) + PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); } } + else + { + ChangeElementNowExt(x, y, change->target_element); - ChangeElementNowExt(x, y, change->target_element); + PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); + } } static void ChangeElement(int x, int y) @@ -5318,7 +5364,7 @@ static void ChangeElement(int x, int y) } } -static boolean CheckTriggeredElementChange(int trigger_element, +static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, int trigger_event) { int i, x, y; @@ -5334,6 +5380,12 @@ static boolean CheckTriggeredElementChange(int trigger_element, for (y=0; yprogrammed_action) + if (game.current_gravity && !player->programmed_action) { int move_dir_vertical = player->action & (MV_UP | MV_DOWN); int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT); @@ -6042,6 +6106,7 @@ static void CheckGravityMovement(struct PlayerInfo *player) (IN_LEV_FIELD(new_jx, new_jy) && (Feld[new_jx][new_jy] == EL_SP_BASE || Feld[new_jx][new_jy] == EL_SAND)); + /* !!! extend EL_SAND to anything diggable !!! */ if (field_under_player_is_free && !player_is_moving_to_valid_field && @@ -6312,7 +6377,9 @@ void ScrollFigure(struct PlayerInfo *player, int mode) if (Feld[last_jx][last_jy] == EL_EMPTY) Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; +#if 0 DrawPlayer(player); +#endif return; } else if (!FrameReached(&player->actual_frame_counter, 1)) @@ -6328,7 +6395,9 @@ void ScrollFigure(struct PlayerInfo *player, int mode) if (player->MovPos == 0) CheckGravityMovement(player); - DrawPlayer(player); +#if 0 + DrawPlayer(player); /* needed here only to cleanup last field */ +#endif if (player->MovPos == 0) { @@ -6390,6 +6459,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode) void TestIfPlayerTouchesCustomElement(int x, int y) { + static boolean check_changing = FALSE; static int xy[4][2] = { { 0, -1 }, @@ -6400,6 +6470,12 @@ void TestIfPlayerTouchesCustomElement(int x, int y) boolean center_is_player = (IS_PLAYER(x, y)); int i; + /* prevent TestIfPlayerTouchesCustomElement() from looping */ + if (check_changing) + return; + + check_changing = TRUE; + for (i=0; i<4; i++) { int xx = x + xy[i][0]; @@ -6410,21 +6486,24 @@ void TestIfPlayerTouchesCustomElement(int x, int y) if (center_is_player) { - CheckTriggeredElementChange(Feld[xx][yy], CE_OTHER_GETS_TOUCHED); + CheckTriggeredElementChange(xx, yy, Feld[xx][yy], CE_OTHER_GETS_TOUCHED); CheckElementChange(xx, yy, Feld[xx][yy], CE_TOUCHED_BY_PLAYER); } else if (IS_PLAYER(xx, yy)) { - CheckTriggeredElementChange(Feld[x][y], CE_OTHER_GETS_TOUCHED); + CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_GETS_TOUCHED); CheckElementChange(x, y, Feld[x][y], CE_TOUCHED_BY_PLAYER); break; } } + + check_changing = FALSE; } void TestIfElementTouchesCustomElement(int x, int y) { + static boolean check_changing = FALSE; static int xy[4][2] = { { 0, -1 }, @@ -6435,6 +6514,12 @@ void TestIfElementTouchesCustomElement(int x, int y) boolean center_is_custom = (IS_CUSTOM_ELEMENT(Feld[x][y])); int i; + /* prevent TestIfElementTouchesCustomElement() from looping */ + if (check_changing) + return; + + check_changing = TRUE; + for (i=0; i<4; i++) { int xx = x + xy[i][0]; @@ -6455,6 +6540,8 @@ void TestIfElementTouchesCustomElement(int x, int y) CheckElementChange(xx, yy, Feld[xx][yy], CE_OTHER_IS_TOUCHING); } } + + check_changing = FALSE; } void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) @@ -6995,6 +7082,12 @@ int DigField(struct PlayerInfo *player, !IS_FREE(nextx, nexty)) return MF_NO_ACTION; + if (element == EL_SP_GRAVITY_PORT_LEFT || + element == EL_SP_GRAVITY_PORT_RIGHT || + element == EL_SP_GRAVITY_PORT_UP || + element == EL_SP_GRAVITY_PORT_DOWN) + game.current_gravity = !game.current_gravity; + /* automatically move to the next field with double speed */ player->programmed_action = move_direction; DOUBLE_PLAYER_SPEED(player); @@ -7125,8 +7218,12 @@ int DigField(struct PlayerInfo *player, if (mode != DF_SNAP) { +#if 1 + GfxElement[x][y] = GFX_ELEMENT(element); +#else GfxElement[x][y] = (CAN_BE_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element)); +#endif player->is_digging = TRUE; } @@ -7204,7 +7301,7 @@ int DigField(struct PlayerInfo *player, RaiseScoreElement(element); PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); - CheckTriggeredElementChange(element, CE_OTHER_GETS_COLLECTED); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); break; } @@ -7282,6 +7379,7 @@ int DigField(struct PlayerInfo *player, PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); InitMovingField(x, y, move_direction); + GfxAction[x][y] = ACTION_PUSHING; if (mode == DF_SNAP) ContinueMoving(x, y); @@ -7294,14 +7392,14 @@ int DigField(struct PlayerInfo *player, if (game.engine_version < RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); - CheckTriggeredElementChange(element, CE_OTHER_GETS_PUSHED); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PUSHED); CheckElementChange(x, y, element, CE_PUSHED_BY_PLAYER); break; } else { - CheckTriggeredElementChange(element, CE_OTHER_GETS_PRESSED); + CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PRESSED); CheckElementChange(x, y, element, CE_PRESSED_BY_PLAYER); } @@ -7840,6 +7938,8 @@ static void HandleGameButtons(struct GadgetInfo *gi) else if (audio.music_available) { setup.sound = setup.sound_music = TRUE; + + SetAudioMode(setup.sound); PlayMusic(level_nr); } break; @@ -7848,14 +7948,20 @@ static void HandleGameButtons(struct GadgetInfo *gi) if (setup.sound_loops) setup.sound_loops = FALSE; else if (audio.loops_available) + { setup.sound = setup.sound_loops = TRUE; + SetAudioMode(setup.sound); + } break; case SOUND_CTRL_ID_SIMPLE: if (setup.sound_simple) setup.sound_simple = FALSE; else if (audio.sound_available) + { setup.sound = setup.sound_simple = TRUE; + SetAudioMode(setup.sound); + } break; default: