X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=6473b49a8030bf25ebcb47d333cc207d2fbb25b8;hb=278196b1b8a46ae3e3b0e768202760ff496ac3c5;hp=1cc2f72b6a42f55b412607049633ed5f1ed1a588;hpb=0f38cfdd905d52190ca959b75c849459cbc99144;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 1cc2f72b..6473b49a 100644 --- a/src/game.c +++ b/src/game.c @@ -962,7 +962,7 @@ static struct GamePanelControlInfo game_panel_controls[] = ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Tile[x][y] == EL_DIAMOND) #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ - ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Tile[x][y])) + ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_FOOD_DARK_YAMYAM(Tile[x][y])) #define PACMAN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Tile[x][y])) @@ -1069,9 +1069,9 @@ static void HandleElementChange(int, int, int); static void ExecuteCustomElementAction(int, int, int, int); static boolean ChangeElement(int, int, int, int); -static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); +static boolean CheckTriggeredElementChangeExt(int, int, int, int, int, int, int); #define CheckTriggeredElementChange(x, y, e, ev) \ - CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1) + CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1) #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s) \ CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1) #define CheckTriggeredElementChangeBySide(x, y, e, ev, s) \ @@ -1784,7 +1784,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) player->active = TRUE; // remove potentially duplicate players - if (StorePlayer[jx][jy] == Tile[x][y]) + if (IN_LEV_FIELD(jx, jy) && StorePlayer[jx][jy] == Tile[x][y]) StorePlayer[jx][jy] = 0; StorePlayer[x][y] = Tile[x][y]; @@ -2566,7 +2566,9 @@ static void UpdateGameControlValues(void) int element = gpc->value; int graphic = el2panelimg(element); int init_gfx_random = (graphic_info[graphic].anim_global_sync ? - sync_random_frame : INIT_GFX_RANDOM()); + sync_random_frame : + graphic_info[graphic].anim_global_anim_sync ? + getGlobalAnimSyncFrame() : INIT_GFX_RANDOM()); if (gpc->value != gpc->last_value) { @@ -2601,7 +2603,9 @@ static void UpdateGameControlValues(void) int last_anim_random_frame = gfx.anim_random_frame; int graphic = gpc->graphic; int init_gfx_random = (graphic_info[graphic].anim_global_sync ? - sync_random_frame : INIT_GFX_RANDOM()); + sync_random_frame : + graphic_info[graphic].anim_global_anim_sync ? + getGlobalAnimSyncFrame() : INIT_GFX_RANDOM()); if (gpc->value != gpc->last_value) { @@ -3569,7 +3573,7 @@ void InitGame(void) int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); int fade_mask = REDRAW_FIELD; - + boolean restarting = (game_status == GAME_MODE_PLAYING); boolean emulate_bd = TRUE; // unless non-BOULDERDASH elements found boolean emulate_sp = TRUE; // unless non-SUPAPLEX elements found int initial_move_dir = MV_DOWN; @@ -3581,7 +3585,15 @@ void InitGame(void) if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); - SetGameStatus(GAME_MODE_PLAYING); + if (restarting) + { + // force fading out global animations displayed during game play + SetGameStatus(GAME_MODE_PSEUDO_RESTARTING); + } + else + { + SetGameStatus(GAME_MODE_PLAYING); + } if (level_editor_test_game) FadeSkipNextFadeOut(); @@ -3597,6 +3609,14 @@ void InitGame(void) FadeOut(fade_mask); + if (restarting) + { + // force restarting global animations displayed during game play + RestartGlobalAnimsByStatus(GAME_MODE_PSEUDO_RESTARTING); + + SetGameStatus(GAME_MODE_PLAYING); + } + if (level_editor_test_game) FadeSkipNextFadeIn(); @@ -4495,7 +4515,6 @@ void InitGame(void) } game.restart_level = FALSE; - game.restart_game_message = NULL; game.request_active = FALSE; game.request_active_or_moving = FALSE; @@ -4777,6 +4796,8 @@ static void LevelSolved(void) game.LevelSolved = TRUE; game.GameOver = TRUE; + tape.solved = TRUE; + // needed here to display correct panel values while player walks into exit LevelSolved_SetFinalGameValues(); } @@ -5116,10 +5137,11 @@ static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry, if (strEqual(new_entry->tape_basename, entry->tape_basename) && !strEqual(new_entry->tape_basename, UNDEFINED_FILENAME)) { - // special case: use server score instead of local score value if higher - // (historic scores might have been truncated to 16-bit values locally) - if (score_is_better) - entry->score = new_entry->score; + // add fields from server score entry not stored in local score entry + // (currently, this means setting platform, version and country fields; + // in rare cases, this may also correct an invalid score value, as + // historic scores might have been truncated to 16-bit values locally) + *entry = *new_entry; return -1; } @@ -5302,6 +5324,8 @@ static void ResetGfxFrame(int x, int y) if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; + else if (graphic_info[graphic].anim_global_anim_sync) + GfxFrame[x][y] = getGlobalAnimSyncFrame(); else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) GfxFrame[x][y] = CustomValue[x][y]; else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) @@ -5381,17 +5405,9 @@ void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y) { - int oldx = x, oldy = y; int direction = MovDir[x][y]; - - if (direction == MV_LEFT) - oldx++; - else if (direction == MV_RIGHT) - oldx--; - else if (direction == MV_UP) - oldy++; - else if (direction == MV_DOWN) - oldy--; + int oldx = x + (direction & MV_LEFT ? +1 : direction & MV_RIGHT ? -1 : 0); + int oldy = y + (direction & MV_UP ? +1 : direction & MV_DOWN ? -1 : 0); *comes_from_x = oldx; *comes_from_y = oldy; @@ -5406,16 +5422,17 @@ static int MovingOrBlocked2Element(int x, int y) int oldx, oldy; Blocked2Moving(x, y, &oldx, &oldy); + return Tile[oldx][oldy]; } - else - return element; + + return element; } static int MovingOrBlocked2ElementIfNotLeaving(int x, int y) { // like MovingOrBlocked2Element(), but if element is moving - // and (x,y) is the field the moving element is just leaving, + // and (x, y) is the field the moving element is just leaving, // return EL_BLOCKED instead of the element value int element = Tile[x][y]; @@ -5608,7 +5625,7 @@ static void setScreenCenteredToAllPlayers(int *sx, int *sy) *sy = (sy1 + sy2) / 2; } -static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, +static void DrawRelocateScreen(int old_x, int old_y, int x, int y, boolean center_screen, boolean quick_relocation) { unsigned int frame_delay_value_old = GetVideoFrameDelay(); @@ -5779,7 +5796,7 @@ static void RelocatePlayer(int jx, int jy, int el_player_raw) } // only visually relocate centered player - DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir, + DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, FALSE, level.instant_relocation); TestIfPlayerTouchesBadThing(jx, jy); @@ -5812,9 +5829,6 @@ static void Explode(int ex, int ey, int phase, int mode) int last_phase; int border_element; - // !!! eliminate this variable !!! - int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); - if (game.explosions_delayed) { ExplodeField[ex][ey] = mode; @@ -5824,6 +5838,8 @@ static void Explode(int ex, int ey, int phase, int mode) if (phase == EX_PHASE_START) // initialize 'Store[][]' field { int center_element = Tile[ex][ey]; + int ce_value = CustomValue[ex][ey]; + int ce_score = element_info[center_element].collect_score; int artwork_element, explosion_element; // set these values later // remove things displayed in background while burning dynamite @@ -5962,6 +5978,14 @@ static void Explode(int ex, int ey, int phase, int mode) else Store[x][y] = EL_EMPTY; + if (IS_CUSTOM_ELEMENT(center_element)) + Store[x][y] = (Store[x][y] == EL_CURRENT_CE_VALUE ? ce_value : + Store[x][y] == EL_CURRENT_CE_SCORE ? ce_score : + Store[x][y] >= EL_PREV_CE_8 && + Store[x][y] <= EL_NEXT_CE_8 ? + RESOLVED_REFERENCE_ELEMENT(center_element, Store[x][y]) : + Store[x][y]); + if (x != ex || y != ey || mode == EX_TYPE_BORDER || center_element == EL_AMOEBA_TO_DIAMOND) Store2[x][y] = element; @@ -6095,7 +6119,7 @@ static void Explode(int ex, int ey, int phase, int mode) int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING); int frame = getGraphicAnimationFrameXY(graphic, x, y); - if (phase == delay) + if (phase == 1) TEST_DrawLevelFieldCrumbled(x, y); if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY) @@ -6418,7 +6442,7 @@ static void ToggleBeltSwitch(int x, int y) } } -static void ToggleSwitchgateSwitch(int x, int y) +static void ToggleSwitchgateSwitch(void) { int xx, yy; @@ -6898,7 +6922,7 @@ static void Impact(int x, int y) smashed == EL_DC_SWITCHGATE_SWITCH_UP || smashed == EL_DC_SWITCHGATE_SWITCH_DOWN) { - ToggleSwitchgateSwitch(x, y + 1); + ToggleSwitchgateSwitch(); } else if (smashed == EL_LIGHT_SWITCH || smashed == EL_LIGHT_SWITCH_ACTIVE) @@ -7521,7 +7545,7 @@ static void TurnRoundExt(int x, int 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); + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y); if (element_info[element].move_stepsize == 0) // "not moving" return; @@ -8351,7 +8375,7 @@ static void StartMoving(int x, int y) PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) - DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0); + DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2img(element), 0); game.friends_still_needed--; if (!game.friends_still_needed && @@ -8363,7 +8387,7 @@ static void StartMoving(int x, int y) } else if (IS_FOOD_PENGUIN(Tile[newx][newy])) { - if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING) + if (DigField(local_player, x, y, newx, newy, 0, 0, DF_DIG) == MP_MOVING) TEST_DrawLevelField(newx, newy); else GfxDir[x][y] = MovDir[x][y] = MV_NONE; @@ -8668,7 +8692,7 @@ void ContinueMoving(int x, int y) if (pushed_by_player) // special case: moving object pushed by player { - MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); + MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x, y)->MovPos)); } else if (use_step_delay) // special case: moving object has step delay { @@ -8930,7 +8954,7 @@ void ContinueMoving(int x, int y) CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER, player->index_bit, push_side); - CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X, + CheckTriggeredElementChangeByPlayer(newx, newy, element, CE_PLAYER_PUSHES_X, player->index_bit, push_side); } @@ -9656,7 +9680,7 @@ static void DrawTwinkleOnField(int x, int y) } } -static void MauerWaechst(int x, int y) +static void WallGrowing(int x, int y) { int delay = 6; @@ -9706,15 +9730,59 @@ static void MauerWaechst(int x, int y) } } -static void MauerAbleger(int ax, int ay) +static void CheckWallGrowing(int ax, int ay) { int element = Tile[ax][ay]; int graphic = el2img(element); - boolean oben_frei = FALSE, unten_frei = FALSE; - boolean links_frei = FALSE, rechts_frei = FALSE; - boolean oben_massiv = FALSE, unten_massiv = FALSE; - boolean links_massiv = FALSE, rechts_massiv = FALSE; - boolean new_wall = FALSE; + boolean free_top = FALSE; + boolean free_bottom = FALSE; + boolean free_left = FALSE; + boolean free_right = FALSE; + boolean stop_top = FALSE; + boolean stop_bottom = FALSE; + boolean stop_left = FALSE; + boolean stop_right = FALSE; + boolean new_wall = FALSE; + + boolean is_steelwall = (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || + element == EL_EXPANDABLE_STEELWALL_VERTICAL || + element == EL_EXPANDABLE_STEELWALL_ANY); + + boolean grow_vertical = (element == EL_EXPANDABLE_WALL_VERTICAL || + element == EL_EXPANDABLE_WALL_ANY || + element == EL_EXPANDABLE_STEELWALL_VERTICAL || + element == EL_EXPANDABLE_STEELWALL_ANY); + + boolean grow_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL || + element == EL_EXPANDABLE_WALL_ANY || + element == EL_EXPANDABLE_WALL || + element == EL_BD_EXPANDABLE_WALL || + element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || + element == EL_EXPANDABLE_STEELWALL_ANY); + + boolean stop_vertical = (element == EL_EXPANDABLE_WALL_VERTICAL || + element == EL_EXPANDABLE_STEELWALL_VERTICAL); + + boolean stop_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL || + element == EL_EXPANDABLE_WALL || + element == EL_EXPANDABLE_STEELWALL_HORIZONTAL); + + int wall_growing = (is_steelwall ? + EL_EXPANDABLE_STEELWALL_GROWING : + EL_EXPANDABLE_WALL_GROWING); + + int gfx_wall_growing_up = (is_steelwall ? + IMG_EXPANDABLE_STEELWALL_GROWING_UP : + IMG_EXPANDABLE_WALL_GROWING_UP); + int gfx_wall_growing_down = (is_steelwall ? + IMG_EXPANDABLE_STEELWALL_GROWING_DOWN : + IMG_EXPANDABLE_WALL_GROWING_DOWN); + int gfx_wall_growing_left = (is_steelwall ? + IMG_EXPANDABLE_STEELWALL_GROWING_LEFT : + IMG_EXPANDABLE_WALL_GROWING_LEFT); + int gfx_wall_growing_right = (is_steelwall ? + IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT : + IMG_EXPANDABLE_WALL_GROWING_RIGHT); if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); @@ -9730,179 +9798,83 @@ static void MauerAbleger(int ax, int ay) } if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1)) - oben_frei = TRUE; + free_top = TRUE; if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1)) - unten_frei = TRUE; + free_bottom = TRUE; if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay)) - links_frei = TRUE; + free_left = TRUE; if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay)) - rechts_frei = TRUE; + free_right = TRUE; - if (element == EL_EXPANDABLE_WALL_VERTICAL || - element == EL_EXPANDABLE_WALL_ANY) + if (grow_vertical) { - if (oben_frei) + if (free_top) { - Tile[ax][ay - 1] = EL_EXPANDABLE_WALL_GROWING; + Tile[ax][ay - 1] = wall_growing; Store[ax][ay - 1] = element; GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP; + if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1))) - DrawLevelGraphic(ax, ay - 1, IMG_EXPANDABLE_WALL_GROWING_UP, 0); - new_wall = TRUE; - } - if (unten_frei) - { - Tile[ax][ay + 1] = EL_EXPANDABLE_WALL_GROWING; - Store[ax][ay + 1] = element; - GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN; - if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1))) - DrawLevelGraphic(ax, ay + 1, IMG_EXPANDABLE_WALL_GROWING_DOWN, 0); - new_wall = TRUE; - } - } + DrawLevelGraphic(ax, ay - 1, gfx_wall_growing_up, 0); - if (element == EL_EXPANDABLE_WALL_HORIZONTAL || - element == EL_EXPANDABLE_WALL_ANY || - element == EL_EXPANDABLE_WALL || - element == EL_BD_EXPANDABLE_WALL) - { - if (links_frei) - { - Tile[ax - 1][ay] = EL_EXPANDABLE_WALL_GROWING; - Store[ax - 1][ay] = element; - GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT; - if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay))) - DrawLevelGraphic(ax - 1, ay, IMG_EXPANDABLE_WALL_GROWING_LEFT, 0); new_wall = TRUE; } - if (rechts_frei) + if (free_bottom) { - Tile[ax + 1][ay] = EL_EXPANDABLE_WALL_GROWING; - Store[ax + 1][ay] = element; - GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT; - if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay))) - DrawLevelGraphic(ax + 1, ay, IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0); - new_wall = TRUE; - } - } - - if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei)) - TEST_DrawLevelField(ax, ay); - - if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1])) - oben_massiv = TRUE; - if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1])) - unten_massiv = TRUE; - if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay])) - links_massiv = TRUE; - if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay])) - rechts_massiv = TRUE; - - if (((oben_massiv && unten_massiv) || - element == EL_EXPANDABLE_WALL_HORIZONTAL || - element == EL_EXPANDABLE_WALL) && - ((links_massiv && rechts_massiv) || - element == EL_EXPANDABLE_WALL_VERTICAL)) - Tile[ax][ay] = EL_WALL; - - if (new_wall) - PlayLevelSoundAction(ax, ay, ACTION_GROWING); -} - -static void MauerAblegerStahl(int ax, int ay) -{ - int element = Tile[ax][ay]; - int graphic = el2img(element); - boolean oben_frei = FALSE, unten_frei = FALSE; - boolean links_frei = FALSE, rechts_frei = FALSE; - boolean oben_massiv = FALSE, unten_massiv = FALSE; - boolean links_massiv = FALSE, rechts_massiv = FALSE; - boolean new_wall = FALSE; - - if (IS_ANIMATED(graphic)) - DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); - - if (!MovDelay[ax][ay]) // start building new wall - MovDelay[ax][ay] = 6; - - if (MovDelay[ax][ay]) // wait some time before building new wall - { - MovDelay[ax][ay]--; - if (MovDelay[ax][ay]) - return; - } - - if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1)) - oben_frei = TRUE; - if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1)) - unten_frei = TRUE; - if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay)) - links_frei = TRUE; - if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay)) - rechts_frei = TRUE; - - if (element == EL_EXPANDABLE_STEELWALL_VERTICAL || - element == EL_EXPANDABLE_STEELWALL_ANY) - { - if (oben_frei) - { - Tile[ax][ay - 1] = EL_EXPANDABLE_STEELWALL_GROWING; - Store[ax][ay - 1] = element; - GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP; - if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1))) - DrawLevelGraphic(ax, ay - 1, IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0); - new_wall = TRUE; - } - if (unten_frei) - { - Tile[ax][ay + 1] = EL_EXPANDABLE_STEELWALL_GROWING; + Tile[ax][ay + 1] = wall_growing; Store[ax][ay + 1] = element; GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN; + if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1))) - DrawLevelGraphic(ax, ay + 1, IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0); + DrawLevelGraphic(ax, ay + 1, gfx_wall_growing_down, 0); + new_wall = TRUE; } } - if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || - element == EL_EXPANDABLE_STEELWALL_ANY) + if (grow_horizontal) { - if (links_frei) + if (free_left) { - Tile[ax - 1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; + Tile[ax - 1][ay] = wall_growing; Store[ax - 1][ay] = element; GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT; + if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay))) - DrawLevelGraphic(ax - 1, ay, IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0); + DrawLevelGraphic(ax - 1, ay, gfx_wall_growing_left, 0); + new_wall = TRUE; } - if (rechts_frei) + if (free_right) { - Tile[ax + 1][ay] = EL_EXPANDABLE_STEELWALL_GROWING; + Tile[ax + 1][ay] = wall_growing; Store[ax + 1][ay] = element; GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT; + if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay))) - DrawLevelGraphic(ax + 1, ay, IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0); + DrawLevelGraphic(ax + 1, ay, gfx_wall_growing_right, 0); + new_wall = TRUE; } } + if (element == EL_EXPANDABLE_WALL && (free_left || free_right)) + TEST_DrawLevelField(ax, ay); + if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1])) - oben_massiv = TRUE; + stop_top = TRUE; if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1])) - unten_massiv = TRUE; + stop_bottom = TRUE; if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay])) - links_massiv = TRUE; + stop_left = TRUE; if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay])) - rechts_massiv = TRUE; + stop_right = TRUE; - if (((oben_massiv && unten_massiv) || - element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) && - ((links_massiv && rechts_massiv) || - element == EL_EXPANDABLE_STEELWALL_VERTICAL)) - Tile[ax][ay] = EL_STEELWALL; + if (((stop_top && stop_bottom) || stop_horizontal) && + ((stop_left && stop_right) || stop_vertical)) + Tile[ax][ay] = (is_steelwall ? EL_STEELWALL : EL_WALL); if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); @@ -11721,6 +11693,21 @@ void AdvanceFrameAndPlayerCounters(int player_nr) } } +void AdvanceFrameCounter(void) +{ + FrameCounter++; +} + +void AdvanceGfxFrame(void) +{ + int x, y; + + SCAN_PLAYFIELD(x, y) + { + GfxFrame[x][y]++; + } +} + void StartGameActions(boolean init_network_game, boolean record_tape, int random_seed) { @@ -11916,7 +11903,7 @@ static void GameActionsExt(void) TapeRecordAction(tape_action); // remember if game was played (especially after tape stopped playing) - if (!tape.playing && summarized_player_action) + if (!tape.playing && summarized_player_action && !checkGameFailed()) game.GamePlayed = TRUE; #if USE_NEW_PLAYER_ASSIGNMENTS @@ -12039,25 +12026,23 @@ void GameActions(void) void GameActions_EM_Main(void) { byte effective_action[MAX_PLAYERS]; - boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; - GameActions_EM(effective_action, warp_mode); + GameActions_EM(effective_action); } void GameActions_SP_Main(void) { byte effective_action[MAX_PLAYERS]; - boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); int i; for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; - GameActions_SP(effective_action, warp_mode); + GameActions_SP(effective_action); for (i = 0; i < MAX_PLAYERS; i++) { @@ -12070,9 +12055,9 @@ void GameActions_SP_Main(void) void GameActions_MM_Main(void) { - boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); + AdvanceGfxFrame(); - GameActions_MM(local_player->effective_mouse_action, warp_mode); + GameActions_MM(local_player->effective_mouse_action); } void GameActions_RND_Main(void) @@ -12136,7 +12121,7 @@ void GameActions_RND(void) game.centered_player_nr = game.centered_player_nr_next; game.set_centered_player = FALSE; - DrawRelocateScreen(0, 0, sx, sy, MV_NONE, TRUE, setup.quick_switch); + DrawRelocateScreen(0, 0, sx, sy, TRUE, setup.quick_switch); DrawGameDoorValues(); } @@ -12433,17 +12418,16 @@ void GameActions_RND(void) CheckExitSP(x, y); else if (element == EL_EXPANDABLE_WALL_GROWING || element == EL_EXPANDABLE_STEELWALL_GROWING) - MauerWaechst(x, y); + WallGrowing(x, y); else if (element == EL_EXPANDABLE_WALL || element == EL_EXPANDABLE_WALL_HORIZONTAL || element == EL_EXPANDABLE_WALL_VERTICAL || element == EL_EXPANDABLE_WALL_ANY || - element == EL_BD_EXPANDABLE_WALL) - MauerAbleger(x, y); - else if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || + element == EL_BD_EXPANDABLE_WALL || + element == EL_EXPANDABLE_STEELWALL_HORIZONTAL || element == EL_EXPANDABLE_STEELWALL_VERTICAL || element == EL_EXPANDABLE_STEELWALL_ANY) - MauerAblegerStahl(x, y); + CheckWallGrowing(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); else if (element == EL_EXPLOSION) @@ -12452,7 +12436,7 @@ void GameActions_RND(void) element == EL_DIAGONAL_SHRINKING || element == EL_DIAGONAL_GROWING) { - graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); + graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], GfxDir[x][y]); DrawLevelGraphicAnimationIfNeeded(x, y, graphic); } @@ -12497,7 +12481,7 @@ void GameActions_RND(void) y = RND(lev_fieldy); element = Tile[x][y]; - if (!IS_PLAYER(x,y) && + if (!IS_PLAYER(x, y) && (element == EL_EMPTY || CAN_GROW_INTO(element) || element == EL_QUICKSAND_EMPTY || @@ -12873,7 +12857,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; - can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG); + can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx, real_dy, DF_DIG); if (can_move != MP_MOVING) return can_move; @@ -13967,7 +13951,7 @@ void KillPlayer(struct PlayerInfo *player) player->killed = TRUE; // remove accessible field at the player's position - Tile[jx][jy] = EL_EMPTY; + RemoveField(jx, jy); // deactivate shield (else Bang()/Explode() would not work right) player->shield_normal_time_left = 0; @@ -14013,7 +13997,6 @@ void BuryPlayer(struct PlayerInfo *player) return; PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING); - PlayLevelSound(jx, jy, SND_GAME_LOSING); RemovePlayer(player); @@ -14192,7 +14175,7 @@ static int DigField(struct PlayerInfo *player, if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) return MP_NO_ACTION; // field has no opening in this direction - if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) + if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element, opposite_direction)) return MP_NO_ACTION; // field has no opening in this direction if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) @@ -14430,9 +14413,13 @@ static int DigField(struct PlayerInfo *player, } else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) { - player->shield_normal_time_left += level.shield_normal_time; + int shield_time = (element == EL_SHIELD_DEADLY ? + level.shield_deadly_time : + level.shield_normal_time); + + player->shield_normal_time_left += shield_time; if (element == EL_SHIELD_DEADLY) - player->shield_deadly_time_left += level.shield_deadly_time; + player->shield_deadly_time_left += shield_time; } else if (element == EL_DYNAMITE || element == EL_EM_DYNAMITE || @@ -14667,7 +14654,7 @@ static int DigField(struct PlayerInfo *player, LevelSolved(); - PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); + PlaySound(SND_GAME_SOKOBAN_SOLVING); } } else @@ -14752,7 +14739,7 @@ static int DigField(struct PlayerInfo *player, element == EL_DC_SWITCHGATE_SWITCH_UP || element == EL_DC_SWITCHGATE_SWITCH_DOWN) { - ToggleSwitchgateSwitch(x, y); + ToggleSwitchgateSwitch(); } else if (element == EL_LIGHT_SWITCH || element == EL_LIGHT_SWITCH_ACTIVE) @@ -15645,21 +15632,43 @@ void RequestQuitGame(boolean escape_key_pressed) "Do you really want to quit the game?"); } -void RequestRestartGame(char *message) +static char *getRestartGameMessage(void) { - game.restart_game_message = NULL; + boolean play_again = hasStartedNetworkGame(); + static char message[MAX_OUTPUT_LINESIZE]; + char *game_over_text = "Game over!"; + char *play_again_text = " Play it again?"; + + if (level.game_engine_type == GAME_ENGINE_TYPE_MM && + game_mm.game_over_message != NULL) + game_over_text = game_mm.game_over_message; + snprintf(message, MAX_OUTPUT_LINESIZE, "%s%s", game_over_text, + (play_again ? play_again_text : "")); + + return message; +} + +static void RequestRestartGame(void) +{ + char *message = getRestartGameMessage(); boolean has_started_game = hasStartedNetworkGame(); int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM); + int door_state = DOOR_CLOSE_1; - if (Request(message, request_mode | REQ_STAY_CLOSED) && has_started_game) + if (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game) { + CloseDoor(door_state); + StartGameActions(network.enabled, setup.autorecord, level.random_seed); } else { - // needed in case of envelope request to close game panel - CloseDoor(DOOR_CLOSE_1); + // if game was invoked from level editor, also close tape recorder door + if (level_editor_test_game) + door_state = DOOR_CLOSE_ALL; + + CloseDoor(door_state); SetGameStatus(GAME_MODE_MAIN); @@ -15667,42 +15676,44 @@ void RequestRestartGame(char *message) } } -void CheckGameOver(void) +boolean CheckRestartGame(void) { - static boolean last_game_over = FALSE; static int game_over_delay = 0; int game_over_delay_value = 50; boolean game_over = checkGameFailed(); - // do not handle game over if request dialog is already active - if (game.request_active) - return; - - // do not ask to play again if game was never actually played - if (!game.GamePlayed) - return; - if (!game_over) { - last_game_over = FALSE; game_over_delay = game_over_delay_value; - return; + return FALSE; } if (game_over_delay > 0) { + if (game_over_delay == game_over_delay_value / 2) + PlaySound(SND_GAME_LOSING); + game_over_delay--; - return; + return FALSE; } - if (last_game_over != game_over) - game.restart_game_message = (hasStartedNetworkGame() ? - "Game over! Play it again?" : - "Game over!"); + // do not handle game over if request dialog is already active + if (game.request_active) + return FALSE; - last_game_over = game_over; + // do not ask to play again if game was never actually played + if (!game.GamePlayed) + return FALSE; + + // do not ask to play again if this was disabled in setup menu + if (!setup.ask_on_game_over) + return FALSE; + + RequestRestartGame(); + + return TRUE; } boolean checkGameSolved(void) @@ -15886,7 +15897,7 @@ static ListNode *SaveEngineSnapshotBuffers(void) if (level.game_engine_type == GAME_ENGINE_TYPE_SP) SaveEngineSnapshotValues_SP(&buffers); if (level.game_engine_type == GAME_ENGINE_TYPE_MM) - SaveEngineSnapshotValues_MM(&buffers); + SaveEngineSnapshotValues_MM(); // save values stored in special snapshot structure