X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=2a63d3cea336b8d82d9a92d23525ad97cf5055a1;hb=62ce600f34661138022d2ab3e67b254d43b5228e;hp=3051f5ac9d93771620536c019413d08420dceec0;hpb=9de8eede744c45187c7011543ef8097d1ebc879c;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 3051f5ac..2a63d3ce 100644 --- a/src/game.c +++ b/src/game.c @@ -1046,7 +1046,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])) Back[ex][ey] = 0; @@ -1906,7 +1918,9 @@ 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 @@ -2206,6 +2220,7 @@ void Bang(int x, int y) player->element_nr); } +#if 0 #if 1 PlaySoundLevelAction(x, y, ACTION_EXPLODING); #else @@ -2214,6 +2229,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 */ @@ -2587,6 +2603,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 +2642,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); @@ -2725,6 +2770,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) || @@ -3578,31 +3630,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]; @@ -4005,22 +4073,9 @@ void ContinueMoving(int x, int y) int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx, newy = y + dy; int nextx = newx + dx, nexty = newy + dy; - int horiz_move = (dx != 0); - int sign = (horiz_move ? dx : dy); - int step = sign * element_info[element].move_stepsize; boolean pushed = Pushed[x][y]; - /* 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; - } - - 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)); @@ -5073,14 +5128,23 @@ static void ChangeElementNowExt(int x, int y, int target_element) if (CAN_BE_CRUMBLED(Feld[x][y])) DrawLevelFieldCrumbledSandNeighbours(x, y); + + 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; + /* 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) { Bang(x, y); @@ -5122,6 +5186,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)) || @@ -5147,6 +5214,9 @@ static void ChangeElementNow(int x, int y, int element) if (can_change[xx][yy] && (!change->use_random_change || RND(change->random) == 0)) { + if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) + RemoveMovingField(ex, ey); + ChangeElementNowExt(ex, ey, change->content[xx][yy]); /* for symmetry reasons, stop newly created border elements */ @@ -5266,6 +5336,9 @@ static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, if (x == lx && y == ly) /* do not change trigger element itself */ continue; + if (Changing[x][y]) /* do not change just changing elements */ + continue; + if (Feld[x][y] == i) { ChangeDelay[x][y] = 1;