X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=5b22dcbd4f7d511af5972303033fe20a6f5bae44;hb=268045d6b06349f1cf10d5cc6f9516b5caa20dea;hp=c52d16250d7ce2e7f3b412dd44e500cf0c94a3cf;hpb=f2e11ad5ab49e5d051e3d3f054330b802905e4bb;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index c52d1625..5b22dcbd 100644 --- a/src/game.c +++ b/src/game.c @@ -1054,6 +1054,7 @@ void InitGame() JustStopped[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; + Changing[x][y] = FALSE; ExplodePhase[x][y] = 0; ExplodeField[x][y] = EX_NO_EXPLOSION; @@ -1880,6 +1881,17 @@ void Explode(int ex, int ey, int phase, int mode) { int center_element = Feld[ex][ey]; +#if 0 + /* --- This is only really needed (and now handled) in "Impact()". --- */ + /* do not explode moving elements that left the explode field in time */ + if (game.engine_version >= 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; @@ -1894,6 +1906,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 +1920,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 1 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 +1958,13 @@ void Explode(int ex, int ey, int phase, int mode) } /* save walkable background elements while explosion on same tile */ +#if 1 if (IS_INDESTRUCTIBLE(element)) Back[x][y] = element; +#else + if (IS_INDESTRUCTIBLE(element) && IS_WALKABLE(element)) + Back[x][y] = element; +#endif /* ignite explodable elements reached by other explosion */ if (element == EL_EXPLOSION) @@ -1988,11 +2018,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 +2038,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; @@ -2206,6 +2237,7 @@ void Bang(int x, int y) player->element_nr); } +#if 0 #if 1 PlaySoundLevelAction(x, y, ACTION_EXPLODING); #else @@ -2214,6 +2246,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 +2620,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 +2659,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 +2787,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 +3443,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) { @@ -3953,6 +4024,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 */ } @@ -4021,22 +4097,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)); @@ -5089,14 +5152,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); @@ -5138,6 +5210,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)) || @@ -5152,7 +5227,7 @@ static void ChangeElementNow(int x, int y, int element) if (!change->only_complete || complete_change) { 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++) @@ -5161,8 +5236,11 @@ 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]); /* for symmetry reasons, stop newly created border elements */ @@ -5282,6 +5360,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; @@ -5505,6 +5586,16 @@ void GameActions() GfxFrame[x][y]++; +#if 1 + /* reset finished pushing action (not done in ContinueMoving() to allow + continous pushing animation for elements without push delay) */ + if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) + { + ResetGfxAnimation(x, y); + DrawLevelField(x, y); + } +#endif + #if DEBUG if (IS_BLOCKED(x, y)) { @@ -5578,9 +5669,10 @@ void GameActions() #if 1 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]); #if 0 - if (element == EL_PACMAN) - printf("::: %d, %d, %d\n", - IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y]); + if (element == EL_MOLE) + printf("::: %d, %d, %d [%d]\n", + IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y], + GfxAction[x][y]); #endif #if 0 if (element == EL_YAMYAM) @@ -5596,7 +5688,7 @@ void GameActions() DrawLevelGraphicAnimationIfNeeded(x, y, graphic); #if 0 - if (element == EL_YAMYAM) + if (element == EL_MOLE) printf("::: %d, %d\n", graphic, GfxFrame[x][y]); #endif } @@ -6260,7 +6352,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)) @@ -6276,7 +6370,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) { @@ -6338,6 +6434,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 }, @@ -6348,6 +6445,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]; @@ -6369,10 +6472,13 @@ void TestIfPlayerTouchesCustomElement(int x, int y) break; } } + + check_changing = FALSE; } void TestIfElementTouchesCustomElement(int x, int y) { + static boolean check_changing = FALSE; static int xy[4][2] = { { 0, -1 }, @@ -6383,6 +6489,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]; @@ -6403,6 +6515,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) @@ -7230,6 +7344,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); @@ -7788,6 +7903,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; @@ -7796,14 +7913,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: