X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=8978e70750489ebe4c15af503f0d3ae9c461537c;hp=2e951c1761a96476b13fa9436cb5d6e0d254a2dc;hb=47da774c66f9325f9d27cddb5a697514154e2de9;hpb=50a54138903c0bbbe409a7d1da14a92b77babacb diff --git a/src/game.c b/src/game.c index 2e951c17..8978e707 100644 --- a/src/game.c +++ b/src/game.c @@ -1,15 +1,13 @@ -/*********************************************************** -* Rocks'n'Diamonds -- McDuffin Strikes Back! * -*----------------------------------------------------------* -* (c) 1995-2006 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* game.c * -***********************************************************/ +// ============================================================================ +// Rocks'n'Diamonds - McDuffin Strikes Back! +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// game.c +// ============================================================================ #include "libgame/libgame.h" @@ -17,9 +15,11 @@ #include "init.h" #include "tools.h" #include "screens.h" +#include "events.h" #include "files.h" #include "tape.h" #include "network.h" +#include "anim.h" /* DEBUG SETTINGS */ @@ -30,49 +30,10 @@ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ -#define USE_NEW_STUFF ( 1) - -#define USE_NEW_SP_SLIPPERY (USE_NEW_STUFF * 1) -#define USE_NEW_CUSTOM_VALUE (USE_NEW_STUFF * 1) -#define USE_NEW_PLAYER_ANIM (USE_NEW_STUFF * 1) -#define USE_NEW_ALL_SLIPPERY (USE_NEW_STUFF * 1) -#define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1) -#define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1) -#define USE_NEW_SNAP_DELAY (USE_NEW_STUFF * 1) -#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) -#define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) -#define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1) -#define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1) -#define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1) -#define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1) -#define USE_NEW_CONTINUOUS_SNAPPING (USE_NEW_STUFF * 1) -#define USE_GFX_RESET_GFX_ANIMATION (USE_NEW_STUFF * 1) -#define USE_BOTH_SWITCHGATE_SWITCHES (USE_NEW_STUFF * 1) -#define USE_PLAYER_GRAVITY (USE_NEW_STUFF * 1) -#define USE_FIXED_BORDER_RUNNING_GFX (USE_NEW_STUFF * 1) -#define USE_QUICKSAND_BD_ROCK_BUGFIX (USE_NEW_STUFF * 0) - -#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) - -#define USE_CODE_THAT_BREAKS_SNAKE_BITE (USE_NEW_STUFF * 1) - -#define USE_UFAST_PLAYER_EXIT_BUGFIX (USE_NEW_STUFF * 1) - -#define USE_GFX_RESET_ONLY_WHEN_MOVING (USE_NEW_STUFF * 1) -#define USE_GFX_RESET_PLAYER_ARTWORK (USE_NEW_STUFF * 1) - -#define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) -#define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) -#define USE_FIX_CE_ACTION_WITH_PLAYER (USE_NEW_STUFF * 1) -#define USE_FIX_NO_ACTION_AFTER_CHANGE (USE_NEW_STUFF * 1) - -#define USE_PLAYER_REANIMATION (USE_NEW_STUFF * 1) - -#define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1) - -#define USE_NEW_PLAYER_ASSIGNMENTS (USE_NEW_STUFF * 1) - -#define USE_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 0) +#define USE_QUICKSAND_BD_ROCK_BUGFIX 0 +#define USE_QUICKSAND_IMPACT_BUGFIX 0 +#define USE_DELAYED_GFX_REDRAW 0 +#define USE_NEW_PLAYER_ASSIGNMENTS 1 #if USE_DELAYED_GFX_REDRAW #define TEST_DrawLevelField(x, y) \ @@ -866,6 +827,14 @@ static struct GamePanelControlInfo game_panel_controls[] = #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY( (p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) +/* values for scroll positions */ +#define SCROLL_POSITION_X(x) ((x) < SBX_Left + MIDPOSX ? SBX_Left : \ + (x) > SBX_Right + MIDPOSX ? SBX_Right :\ + (x) - MIDPOSX) +#define SCROLL_POSITION_Y(y) ((y) < SBY_Upper + MIDPOSY ? SBY_Upper :\ + (y) > SBY_Lower + MIDPOSY ? SBY_Lower :\ + (y) - MIDPOSY) + /* values for other actions */ #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) #define MOVE_STEPSIZE_MIN (1) @@ -1011,13 +980,16 @@ static struct GamePanelControlInfo game_panel_controls[] = #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 -#define SOUND_CTRL_ID_MUSIC 3 -#define SOUND_CTRL_ID_LOOPS 4 -#define SOUND_CTRL_ID_SIMPLE 5 -#define GAME_CTRL_ID_SAVE 6 +#define GAME_CTRL_ID_UNDO 3 +#define GAME_CTRL_ID_REDO 4 +#define GAME_CTRL_ID_SAVE 5 +#define GAME_CTRL_ID_PAUSE2 6 #define GAME_CTRL_ID_LOAD 7 +#define SOUND_CTRL_ID_MUSIC 8 +#define SOUND_CTRL_ID_LOOPS 9 +#define SOUND_CTRL_ID_SIMPLE 10 -#define NUM_GAME_BUTTONS 8 +#define NUM_GAME_BUTTONS 11 /* forward declaration for internal use */ @@ -1049,9 +1021,6 @@ static void KillPlayerUnlessExplosionProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); static void TestIfElementHitsCustomElement(int, int, int); -#if 0 -static void TestIfElementSmashesCustomElement(int, int, int); -#endif static void HandleElementChange(int, int, int); static void ExecuteCustomElementAction(int, int, int, int); @@ -1237,11 +1206,7 @@ static struct ChangingElementInfo change_delay_list[] = }, { EL_EM_EXIT_CLOSING, -#if 1 EL_EMPTY, -#else - EL_EM_EXIT_CLOSED, -#endif 29, NULL, NULL, @@ -1257,11 +1222,7 @@ static struct ChangingElementInfo change_delay_list[] = }, { EL_EM_STEEL_EXIT_CLOSING, -#if 1 EL_STEELWALL, -#else - EL_EM_STEEL_EXIT_CLOSED, -#endif 29, NULL, NULL, @@ -1658,7 +1619,6 @@ void GetPlayerConfig() setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music); SetAudioMode(setup.sound); - InitJoysticks(); } int GetElementFromGroupElement(int element) @@ -1763,7 +1723,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) player->jy = player->last_jy = y; } -#if USE_PLAYER_REANIMATION if (!init_game) { int player_nr = GET_PLAYER_NR(element); @@ -1772,7 +1731,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) if (player->active && player->killed) player->reanimated = TRUE; /* if player was just killed, reanimate him */ } -#endif } static void InitField(int x, int y, boolean init_game) @@ -1925,18 +1883,6 @@ static void InitField(int x, int y, boolean init_game) } break; -#if !USE_BOTH_SWITCHGATE_SWITCHES - case EL_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */ - if (init_game) - Feld[x][y] = EL_SWITCHGATE_SWITCH_UP; - break; - - case EL_DC_SWITCHGATE_SWITCH_DOWN: /* always start with same switch pos */ - if (init_game) - Feld[x][y] = EL_DC_SWITCHGATE_SWITCH_UP; - break; -#endif - case EL_LIGHT_SWITCH_ACTIVE: if (init_game) game.light_time_left = level.time_light * FRAMES_PER_SECOND; @@ -1994,10 +1940,8 @@ static void InitField(int x, int y, boolean init_game) if (CAN_MOVE(element)) InitMovDir(x, y); -#if USE_NEW_CUSTOM_VALUE if (!element_info[element].use_last_ce_value || init_game) CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); -#endif } else if (IS_GROUP_ELEMENT(element)) { @@ -2013,7 +1957,7 @@ static void InitField(int x, int y, boolean init_game) CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); } -static inline void InitField_WithBug1(int x, int y, boolean init_game) +inline static void InitField_WithBug1(int x, int y, boolean init_game) { InitField(x, y, init_game); @@ -2023,7 +1967,7 @@ static inline void InitField_WithBug1(int x, int y, boolean init_game) InitMovDir(x, y); } -static inline void InitField_WithBug2(int x, int y, boolean init_game) +inline static void InitField_WithBug2(int x, int y, boolean init_game) { int old_element = Feld[x][y]; @@ -2113,6 +2057,16 @@ static int compareGamePanelOrderInfo(const void *object1, const void *object2) return compare_result; } +int getPlayerInventorySize(int player_nr) +{ + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return level.native_em_level->ply[player_nr]->dynamite; + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + return level.native_sp_level->game_sp->red_disk_count; + else + return stored_player[player_nr].inventory_size; +} + void InitGameControlValues() { int i; @@ -2250,15 +2204,8 @@ void UpdateGameControlValues() get_key_element_from_nr(k); } - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - level.native_em_level->ply[i]->dynamite; - else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - level.native_sp_level->game_sp->red_disk_count; - else - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - stored_player[i].inventory_size; + game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += + getPlayerInventorySize(i); if (stored_player[i].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = @@ -2285,15 +2232,8 @@ void UpdateGameControlValues() get_key_element_from_nr(k); } - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - level.native_em_level->ply[player_nr]->dynamite; - else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - level.native_sp_level->game_sp->red_disk_count; - else - game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += - stored_player[player_nr].inventory_size; + game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += + getPlayerInventorySize(player_nr); if (stored_player[player_nr].num_white_keys > 0) game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; @@ -2403,12 +2343,8 @@ void UpdateGameControlValues() game_panel_controls[GAME_PANEL_MAGIC_WALL_TIME].value = game.magic_wall_time_left; -#if USE_PLAYER_GRAVITY game_panel_controls[GAME_PANEL_GRAVITY_STATE].value = local_player->gravity; -#else - game_panel_controls[GAME_PANEL_GRAVITY_STATE].value = game.gravity; -#endif for (i = 0; i < NUM_PANEL_GRAPHICS; i++) game_panel_controls[GAME_PANEL_GRAPHIC_1 + i].value = EL_GRAPHIC_1 + i; @@ -2505,47 +2441,25 @@ void DisplayGameControlValues() return; /* copy default game door content to main double buffer */ -#if 1 + /* !!! CHECK AGAIN !!! */ SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); -#else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); -#endif /* redraw game control buttons */ -#if 1 RedrawGameButtons(); -#else - UnmapGameButtons(); - MapGameButtons(); -#endif - game_status = GAME_MODE_PSEUDO_PANEL; + SetGameStatus(GAME_MODE_PSEUDO_PANEL); -#if 1 for (i = 0; i < NUM_GAME_PANEL_CONTROLS; i++) -#else - for (i = 0; game_panel_controls[i].nr != -1; i++) -#endif { -#if 1 int nr = game_panel_order[i].nr; struct GamePanelControlInfo *gpc = &game_panel_controls[nr]; -#else - struct GamePanelControlInfo *gpc = &game_panel_controls[i]; - int nr = gpc->nr; -#endif struct TextPosInfo *pos = gpc->pos; int type = gpc->type; int value = gpc->value; int frame = gpc->frame; -#if 0 - int last_value = gpc->last_value; - int last_frame = gpc->last_frame; -#endif int size = pos->size; int font = pos->font; boolean draw_masked = pos->draw_masked; @@ -2554,18 +2468,9 @@ void DisplayGameControlValues() if (PANEL_DEACTIVATED(pos)) continue; -#if 0 - if (value == last_value && frame == last_frame) - continue; -#endif - gpc->last_value = value; gpc->last_frame = frame; -#if 0 - printf("::: value %d changed from %d to %d\n", nr, last_value, value); -#endif - if (type == TYPE_INTEGER) { if (nr == GAME_PANEL_LEVEL_NUMBER || @@ -2583,33 +2488,15 @@ void DisplayGameControlValues() size = (value < value_change ? size1 : size2); font = (value < value_change ? font1 : font2); - -#if 0 - /* clear background if value just changed its size (dynamic digits) */ - if ((last_value < value_change) != (value < value_change)) - { - int width1 = size1 * getFontWidth(font1); - int width2 = size2 * getFontWidth(font2); - int max_width = MAX(width1, width2); - int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); - - pos->width = max_width; - - ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), - max_width, max_height); - } -#endif } } -#if 1 /* correct text size if "digits" is zero or less */ if (size <= 0) size = strlen(int2str(value, size)); /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); -#endif DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, size), font, mask_mode); @@ -2623,7 +2510,6 @@ void DisplayGameControlValues() int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); -#if 1 if (value != EL_UNDEFINED && value != EL_EMPTY) { element = value; @@ -2631,10 +2517,8 @@ void DisplayGameControlValues() // printf("::: %d, '%s' [%d]\n", element, EL_NAME(element), size); -#if 1 if (element >= EL_GRAPHIC_1 && element <= EL_GRAPHIC_8 && size == 0) size = TILESIZE; -#endif getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x, &src_y); @@ -2643,41 +2527,12 @@ void DisplayGameControlValues() height = graphic_info[graphic].height * size / TILESIZE; if (draw_masked) - { - SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, - dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); - } else - { BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); - } - } -#else - if (value == EL_UNDEFINED || value == EL_EMPTY) - { - element = (last_value == EL_UNDEFINED ? EL_EMPTY : last_value); - graphic = el2panelimg(element); - - src_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; - src_x = DOOR_GFX_PAGEX5 + ALIGNED_TEXT_XPOS(pos); - src_y = DOOR_GFX_PAGEY1 + ALIGNED_TEXT_YPOS(pos); - } - else - { - element = value; - graphic = el2panelimg(value); - - getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x,&src_y); } - - width = graphic_info[graphic].width * size / TILESIZE; - height = graphic_info[graphic].height * size / TILESIZE; - - BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); -#endif } else if (type == TYPE_STRING) { @@ -2694,20 +2549,6 @@ void DisplayGameControlValues() { int font1 = pos->font; /* (used for normal state) */ int font2 = pos->font_alt; /* (used for active state) */ -#if 0 - int size1 = strlen(state_normal); - int size2 = strlen(state_active); - int width1 = size1 * getFontWidth(font1); - int width2 = size2 * getFontWidth(font2); - int max_width = MAX(width1, width2); - int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); - - pos->width = max_width; - - /* clear background for values that may have changed its size */ - ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), - max_width, max_height); -#endif font = (active ? font2 : font1); } @@ -2716,7 +2557,6 @@ void DisplayGameControlValues() { char *s_cut; -#if 1 if (size <= 0) { /* don't truncate output if "chars" is zero or less */ @@ -2725,7 +2565,6 @@ void DisplayGameControlValues() /* dynamically correct text alignment */ pos->width = size * getFontWidth(font); } -#endif s_cut = getStringCopyN(s, size); @@ -2739,228 +2578,18 @@ void DisplayGameControlValues() redraw_mask |= REDRAW_DOOR_1; } - game_status = GAME_MODE_PLAYING; + SetGameStatus(GAME_MODE_PLAYING); } void UpdateAndDisplayGameControlValues() { - if (tape.warp_forward) + if (tape.deactivate_display) return; UpdateGameControlValues(); DisplayGameControlValues(); } -void DrawGameValue_Emeralds(int value) -{ - struct TextPosInfo *pos = &game.panel.gems; - int font_nr = pos->font; - int font_width = getFontWidth(font_nr); - int chars = pos->size; - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - if (PANEL_DEACTIVATED(pos)) - return; - - pos->width = chars * font_width; - - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); -} - -void DrawGameValue_Dynamite(int value) -{ - struct TextPosInfo *pos = &game.panel.inventory_count; - int font_nr = pos->font; - int font_width = getFontWidth(font_nr); - int chars = pos->size; - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - if (PANEL_DEACTIVATED(pos)) - return; - - pos->width = chars * font_width; - - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); -} - -void DrawGameValue_Score(int value) -{ - struct TextPosInfo *pos = &game.panel.score; - int font_nr = pos->font; - int font_width = getFontWidth(font_nr); - int chars = pos->size; - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - if (PANEL_DEACTIVATED(pos)) - return; - - pos->width = chars * font_width; - - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); -} - -void DrawGameValue_Time(int value) -{ - struct TextPosInfo *pos = &game.panel.time; - static int last_value = -1; - int chars1 = 3; - int chars2 = 4; - int chars = pos->size; - int font1_nr = pos->font; - int font2_nr = pos->font_alt; - int font_nr = font1_nr; - boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - if (PANEL_DEACTIVATED(pos)) - return; - - if (use_dynamic_chars) /* use dynamic number of chars */ - { - chars = (value < 1000 ? chars1 : chars2); - font_nr = (value < 1000 ? font1_nr : font2_nr); - } - - /* clear background if value just changed its size (dynamic chars only) */ - if (use_dynamic_chars && (last_value < 1000) != (value < 1000)) - { - int width1 = chars1 * getFontWidth(font1_nr); - int width2 = chars2 * getFontWidth(font2_nr); - int max_width = MAX(width1, width2); - int max_height = MAX(getFontHeight(font1_nr), getFontHeight(font2_nr)); - - pos->width = max_width; - - ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), - max_width, max_height); - } - - pos->width = chars * getFontWidth(font_nr); - - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); - - last_value = value; -} - -void DrawGameValue_Level(int value) -{ - struct TextPosInfo *pos = &game.panel.level_number; - int chars1 = 2; - int chars2 = 3; - int chars = pos->size; - int font1_nr = pos->font; - int font2_nr = pos->font_alt; - int font_nr = font1_nr; - boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - if (PANEL_DEACTIVATED(pos)) - return; - - if (use_dynamic_chars) /* use dynamic number of chars */ - { - chars = (level_nr < 100 ? chars1 : chars2); - font_nr = (level_nr < 100 ? font1_nr : font2_nr); - } - - pos->width = chars * getFontWidth(font_nr); - - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); -} - -void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) -{ - int i; - -#if 1 - return; /* !!! USE NEW STUFF !!! */ -#endif - - for (i = 0; i < MAX_NUM_KEYS; i++) - { - struct TextPosInfo *pos = &game.panel.key[i]; - int src_x = DOOR_GFX_PAGEX5 + 18 + (i % 4) * MINI_TILEX; - int src_y = DOOR_GFX_PAGEY1 + 123; - int dst_x = PANEL_XPOS(pos); - int dst_y = PANEL_YPOS(pos); - - int element = (i >= STD_NUM_KEYS ? EL_EMC_KEY_5 - 4 : - level.game_engine_type == GAME_ENGINE_TYPE_EM ? EL_EM_KEY_1 : - EL_KEY_1) + i; - int graphic = el2edimg(element); - - if (PANEL_DEACTIVATED(pos)) - continue; - -#if 0 - /* masked blit with tiles from half-size scaled bitmap does not work yet - (no mask bitmap created for these sizes after loading and scaling) -- - solution: load without creating mask, scale, then create final mask */ - - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, - MINI_TILEX, MINI_TILEY, dst_x, dst_y); - - if (key[i]) - { - Bitmap *src_bitmap; - int src_x, src_y; - - getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y); - - SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, - dst_x - src_x, dst_y - src_y); - BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, - dst_x, dst_y); - } -#else - if (key[i]) - DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); - else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, - MINI_TILEX, MINI_TILEY, dst_x, dst_y); -#endif - } -} - -void DrawAllGameValues(int emeralds, int dynamite, int score, int time, - int key_bits) -{ - int key[MAX_NUM_KEYS]; - int i; - - /* prevent EM engine from updating time/score values parallel to GameWon() */ - if (level.game_engine_type == GAME_ENGINE_TYPE_EM && - local_player->LevelSolved) - return; - - for (i = 0; i < MAX_NUM_KEYS; i++) - key[i] = key_bits & (1 << i); - - DrawGameValue_Level(level_nr); - - DrawGameValue_Emeralds(emeralds); - DrawGameValue_Dynamite(dynamite); - DrawGameValue_Score(score); - DrawGameValue_Time(time); - - DrawGameValue_Keys(key); -} - void UpdateGameDoorValues() { UpdateGameControlValues(); @@ -2971,49 +2600,6 @@ void DrawGameDoorValues() DisplayGameControlValues(); } -void DrawGameDoorValues_OLD() -{ - int time_value = (game.no_time_limit ? TimePlayed : TimeLeft); - int dynamite_value = 0; - int score_value = (local_player->LevelSolved ? local_player->score_final : - local_player->score); - int gems_value = local_player->gems_still_needed; - int key_bits = 0; - int i, j; - - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - { - DrawGameDoorValues_EM(); - - return; - } - - if (game.centered_player_nr == -1) - { - for (i = 0; i < MAX_PLAYERS; i++) - { - for (j = 0; j < MAX_NUM_KEYS; j++) - if (stored_player[i].key[j]) - key_bits |= (1 << j); - - dynamite_value += stored_player[i].inventory_size; - } - } - else - { - int player_nr = game.centered_player_nr; - - for (i = 0; i < MAX_NUM_KEYS; i++) - if (stored_player[player_nr].key[i]) - key_bits |= (1 << i); - - dynamite_value = stored_player[player_nr].inventory_size; - } - - DrawAllGameValues(gems_value, dynamite_value, score_value, time_value, - key_bits); -} - /* ============================================================================= @@ -3112,39 +2698,13 @@ static void InitGameEngine() game.use_block_last_field_bug = (game.engine_version < VERSION_IDENT(3,1,1,0)); - /* - Summary of bugfix/change: - Changed behaviour of CE changes with multiple changes per single frame. - - Fixed/changed in version: - 3.2.0-6 - - Description: - Before 3.2.0-6, only one single CE change was allowed in each engine frame. - This resulted in race conditions where CEs seem to behave strange in some - situations (where triggered CE changes were just skipped because there was - already a CE change on that tile in the playfield in that engine frame). - Since 3.2.0-6, this was changed to allow up to MAX_NUM_CHANGES_PER_FRAME. - (The number of changes per frame must be limited in any case, because else - it is easily possible to define CE changes that would result in an infinite - loop, causing the whole game to freeze. The MAX_NUM_CHANGES_PER_FRAME value - should be set large enough so that it would only be reached in cases where - the corresponding CE change conditions run into a loop. Therefore, it seems - to be reasonable to set MAX_NUM_CHANGES_PER_FRAME to the same value as the - maximal number of change pages for custom elements.) + game_em.use_single_button = + (game.engine_version > VERSION_IDENT(4,0,0,2)); - Affected levels/tapes: - Probably many. - */ + /* ---------------------------------------------------------------------- */ -#if USE_ONLY_ONE_CHANGE_PER_FRAME + /* set maximal allowed number of custom element changes per game frame */ game.max_num_changes_per_frame = 1; -#else - game.max_num_changes_per_frame = - (game.engine_version < VERSION_IDENT(3,2,0,6) ? 1 : 32); -#endif - - /* ---------------------------------------------------------------------- */ /* default scan direction: scan playfield from top/left to bottom/right */ InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL); @@ -3266,7 +2826,6 @@ static void InitGameEngine() } } -#if 1 /* ---------- initialize reference elements in change conditions --------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -3285,7 +2844,6 @@ static void InitGameEngine() ei->change_page[j].trigger_element = trigger_element; } } -#endif /* ---------- initialize run-time trigger player and element ------------- */ @@ -3484,6 +3042,20 @@ static void InitGameEngine() setup.scroll_delay ? setup.scroll_delay_value : 0); game.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); + + /* ---------- initialize game engine snapshots ---------------------------- */ + for (i = 0; i < MAX_PLAYERS; i++) + game.snapshot.last_action[i] = 0; + game.snapshot.changed_action = FALSE; + game.snapshot.collected_item = FALSE; + game.snapshot.mode = + (strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_STEP) ? + SNAPSHOT_MODE_EVERY_STEP : + strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_MOVE) ? + SNAPSHOT_MODE_EVERY_MOVE : + strEqual(setup.engine_snapshot_mode, STR_SNAPSHOT_MODE_EVERY_COLLECT) ? + SNAPSHOT_MODE_EVERY_COLLECT : SNAPSHOT_MODE_OFF); + game.snapshot.save_snapshot = FALSE; } int get_num_special_action(int element, int action_first, int action_last) @@ -3522,69 +3094,44 @@ void InitGame() { 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 emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ -#if 0 - boolean do_fading = (game_status == GAME_MODE_MAIN); -#endif -#if 1 int initial_move_dir = MV_DOWN; -#else - int initial_move_dir = MV_NONE; -#endif int i, j, x, y; -#if 1 - game_status = GAME_MODE_PLAYING; -#endif - -#if 1 - - StopAnimation(); + // required here to update video display before fading (FIX THIS) + DrawMaskedBorder(REDRAW_DOOR_2); if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); -#if 1 + SetGameStatus(GAME_MODE_PLAYING); + if (level_editor_test_game) FadeSkipNextFadeIn(); else FadeSetEnterScreen(); -#else - if (level_editor_test_game) - fading = fading_none; - else - fading = menu.destination; -#endif -#if 1 - FadeOut(REDRAW_FIELD); -#else - if (do_fading) - FadeOut(REDRAW_FIELD); -#endif + if (CheckIfGlobalBorderHasChanged()) + fade_mask = REDRAW_ALL; -#endif + FadeSoundsAndMusic(); -#if 0 - printf("::: FADING OUT: DONE\n"); - Delay(1000); -#endif + ExpireSoundLoops(TRUE); -#if 0 - game_status = GAME_MODE_PLAYING; -#endif + FadeOut(fade_mask); -#if 1 /* needed if different viewport properties defined for playing */ ChangeViewportPropertiesIfNeeded(); -#endif -#if 1 + ClearField(); + + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); + DrawCompleteVideoDisplay(); -#endif InitGameEngine(); InitGameControlValues(); @@ -3672,6 +3219,13 @@ void InitGame() player->is_bored = FALSE; player->is_sleeping = FALSE; + player->was_waiting = TRUE; + player->was_moving = FALSE; + player->was_snapping = FALSE; + player->was_dropping = FALSE; + + player->force_dropping = FALSE; + player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; @@ -3784,11 +3338,6 @@ void InitGame() game.switchgate_pos = 0; game.wind_direction = level.wind_direction_initial; -#if !USE_PLAYER_GRAVITY - game.gravity = FALSE; - game.explosions_delayed = TRUE; -#endif - game.lenses_time_left = 0; game.magnify_time_left = 0; @@ -3831,9 +3380,7 @@ void InitGame() MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; -#if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; /* initialized in InitField() */ -#endif Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; @@ -3894,7 +3441,6 @@ void InitGame() emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); -#if USE_NEW_ALL_SLIPPERY /* initialize type of slippery elements */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { @@ -3912,7 +3458,6 @@ void InitGame() element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; } } -#endif /* initialize explosion and ignition delay */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) @@ -3932,14 +3477,6 @@ void InitGame() if (i == EL_BLACK_ORB) element_info[i].ignition_delay = 1; } - -#if 0 - if (element_info[i].explosion_delay < 1) /* !!! check again !!! */ - element_info[i].explosion_delay = 1; - - if (element_info[i].ignition_delay < 1) /* !!! check again !!! */ - element_info[i].ignition_delay = 1; -#endif } /* correct non-moving belts to start moving left */ @@ -3958,23 +3495,10 @@ void InitGame() local_player->connected = TRUE; /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ -#if 0 - printf("::: TEAM MODE: %d\n", game.team_mode); -#endif - if (tape.playing) { -#if 1 for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = tape.player_participates[i]; -#else - /* try to guess locally connected team mode players (needed for correct - assignment of player figures from level to locally playing players) */ - - for (i = 0; i < MAX_PLAYERS; i++) - if (tape.player_participates[i]) - stored_player[i].connected = TRUE; -#endif } else if (game.team_mode && !options.network) { @@ -4031,7 +3555,6 @@ void InitGame() /* assign first free player found that is present in the playfield */ -#if 1 /* first try: look for unmapped playfield player that is not connected */ for (j = 0; j < MAX_PLAYERS; j++) if (field_player == NULL && @@ -4046,22 +3569,6 @@ void InitGame() stored_player[j].present && !stored_player[j].mapped) field_player = &stored_player[j]; -#else - /* first try: look for unmapped playfield player that is not connected */ - if (field_player == NULL) - for (j = 0; j < MAX_PLAYERS; j++) - if (stored_player[j].present && - !stored_player[j].mapped && - !stored_player[j].connected) - field_player = &stored_player[j]; - - /* second try: look for *any* unmapped playfield player */ - if (field_player == NULL) - for (j = 0; j < MAX_PLAYERS; j++) - if (stored_player[j].present && - !stored_player[j].mapped) - field_player = &stored_player[j]; -#endif if (field_player != NULL) { @@ -4184,26 +3691,25 @@ void InitGame() #if USE_NEW_PLAYER_ASSIGNMENTS -#if 1 if (!game.team_mode) -#endif - - for (i = 0; i < MAX_PLAYERS; i++) { - if (stored_player[i].active && - !tape.player_participates[map_player_action[i]]) + for (i = 0; i < MAX_PLAYERS; i++) { - struct PlayerInfo *player = &stored_player[i]; - int jx = player->jx, jy = player->jy; + if (stored_player[i].active && + !tape.player_participates[map_player_action[i]]) + { + struct PlayerInfo *player = &stored_player[i]; + int jx = player->jx, jy = player->jy; #if DEBUG_INIT_PLAYER - if (options.debug) - printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy); + if (options.debug) + printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy); #endif - player->active = FALSE; - StorePlayer[jx][jy] = 0; - Feld[jx][jy] = EL_EMPTY; + player->active = FALSE; + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_EMPTY; + } } } @@ -4302,55 +3808,15 @@ void InitGame() SBY_Lower = lev_fieldy - SCR_FIELDY + 1; } -#if NEW_TILESIZE - - // printf("::: START-0: %d, %d\n", lev_fieldx, SCR_FIELDX); - // printf("::: START-1: %d, %d\n", SBX_Left, SBX_Right); - -#if 1 if (full_lev_fieldx <= SCR_FIELDX) SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; - if (full_lev_fieldy <= SCR_FIELDY) SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; -#else - if (lev_fieldx + (SBX_Left < 0 ? 2 : 0) <= SCR_FIELDX) - SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; - - if (lev_fieldy + (SBY_Upper < 0 ? 2 : 0) <= SCR_FIELDY) - SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; -#endif - - /* - printf("::: START-2: %d, %d (%d)\n", SBX_Left, SBX_Right, - SBX_Right - SBX_Left + 1); - */ -#if 1 if (EVEN(SCR_FIELDX) && full_lev_fieldx > SCR_FIELDX) SBX_Left--; if (EVEN(SCR_FIELDY) && full_lev_fieldy > SCR_FIELDY) SBY_Upper--; -#else - if (EVEN(SCR_FIELDX)) - SBX_Left--; - if (EVEN(SCR_FIELDY)) - SBY_Upper--; -#endif - -#if 0 - printf("::: START-3: %d, %d\n", SBX_Left, SBX_Right); - printf("\n"); -#endif - -#else - - if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX) - SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; - - if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY) - SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; -#endif /* if local player not found, look for custom element that might create the player (make some assumptions about the right custom element) */ @@ -4442,84 +3908,23 @@ void InitGame() } } - scroll_x = (start_x < SBX_Left + MIDPOSX ? SBX_Left : - start_x > SBX_Right + MIDPOSX ? SBX_Right : - start_x - MIDPOSX); - - scroll_y = (start_y < SBY_Upper + MIDPOSY ? SBY_Upper : - start_y > SBY_Lower + MIDPOSY ? SBY_Lower : - start_y - MIDPOSY); + scroll_x = SCROLL_POSITION_X(start_x); + scroll_y = SCROLL_POSITION_Y(start_y); } else { - scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : - local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : - local_player->jx - MIDPOSX); - - scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : - local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : - local_player->jy - MIDPOSY); + scroll_x = SCROLL_POSITION_X(local_player->jx); + scroll_y = SCROLL_POSITION_Y(local_player->jy); } -#if 0 - printf("::: %d, %d (initial)\n", scroll_x, scroll_y); -#endif - -#if 0 - /* do not use PLAYING mask for fading out from main screen */ - game_status = GAME_MODE_MAIN; -#endif - -#if 0 - - StopAnimation(); - - if (!game.restart_level) - CloseDoor(DOOR_CLOSE_1); - -#if 1 - if (level_editor_test_game) - FadeSkipNextFadeIn(); - else - FadeSetEnterScreen(); -#else - if (level_editor_test_game) - fading = fading_none; - else - fading = menu.destination; -#endif - -#if 1 - FadeOut(REDRAW_FIELD); -#else - if (do_fading) - FadeOut(REDRAW_FIELD); -#endif - -#endif - -#if 0 - game_status = GAME_MODE_PLAYING; -#endif - /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { InitGameEngine_EM(); - -#if 0 - /* blit playfield from scroll buffer to normal back buffer for fading in */ - BlitScreenToBitmap_EM(backbuffer); -#endif } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { InitGameEngine_SP(); - -#if 0 - /* blit playfield from scroll buffer to normal back buffer for fading in */ - BlitScreenToBitmap_SP(backbuffer); -#endif } else { @@ -4529,88 +3934,56 @@ void InitGame() /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) CloseAllOpenTimegates(); - -#if 0 - /* blit playfield from scroll buffer to normal back buffer for fading in */ -#if NEW_TILESIZE - BlitScreenToBitmap(backbuffer); -#else - if (setup.soft_scrolling) - BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); -#endif -#endif - -#if 0 - redraw_mask |= REDRAW_FROM_BACKBUFFER; -#endif } -#if 1 + /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap(backbuffer); - - redraw_mask |= REDRAW_FROM_BACKBUFFER; -#endif /* !!! FIX THIS (END) !!! */ -#if 1 - FadeIn(REDRAW_FIELD); -#else - if (do_fading) - FadeIn(REDRAW_FIELD); + DrawMaskedBorder(fade_mask); + FadeIn(fade_mask); + +#if 1 + // full screen redraw is required at this point in the following cases: + // - special editor door undrawn when game was started from level editor + // - drawing area (playfield) was changed and has to be removed completely + redraw_mask = REDRAW_ALL; BackToFront(); #endif if (!game.restart_level) { /* copy default game door content to main double buffer */ -#if 1 -#if 1 + /* !!! CHECK AGAIN !!! */ SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); -#else - struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL]; - - /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */ - ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE); - BlitBitmap(gfx->bitmap, drawto, gfx->src_x, gfx->src_y, - MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), DX, DY); -#endif -#else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); -#endif } SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); -#if 1 UpdateAndDisplayGameControlValues(); -#else - UpdateGameDoorValues(); - DrawGameDoorValues(); -#endif if (!game.restart_level) { UnmapGameButtons(); UnmapTapeButtons(); + + FreeGameButtons(); + CreateGameButtons(); + game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; + MapGameButtons(); MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ -#if 1 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); -#else - BlitBitmap(drawto, bitmap_db_door, - DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); -#endif OpenDoor(DOOR_OPEN_ALL); @@ -4645,34 +4018,41 @@ void InitGame() #endif } -#if 1 UnmapAllGadgets(); MapGameButtons(); MapTapeButtons(); -#endif if (!game.restart_level && !tape.playing) { LevelStats_incPlayed(level_nr); SaveLevelSetup_SeriesInfo(); - -#if 0 - printf("::: PLAYING LEVEL (%d)\n", LevelStats_getPlayed(level_nr)); -#endif } game.restart_level = FALSE; + + SaveEngineSnapshotToListInitial(); } -void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y) +void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y, + int actual_player_x, int actual_player_y) { /* this is used for non-R'n'D game engines to update certain engine values */ + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + { + actual_player_x = correctLevelPosX_EM(actual_player_x); + actual_player_y = correctLevelPosY_EM(actual_player_y); + } + /* needed to determine if sounds are played within the visible screen area */ scroll_x = actual_scroll_x; scroll_y = actual_scroll_y; + + /* needed to get player position for "follow finger" playing input method */ + local_player->jx = actual_player_x; + local_player->jy = actual_player_y; } void InitMovDir(int x, int y) @@ -4912,18 +4292,12 @@ void GameWon() LevelStats_incSolved(level_nr); SaveLevelSetup_SeriesInfo(); - -#if 0 - printf("::: LEVEL SOLVED (%d)\n", LevelStats_getSolved(level_nr)); -#endif } if (tape.auto_play) /* tape might already be stopped here */ tape.auto_play_level_solved = TRUE; -#if 1 TapeStop(); -#endif game_over_delay_1 = game_over_delay_value_1; game_over_delay_2 = game_over_delay_value_2; @@ -4949,7 +4323,6 @@ void GameWon() time = time_final; score = score_final; -#if 1 local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; @@ -4957,10 +4330,6 @@ void GameWon() game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); -#else - DrawGameValue_Time(time); - DrawGameValue_Score(score); -#endif } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) @@ -4977,24 +4346,14 @@ void GameWon() { int element = Feld[ExitX][ExitY]; -#if 0 - if (element == EL_EM_EXIT_OPEN || - element == EL_EM_STEEL_EXIT_OPEN) - { - Bang(ExitX, ExitY); - } - else -#endif - { - Feld[ExitX][ExitY] = - (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : - element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : - element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: - element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING: - EL_EM_STEEL_EXIT_CLOSING); - - PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); - } + Feld[ExitX][ExitY] = + (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : + element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : + element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: + element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING: + EL_EM_STEEL_EXIT_CLOSING); + + PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); } /* player disappears */ @@ -5034,7 +4393,6 @@ void GameWon() time += time_count_steps * time_count_dir; score += time_count_steps * level.score[SC_TIME_BONUS]; -#if 1 local_player->LevelSolved_CountingTime = time; local_player->LevelSolved_CountingScore = score; @@ -5042,10 +4400,6 @@ void GameWon() game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); -#else - DrawGameValue_Time(time); - DrawGameValue_Score(score); -#endif if (time == time_final) StopSound(SND_GAME_LEVELTIME_BONUS); @@ -5066,9 +4420,7 @@ void GameWon() return; } -#if 1 GameEnd(); -#endif } void GameEnd() @@ -5078,43 +4430,30 @@ void GameEnd() local_player->LevelSolved_GameEnd = TRUE; - CloseDoor(DOOR_CLOSE_1); + if (!global.use_envelope_request) + CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) { -#if 0 - TapeStop(); -#endif - -#if 1 SaveTapeChecked(tape.level_nr); /* ask to save tape */ -#else - SaveTape(tape.level_nr); /* ask to save tape */ -#endif } + CloseDoor(DOOR_CLOSE_ALL); + if (level_editor_test_game) { - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); -#if 1 - DrawAndFadeInMainMenu(REDRAW_FIELD); -#else DrawMainMenu(); -#endif return; } if (!local_player->LevelSolved_SaveScore) { -#if 1 - FadeOut(REDRAW_FIELD); -#endif - - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawAndFadeInMainMenu(REDRAW_FIELD); + DrawMainMenu(); return; } @@ -5126,12 +4465,13 @@ void GameEnd() SaveLevelSetup_SeriesInfo(); } - if (level_nr < leveldir_current->last_level) + if (setup.increment_levels && + level_nr < leveldir_current->last_level) raise_level = TRUE; /* advance to next level */ if ((hi_pos = NewHiScore()) >= 0) { - game_status = GAME_MODE_SCORES; + SetGameStatus(GAME_MODE_SCORES); DrawHallOfFame(hi_pos); @@ -5143,11 +4483,7 @@ void GameEnd() } else { -#if 1 - FadeOut(REDRAW_FIELD); -#endif - - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); if (raise_level) { @@ -5155,7 +4491,7 @@ void GameEnd() TapeErase(); } - DrawAndFadeInMainMenu(REDRAW_FIELD); + DrawMainMenu(); } } @@ -5163,6 +4499,7 @@ int NewHiScore() { int k, l; int position = -1; + boolean one_score_entry_per_name = !program.many_scores_per_name; LoadScore(level_nr); @@ -5180,13 +4517,15 @@ int NewHiScore() { int m = MAX_SCORE_ENTRIES - 1; -#ifdef ONE_PER_NAME - for (l = k; l < MAX_SCORE_ENTRIES; l++) - if (strEqual(setup.player_name, highscore[l].Name)) - m = l; - if (m == k) /* player's new highscore overwrites his old one */ - goto put_into_list; -#endif + if (one_score_entry_per_name) + { + for (l = k; l < MAX_SCORE_ENTRIES; l++) + if (strEqual(setup.player_name, highscore[l].Name)) + m = l; + + if (m == k) /* player's new highscore overwrites his old one */ + goto put_into_list; + } for (l = m; l > k; l--) { @@ -5195,22 +4534,19 @@ int NewHiScore() } } -#ifdef ONE_PER_NAME put_into_list: -#endif + strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN); highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0'; highscore[k].Score = local_player->score_final; position = k; + break; } - -#ifdef ONE_PER_NAME - else if (!strncmp(setup.player_name, highscore[k].Name, + else if (one_score_entry_per_name && + !strncmp(setup.player_name, highscore[k].Name, MAX_PLAYER_NAME_LEN)) break; /* player already there with a higher score */ -#endif - } if (position >= 0) @@ -5250,11 +4586,6 @@ void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) { if (player->GfxAction != action || player->GfxDir != dir) { -#if 0 - printf("Player frame reset! (%d => %d, %d => %d)\n", - player->GfxAction, action, player->GfxDir, dir); -#endif - player->GfxAction = action; player->GfxDir = dir; player->Frame = 0; @@ -5262,12 +4593,10 @@ void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir) } } -#if USE_GFX_RESET_GFX_ANIMATION -static void ResetGfxFrame(int x, int y, boolean redraw) +static void ResetGfxFrame(int x, int y) { int element = Feld[x][y]; int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); - int last_gfx_frame = GfxFrame[x][y]; if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; @@ -5277,11 +4606,7 @@ static void ResetGfxFrame(int x, int y, boolean redraw) GfxFrame[x][y] = element_info[element].collect_score; else if (ANIM_MODE(graphic) == ANIM_CE_DELAY) GfxFrame[x][y] = ChangeDelay[x][y]; - - if (redraw && GfxFrame[x][y] != last_gfx_frame) - DrawLevelGraphicAnimation(x, y, graphic); } -#endif static void ResetGfxAnimation(int x, int y) { @@ -5289,9 +4614,7 @@ static void ResetGfxAnimation(int x, int y) GfxDir[x][y] = MovDir[x][y]; GfxFrame[x][y] = 0; -#if USE_GFX_RESET_GFX_ANIMATION - ResetGfxFrame(x, y, FALSE); -#endif + ResetGfxFrame(x, y); } static void ResetRandomAnimationValue(int x, int y) @@ -5307,51 +4630,24 @@ void InitMovingField(int x, int y, int direction) int newx = x + dx; int newy = y + dy; boolean is_moving_before, is_moving_after; -#if 0 - boolean continues_moving = (WasJustMoving[x][y] && direction == MovDir[x][y]); -#endif /* check if element was/is moving or being moved before/after mode change */ -#if 1 -#if 1 is_moving_before = (WasJustMoving[x][y] != 0); -#else - /* (!!! this does not work -- WasJustMoving is NOT a boolean value !!!) */ - is_moving_before = WasJustMoving[x][y]; -#endif -#else - is_moving_before = (getElementMoveStepsizeExt(x, y, MovDir[x][y]) != 0); -#endif is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0); /* reset animation only for moving elements which change direction of moving or which just started or stopped moving (else CEs with property "can move" / "not moving" are reset each frame) */ -#if USE_GFX_RESET_ONLY_WHEN_MOVING -#if 1 if (is_moving_before != is_moving_after || direction != MovDir[x][y]) ResetGfxAnimation(x, y); -#else - if ((is_moving_before || is_moving_after) && !continues_moving) - ResetGfxAnimation(x, y); -#endif -#else - if (!continues_moving) - ResetGfxAnimation(x, y); -#endif MovDir[x][y] = direction; GfxDir[x][y] = direction; -#if USE_GFX_RESET_ONLY_WHEN_MOVING GfxAction[x][y] = (!is_moving_after ? ACTION_WAITING : direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); -#else - GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ? - ACTION_FALLING : ACTION_MOVING); -#endif /* this is needed for CEs with property "can move" / "not moving" */ @@ -5362,9 +4658,7 @@ void InitMovingField(int x, int y, int direction) MovDir[newx][newy] = MovDir[x][y]; -#if USE_NEW_CUSTOM_VALUE CustomValue[newx][newy] = CustomValue[x][y]; -#endif GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; @@ -5447,26 +4741,16 @@ static void RemoveField(int x, int y) MovDir[x][y] = 0; MovDelay[x][y] = 0; -#if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; -#endif AmoebaNr[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; Pushed[x][y] = FALSE; -#if 0 - ExplodeField[x][y] = EX_TYPE_NONE; -#endif - GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; -#if 0 - /* !!! this would prevent the removed tile from being redrawn !!! */ - GfxRedraw[x][y] = GFX_REDRAW_NONE; -#endif } void RemoveMovingField(int x, int y) @@ -5623,204 +4907,92 @@ static void setScreenCenteredToAllPlayers(int *sx, int *sy) void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, boolean center_screen, boolean quick_relocation) { + unsigned int frame_delay_value_old = GetVideoFrameDelay(); boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay); int wait_delay_value = (no_delay ? 0 : frame_delay_value); + int new_scroll_x, new_scroll_y; - if (quick_relocation) + if (level.lazy_relocation && IN_VIS_FIELD(SCREENX(x), SCREENY(y))) { - if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen) - { - if (!level.shifted_relocation || center_screen) - { - /* quick relocation (without scrolling), with centering of screen */ - - scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left : - x > SBX_Right + MIDPOSX ? SBX_Right : - x - MIDPOSX); - - scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper : - y > SBY_Lower + MIDPOSY ? SBY_Lower : - y - MIDPOSY); - } - else - { - /* quick relocation (without scrolling), but do not center screen */ - - int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : - old_x > SBX_Right + MIDPOSX ? SBX_Right : - old_x - MIDPOSX); - - int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : - old_y > SBY_Lower + MIDPOSY ? SBY_Lower : - old_y - MIDPOSY); - - int offset_x = x + (scroll_x - center_scroll_x); - int offset_y = y + (scroll_y - center_scroll_y); - - scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : - offset_x > SBX_Right + MIDPOSX ? SBX_Right : - offset_x - MIDPOSX); - - scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : - offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : - offset_y - MIDPOSY); - } - } - else - { -#if 1 - if (!level.shifted_relocation || center_screen) - { - /* quick relocation (without scrolling), with centering of screen */ - - scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left : - x > SBX_Right + MIDPOSX ? SBX_Right : - x - MIDPOSX); - - scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper : - y > SBY_Lower + MIDPOSY ? SBY_Lower : - y - MIDPOSY); - } - else - { - /* quick relocation (without scrolling), but do not center screen */ - - int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : - old_x > SBX_Right + MIDPOSX ? SBX_Right : - old_x - MIDPOSX); - - int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : - old_y > SBY_Lower + MIDPOSY ? SBY_Lower : - old_y - MIDPOSY); + /* case 1: quick relocation inside visible screen (without scrolling) */ - int offset_x = x + (scroll_x - center_scroll_x); - int offset_y = y + (scroll_y - center_scroll_y); + RedrawPlayfield(); - scroll_x = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : - offset_x > SBX_Right + MIDPOSX ? SBX_Right : - offset_x - MIDPOSX); - - scroll_y = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : - offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : - offset_y - MIDPOSY); - } -#else - /* quick relocation (without scrolling), inside visible screen area */ - - int offset = game.scroll_delay_value; - - if ((move_dir == MV_LEFT && scroll_x > x - MIDPOSX + offset) || - (move_dir == MV_RIGHT && scroll_x < x - MIDPOSX - offset)) - scroll_x = x - MIDPOSX + (scroll_x < x - MIDPOSX ? -offset : +offset); - - if ((move_dir == MV_UP && scroll_y > y - MIDPOSY + offset) || - (move_dir == MV_DOWN && scroll_y < y - MIDPOSY - offset)) - scroll_y = y - MIDPOSY + (scroll_y < y - MIDPOSY ? -offset : +offset); - - /* don't scroll over playfield boundaries */ - if (scroll_x < SBX_Left || scroll_x > SBX_Right) - scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); + return; + } - /* don't scroll over playfield boundaries */ - if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) - scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); -#endif - } + if (!level.shifted_relocation || center_screen) + { + /* relocation _with_ centering of screen */ - RedrawPlayfield(TRUE, 0,0,0,0); + new_scroll_x = SCROLL_POSITION_X(x); + new_scroll_y = SCROLL_POSITION_Y(y); } else { -#if 1 - int scroll_xx, scroll_yy; - - if (!level.shifted_relocation || center_screen) - { - /* visible relocation (with scrolling), with centering of screen */ - - scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : - x > SBX_Right + MIDPOSX ? SBX_Right : - x - MIDPOSX); + /* relocation _without_ centering of screen */ - scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : - y > SBY_Lower + MIDPOSY ? SBY_Lower : - y - MIDPOSY); - } - else - { - /* visible relocation (with scrolling), but do not center screen */ - - int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : - old_x > SBX_Right + MIDPOSX ? SBX_Right : - old_x - MIDPOSX); + int center_scroll_x = SCROLL_POSITION_X(old_x); + int center_scroll_y = SCROLL_POSITION_Y(old_y); + int offset_x = x + (scroll_x - center_scroll_x); + int offset_y = y + (scroll_y - center_scroll_y); - int center_scroll_y = (old_y < SBY_Upper + MIDPOSY ? SBY_Upper : - old_y > SBY_Lower + MIDPOSY ? SBY_Lower : - old_y - MIDPOSY); + /* for new screen position, apply previous offset to center position */ + new_scroll_x = SCROLL_POSITION_X(offset_x); + new_scroll_y = SCROLL_POSITION_Y(offset_y); + } - int offset_x = x + (scroll_x - center_scroll_x); - int offset_y = y + (scroll_y - center_scroll_y); + if (quick_relocation) + { + /* case 2: quick relocation (redraw without visible scrolling) */ - scroll_xx = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : - offset_x > SBX_Right + MIDPOSX ? SBX_Right : - offset_x - MIDPOSX); + scroll_x = new_scroll_x; + scroll_y = new_scroll_y; - scroll_yy = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : - offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : - offset_y - MIDPOSY); - } + RedrawPlayfield(); -#else + return; + } - /* visible relocation (with scrolling), with centering of screen */ + /* case 3: visible relocation (with scrolling to new position) */ - int scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : - x > SBX_Right + MIDPOSX ? SBX_Right : - x - MIDPOSX); + ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ - int scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : - y > SBY_Lower + MIDPOSY ? SBY_Lower : - y - MIDPOSY); -#endif + SetVideoFrameDelay(wait_delay_value); - ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ + while (scroll_x != new_scroll_x || scroll_y != new_scroll_y) + { + int dx = 0, dy = 0; + int fx = FX, fy = FY; - while (scroll_x != scroll_xx || scroll_y != scroll_yy) - { - int dx = 0, dy = 0; - int fx = FX, fy = FY; + dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0); + dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0); - dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); - dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); + if (dx == 0 && dy == 0) /* no scrolling needed at all */ + break; - if (dx == 0 && dy == 0) /* no scrolling needed at all */ - break; + scroll_x -= dx; + scroll_y -= dy; - scroll_x -= dx; - scroll_y -= dy; + fx += dx * TILEX / 2; + fy += dy * TILEY / 2; - fx += dx * TILEX / 2; - fy += dy * TILEY / 2; + ScrollLevel(dx, dy); + DrawAllPlayers(); - ScrollLevel(dx, dy); - DrawAllPlayers(); + /* scroll in two steps of half tile size to make things smoother */ + BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); - /* scroll in two steps of half tile size to make things smoother */ - BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); - FlushDisplay(); - Delay(wait_delay_value); + /* scroll second step to align at full tile size */ + BlitScreenToBitmap(window); + } - /* scroll second step to align at full tile size */ - BackToFront(); - Delay(wait_delay_value); - } + DrawAllPlayers(); + BackToFront(); - DrawAllPlayers(); - BackToFront(); - Delay(wait_delay_value); - } + SetVideoFrameDelay(frame_delay_value_old); } void RelocatePlayer(int jx, int jy, int el_player_raw) @@ -5870,8 +5042,7 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) DrawPlayer(player); - BackToFront(); - Delay(wait_delay_value); + BackToFront_WithFrameDelay(wait_delay_value); } DrawPlayer(player); /* needed here only to cleanup last field */ @@ -5899,12 +5070,6 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */ { Feld[jx][jy] = element; /* restore previously existing element */ -#if 0 - /* !!! do not initialize already initialized element a second time !!! */ - /* (this causes at least problems with "element creation" CE trigger for - already existing elements, and existing Sokoban fields counted twice) */ - InitField(jx, jy, FALSE); -#endif } /* only visually relocate centered player */ @@ -5921,7 +5086,6 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) CheckTriggeredElementChangeByPlayer(jx, jy, element, CE_PLAYER_ENTERS_X, player->index_bit, enter_side); -#if 1 if (player->is_switching) { /* ensure that relocation while still switching an element does not cause @@ -5934,7 +5098,6 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) player->switch_x += jx - old_jx; player->switch_y += jy - old_jy; } -#endif } void Explode(int ex, int ey, int phase, int mode) @@ -5957,23 +5120,6 @@ void Explode(int ex, int ey, int phase, int mode) int center_element = Feld[ex][ey]; int artwork_element, explosion_element; /* set these values later */ -#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 >= VERSION_IDENT(2,2,0,7) && - center_element == EL_EMPTY && - (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)) - return; -#endif - -#if 0 - /* !!! at this place, the center element may be EL_BLOCKED !!! */ - if (mode == EX_TYPE_NORMAL || - mode == EX_TYPE_CENTER || - mode == EX_TYPE_CROSS) - PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); -#endif - /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) Back[ex][ey] = 0; @@ -6003,12 +5149,10 @@ void Explode(int ex, int ey, int phase, int mode) } } -#if 1 if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); -#endif last_phase = element_info[explosion_element].explosion_delay + 1; @@ -6145,31 +5289,9 @@ void Explode(int ex, int ey, int phase, int mode) ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); -#ifdef DEBUG - - /* activate this even in non-DEBUG version until cause for crash in - getGraphicAnimationFrame() (see below) is found and eliminated */ - -#endif -#if 1 - -#if 1 /* this can happen if the player leaves an explosion just in time */ if (GfxElement[x][y] == EL_UNDEFINED) GfxElement[x][y] = EL_EMPTY; -#else - if (GfxElement[x][y] == EL_UNDEFINED) - { - printf("\n\n"); - printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y); - printf("Explode(): This should never happen!\n"); - printf("\n\n"); - - GfxElement[x][y] = EL_EMPTY; - } -#endif - -#endif border_element = Store2[x][y]; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) @@ -6241,9 +5363,7 @@ void Explode(int ex, int ey, int phase, int mode) ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; -#if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; -#endif InitField_WithBug2(x, y, FALSE); @@ -6343,12 +5463,7 @@ void Bang(int x, int y) { struct PlayerInfo *player = PLAYERINFO(x, y); -#if USE_FIX_CE_ACTION_WITH_PLAYER element = Feld[x][y] = player->initial_element; -#else - element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY : - player->element_nr); -#endif if (level.use_explosion_element[player->index_nr]) { @@ -6386,10 +5501,6 @@ void Bang(int x, int y) break; case EL_DC_LANDMINE: -#if 0 - case EL_EM_EXIT_OPEN: - case EL_EM_STEEL_EXIT_OPEN: -#endif explosion_type = EX_TYPE_CENTER; break; @@ -6613,20 +5724,6 @@ static void ToggleSwitchgateSwitch(int x, int y) { int element = Feld[xx][yy]; -#if !USE_BOTH_SWITCHGATE_SWITCHES - if (element == EL_SWITCHGATE_SWITCH_UP || - element == EL_SWITCHGATE_SWITCH_DOWN) - { - Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; - TEST_DrawLevelField(xx, yy); - } - else if (element == EL_DC_SWITCHGATE_SWITCH_UP || - element == EL_DC_SWITCHGATE_SWITCH_DOWN) - { - Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP + game.switchgate_pos; - TEST_DrawLevelField(xx, yy); - } -#else if (element == EL_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN; @@ -6647,7 +5744,6 @@ static void ToggleSwitchgateSwitch(int x, int y) Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP; TEST_DrawLevelField(xx, yy); } -#endif else if (element == EL_SWITCHGATE_OPEN || element == EL_SWITCHGATE_OPENING) { @@ -6880,12 +5976,8 @@ static void ActivateTimegateSwitch(int x, int y) } -#if 1 Feld[x][y] = (Feld[x][y] == EL_TIMEGATE_SWITCH ? EL_TIMEGATE_SWITCH_ACTIVE : EL_DC_TIMEGATE_SWITCH_ACTIVE); -#else - Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE; -#endif } void Impact(int x, int y) @@ -7111,10 +6203,6 @@ void Impact(int x, int y) } else { -#if 0 - TestIfElementSmashesCustomElement(x, y, MV_DOWN); -#endif - CheckElementChange(x, y + 1, smashed, element, CE_SMASHED); CheckElementChangeBySide(x, y + 1, smashed, element, @@ -7416,7 +6504,6 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_SPRING) { -#if USE_NEW_SPRING_BUMPER if (MovDir[x][y] & MV_HORIZONTAL) { if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) && @@ -7432,12 +6519,6 @@ inline static void TurnRoundExt(int x, int y) SPRING_CAN_ENTER_FIELD(element, x, y + 1)) MovDir[x][y] = MV_NONE; } -#else - if (MovDir[x][y] & MV_HORIZONTAL && - (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || - SPRING_CAN_ENTER_FIELD(element, x, y + 1))) - MovDir[x][y] = MV_NONE; -#endif MovDelay[x][y] = 0; } @@ -7979,7 +7060,7 @@ static void TurnRound(int x, int y) if (MovDelay[x][y]) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction); - ResetGfxFrame(x, y, FALSE); + ResetGfxFrame(x, y); } static boolean JustBeingPushed(int x, int y) @@ -8297,13 +7378,8 @@ void StartMoving(int x, int y) Store[x][y] = EL_ACID; } else if ( -#if USE_FIX_IMPACT_COLLISION (game.engine_version >= VERSION_IDENT(3,1,0,0) && CheckImpact[x][y] && !IS_FREE(x, y + 1)) || -#else - (game.engine_version >= VERSION_IDENT(3,1,0,0) && - CheckCollision[x][y] && !IS_FREE(x, y + 1)) || -#endif (game.engine_version >= VERSION_IDENT(3,0,7,0) && CAN_FALL(element) && WasJustFalling[x][y] && (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) || @@ -8363,7 +7439,6 @@ void StartMoving(int x, int y) boolean can_fall_both = (can_fall_left && can_fall_right); int slippery_type = element_info[Feld[x][y + 1]].slippery_type; -#if USE_NEW_ALL_SLIPPERY if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM) { if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) @@ -8378,37 +7453,7 @@ void StartMoving(int x, int y) can_fall_any = (can_fall_left || can_fall_right); can_fall_both = FALSE; } -#else - if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) - { - 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); - } -#endif - -#if USE_NEW_ALL_SLIPPERY -#else -#if USE_NEW_SP_SLIPPERY - /* !!! better use the same properties as for custom elements here !!! */ - else if (game.engine_version >= VERSION_IDENT(3,1,1,0) && - can_fall_both && IS_SP_ELEMENT(Feld[x][y + 1])) - { - can_fall_right = FALSE; /* slip down on left side */ - can_fall_both = FALSE; - } -#endif -#endif -#if USE_NEW_ALL_SLIPPERY if (can_fall_both) { if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) @@ -8418,18 +7463,6 @@ void StartMoving(int x, int y) can_fall_both = FALSE; } -#else - if (can_fall_both) - { - if (game.emulation == EMU_BOULDERDASH || - element == EL_BD_ROCK || element == EL_BD_DIAMOND) - can_fall_right = FALSE; /* slip down on left side */ - else - can_fall_left = !(can_fall_right = RND(2)); - - can_fall_both = FALSE; - } -#endif if (can_fall_any) { @@ -8438,11 +7471,7 @@ void StartMoving(int x, int y) started_moving = TRUE; } } -#if 0 - else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element)) -#else else if (IS_BELT_ACTIVE(Feld[x][y + 1])) -#endif { boolean left_is_free = (x > 0 && IS_FREE(x - 1, y)); boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y)); @@ -8470,26 +7499,11 @@ void StartMoving(int x, int y) } /* not "else if" because of elements that can fall and move (EL_SPRING) */ -#if 0 - if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NONE) -#else if (CAN_MOVE(element) && !started_moving) -#endif { int move_pattern = element_info[element].move_pattern; int newx, newy; -#if 0 -#if DEBUG - if (MovDir[x][y] == MV_NONE) - { - printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n", - x, y, element, element_info[element].token_name); - printf("StartMoving(): This should never happen!\n"); - } -#endif -#endif - Moving2Blocked(x, y, &newx, &newy); if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) @@ -8582,20 +7596,10 @@ void StartMoving(int x, int y) { int flamed = MovingOrBlocked2Element(xx, yy); - /* !!! */ -#if 0 - if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed)) - Bang(xx, yy); - else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy)) - RemoveMovingField(xx, yy); - else - RemoveField(xx, yy); -#else if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed)) Bang(xx, yy); else RemoveMovingField(xx, yy); -#endif ChangeDelay[xx][yy] = 0; @@ -8791,78 +7795,14 @@ void StartMoving(int x, int y) } else if (!IS_FREE(newx, newy)) { -#if 0 - if (IS_PLAYER(x, y)) - DrawPlayerField(x, y); - else - TEST_DrawLevelField(x, y); -#endif - return; } } else if (IS_CUSTOM_ELEMENT(element) && CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)) { -#if 1 if (!DigFieldByCE(newx, newy, element)) return; -#else - int new_element = Feld[newx][newy]; - - if (!IS_FREE(newx, newy)) - { - int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING : - IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING : - ACTION_BREAKING); - - /* no element can dig solid indestructible elements */ - if (IS_INDESTRUCTIBLE(new_element) && - !IS_DIGGABLE(new_element) && - !IS_COLLECTIBLE(new_element)) - return; - - if (AmoebaNr[newx][newy] && - (new_element == EL_AMOEBA_FULL || - new_element == EL_BD_AMOEBA || - new_element == EL_AMOEBA_GROWING)) - { - AmoebaCnt[AmoebaNr[newx][newy]]--; - AmoebaCnt2[AmoebaNr[newx][newy]]--; - } - - if (IS_MOVING(newx, newy)) - RemoveMovingField(newx, newy); - else - { - RemoveField(newx, newy); - TEST_DrawLevelField(newx, newy); - } - - /* if digged element was about to explode, prevent the explosion */ - ExplodeField[newx][newy] = EX_TYPE_NONE; - - PlayLevelSoundAction(x, y, action); - } - - Store[newx][newy] = EL_EMPTY; - -#if 1 - /* this makes it possible to leave the removed element again */ - if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) - Store[newx][newy] = new_element; -#else - if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) - { - int move_leave_element = element_info[element].move_leave_element; - - /* this makes it possible to leave the removed element again */ - Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? - new_element : move_leave_element); - } -#endif - -#endif if (move_pattern & MV_MAZE_RUNNER_STYLE) { @@ -8910,25 +7850,11 @@ void StartMoving(int x, int y) MovDelay[x][y] = 50; - /* !!! */ -#if 0 - RemoveField(newx, newy); -#endif Feld[newx][newy] = EL_FLAMES; if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY) - { -#if 0 - RemoveField(newx1, newy1); -#endif Feld[newx1][newy1] = EL_FLAMES; - } if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY) - { -#if 0 - RemoveField(newx2, newy2); -#endif Feld[newx2][newy2] = EL_FLAMES; - } return; } @@ -8958,18 +7884,10 @@ void StartMoving(int x, int y) AmoebaCnt[AmoebaNr[newx][newy]]--; } -#if 0 - /* !!! test !!! */ - if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy)) - { - RemoveMovingField(newx, newy); - } -#else if (IS_MOVING(newx, newy)) { RemoveMovingField(newx, newy); } -#endif else { Feld[newx][newy] = EL_EMPTY; @@ -9022,21 +7940,6 @@ void StartMoving(int x, int y) TurnRound(x, y); -#if 0 - /* !!! NEW "CE_BLOCKED" STUFF !!! -- DOES NOT WORK YET... !!! */ - if (move_pattern & MV_ANY_DIRECTION && - move_pattern == MovDir[x][y]) - { - int blocking_element = - (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement); - - CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED, - MovDir[x][y]); - - element = Feld[x][y]; /* element might have changed */ - } -#endif - if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ DrawLevelElementAnimation(x, y, element); @@ -9076,17 +7979,6 @@ void ContinueMoving(int x, int y) if (ABS(MovPos[x][y]) < TILEX) { -#if 0 - int ee = Feld[x][y]; - int gg = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); - int ff = getGraphicAnimationFrame(gg, GfxFrame[x][y]); - - printf("::: %d.%d: moving %d ... [%d, %d, %d] [%d, %d, %d]\n", - x, y, ABS(MovPos[x][y]), - ee, gg, ff, - GfxAction[x][y], GfxDir[x][y], GfxFrame[x][y]); -#endif - TEST_DrawLevelField(x, y); return; /* element is still moving */ @@ -9142,9 +8034,7 @@ void ContinueMoving(int x, int y) Feld[x][y] = EL_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; -#if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); -#endif } else if (element == EL_BD_MAGIC_WALL_FILLING) { @@ -9160,9 +8050,7 @@ void ContinueMoving(int x, int y) Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; -#if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); -#endif } else if (element == EL_DC_MAGIC_WALL_FILLING) { @@ -9178,9 +8066,7 @@ void ContinueMoving(int x, int y) Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; -#if USE_NEW_CUSTOM_VALUE InitField(newx, newy, FALSE); -#endif } else if (element == EL_AMOEBA_DROPPING) { @@ -9214,18 +8100,14 @@ void ContinueMoving(int x, int y) ChangeEvent[newx][newy] = ChangeEvent[x][y]; } -#if USE_NEW_CUSTOM_VALUE CustomValue[newx][newy] = CustomValue[x][y]; -#endif ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; -#if USE_NEW_CUSTOM_VALUE CustomValue[x][y] = 0; -#endif /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; @@ -9236,34 +8118,15 @@ void ContinueMoving(int x, int y) Pushed[x][y] = Pushed[newx][newy] = FALSE; /* some elements can leave other elements behind after moving */ -#if 1 if (ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) -#else - if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY && - (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && - (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) -#endif { int move_leave_element = ei->move_leave_element; -#if 1 -#if 1 /* this makes it possible to leave the removed element again */ if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored); -#else - /* this makes it possible to leave the removed element again */ - if (ei->move_leave_element == EL_TRIGGER_ELEMENT) - move_leave_element = stored; -#endif -#else - /* this makes it possible to leave the removed element again */ - if (ei->move_leave_type == LEAVE_TYPE_LIMITED && - ei->move_leave_element == EL_TRIGGER_ELEMENT) - move_leave_element = stored; -#endif Feld[x][y] = move_leave_element; @@ -9318,10 +8181,8 @@ void ContinueMoving(int x, int y) if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again) CheckCollision[newx][newy] = CHECK_DELAY_COLLISION; -#if USE_FIX_IMPACT_COLLISION if (CAN_FALL(element) && direction == MV_DOWN && check_collision_again) CheckImpact[newx][newy] = CHECK_DELAY_IMPACT; -#endif } if (DONT_TOUCH(element)) /* object may be nasty to player or others */ @@ -9364,29 +8225,6 @@ void ContinueMoving(int x, int y) CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction); TestIfElementTouchesCustomElement(x, y); /* empty or new element */ - -#if 0 - if (ChangePage[newx][newy] != -1) /* delayed change */ - { - int page = ChangePage[newx][newy]; - struct ElementChangeInfo *change = &ei->change_page[page]; - - ChangePage[newx][newy] = -1; - - if (change->can_change) - { - if (ChangeElement(newx, newy, element, page)) - { - if (change->post_change_function) - change->post_change_function(newx, newy); - } - } - - if (change->has_action) - ExecuteCustomElementAction(newx, newy, element, page); - } -#endif - TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -9907,11 +8745,7 @@ static void RunTimegateWheel(int x, int y) static void InitMagicBallDelay(int x, int y) { -#if 1 ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1; -#else - ChangeDelay[x][y] = level.ball_time * FRAMES_PER_SECOND + 1; -#endif } static void ActivateMagicBall(int bx, int by) @@ -10524,11 +9358,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) EL_EMPTY); int action_arg_element = GetElementFromGroupElement(action_arg_element_raw); -#if 0 - if (action_arg_element_raw == EL_GROUP_START) - printf("::: %d,%d: %d ('%s')\n", x, y, element, EL_NAME(element)); -#endif - int action_arg_direction = (action_arg >= CA_ARG_DIRECTION_LEFT && action_arg <= CA_ARG_DIRECTION_DOWN ? action_arg - CA_ARG_DIRECTION : @@ -10556,11 +9385,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_type == CA_SET_LEVEL_GEMS ? level.gems_needed : action_type == CA_SET_LEVEL_TIME ? level.time : action_type == CA_SET_LEVEL_SCORE ? 0 : -#if USE_NEW_CUSTOM_VALUE action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) : -#else - action_type == CA_SET_CE_VALUE ? ei->custom_value_initial : -#endif action_type == CA_SET_CE_SCORE ? 0 : 0); @@ -10572,11 +9397,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min : action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max : action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset : -#if USE_NEW_CUSTOM_VALUE action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] : -#else - action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial : -#endif action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) : action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : @@ -10606,17 +9427,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_mode, action_arg_number, action_arg_number_min, action_arg_number_max); -#if 1 int trigger_player_bits = (change->actual_trigger_player_bits != CH_PLAYER_NONE ? change->actual_trigger_player_bits : change->trigger_player); -#else - int trigger_player_bits = - (change->actual_trigger_player >= EL_PLAYER_1 && - change->actual_trigger_player <= EL_PLAYER_4 ? - (1 << (change->actual_trigger_player - EL_PLAYER_1)) : - PLAYER_BITS_ANY); -#endif int action_arg_player_bits = (action_arg >= CA_ARG_PLAYER_1 && @@ -10660,13 +9473,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { TimeLeft = action_arg_number_new; -#if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); -#else - DrawGameValue_Time(TimeLeft); -#endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) @@ -10680,13 +9489,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { local_player->score = action_arg_number_new; -#if 1 game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); -#else - DrawGameValue_Score(local_player->score); -#endif break; } @@ -10695,27 +9500,15 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { local_player->gems_still_needed = action_arg_number_new; -#if 1 - game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; + game.snapshot.collected_item = TRUE; - DisplayGameControlValues(); -#else - DrawGameValue_Emeralds(local_player->gems_still_needed); -#endif + game_panel_controls[GAME_PANEL_GEMS].value = + local_player->gems_still_needed; - break; - } + DisplayGameControlValues(); -#if !USE_PLAYER_GRAVITY - case CA_SET_LEVEL_GRAVITY: - { - game.gravity = (action_arg == CA_ARG_GRAVITY_OFF ? FALSE : - action_arg == CA_ARG_GRAVITY_ON ? TRUE : - action_arg == CA_ARG_GRAVITY_TOGGLE ? !game.gravity : - game.gravity); break; } -#endif case CA_SET_LEVEL_WIND: { @@ -10726,27 +9519,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_LEVEL_RANDOM_SEED: { -#if 1 /* ensure that setting a new random seed while playing is predictable */ InitRND(action_arg_number_new ? action_arg_number_new : RND(1000000) + 1); -#else - InitRND(action_arg_number_new); -#endif - -#if 0 - printf("::: %d -> %d\n", action_arg_number_new, RND(10)); -#endif - -#if 0 - { - int i; - - printf("::: "); - for (i = 0; i < 9; i++) - printf("%d, ", RND(2)); - printf("\n"); - } -#endif break; } @@ -10805,10 +9579,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_PLAYER_SPEED: { -#if 0 - printf("::: trigger_player_bits == %d\n", trigger_player_bits); -#endif - for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) @@ -10872,7 +9642,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } -#if USE_PLAYER_GRAVITY case CA_SET_PLAYER_GRAVITY: { for (i = 0; i < MAX_PLAYERS; i++) @@ -10889,7 +9658,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } -#endif case CA_SET_PLAYER_ARTWORK: { @@ -10904,10 +9672,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (level.use_artwork_element[i] ? level.artwork_element[i] : stored_player[i].element_nr); -#if USE_GFX_RESET_PLAYER_ARTWORK if (stored_player[i].artwork_element != artwork_element) stored_player[i].Frame = 0; -#endif stored_player[i].artwork_element = artwork_element; @@ -11028,7 +9794,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_CE_VALUE: { -#if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; CustomValue[x][y] = action_arg_number_new; @@ -11044,14 +9809,12 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); } } -#endif break; } case CA_SET_CE_SCORE: { -#if USE_NEW_CUSTOM_VALUE int last_ce_score = ei->collect_score; ei->collect_score = action_arg_number_new; @@ -11087,7 +9850,6 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) } } } -#endif break; } @@ -11143,32 +9905,13 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) int old_element = Feld[x][y]; int new_element = GetElementFromGroupElement(element); int previous_move_direction = MovDir[x][y]; -#if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; -#endif boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y); boolean new_element_is_player = ELEM_IS_PLAYER(new_element); boolean add_player_onto_element = (new_element_is_player && -#if USE_CODE_THAT_BREAKS_SNAKE_BITE - /* this breaks SnakeBite when a snake is - halfway through a door that closes */ - /* NOW FIXED AT LEVEL INIT IN files.c */ new_element != EL_SOKOBAN_FIELD_PLAYER && -#endif IS_WALKABLE(old_element)); -#if 0 - /* check if element under the player changes from accessible to unaccessible - (needed for special case of dropping element which then changes) */ - if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && - IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) - { - Bang(x, y); - - return; - } -#endif - if (!add_player_onto_element) { if (IS_MOVING(x, y) || IS_BLOCKED(x, y)) @@ -11178,27 +9921,18 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) Feld[x][y] = new_element; -#if !USE_GFX_RESET_GFX_ANIMATION - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); -#endif - if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS) MovDir[x][y] = previous_move_direction; -#if USE_NEW_CUSTOM_VALUE if (element_info[new_element].use_last_ce_value) CustomValue[x][y] = last_ce_value; -#endif InitField_WithBug1(x, y, FALSE); new_element = Feld[x][y]; /* element may have changed */ -#if USE_GFX_RESET_GFX_ANIMATION ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); -#endif TEST_DrawLevelField(x, y); @@ -11206,11 +9940,9 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } -#if 1 /* check if element under the player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ /* (must be checked after creating new element for walkable group elements) */ -#if USE_FIX_KILLED_BY_NON_WALKABLE if (IS_PLAYER(x, y) && !player_explosion_protected && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { @@ -11218,16 +9950,6 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) return; } -#else - if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && - IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) - { - Bang(x, y); - - return; - } -#endif -#endif /* "ChangeCount" not set yet to allow "entered by player" change one time */ if (new_element_is_player) @@ -11250,7 +9972,6 @@ static void CreateElementFromChange(int x, int y, int element) { element = GET_VALID_RUNTIME_ELEMENT(element); -#if USE_STOP_CHANGED_ELEMENTS if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { int old_element = Feld[x][y]; @@ -11261,7 +9982,6 @@ static void CreateElementFromChange(int x, int y, int element) (!CAN_MOVE(old_element) || !CAN_MOVE(element))) Stop[x][y] = TRUE; } -#endif CreateFieldExt(x, y, element, TRUE); } @@ -11437,8 +10157,6 @@ static boolean ChangeElement(int x, int y, int element, int page) return TRUE; } -#if USE_NEW_DELAYED_ACTION - static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); @@ -11461,11 +10179,6 @@ static void HandleElementChange(int x, int y, int page) /* this can happen with classic bombs on walkable, changing elements */ if (!CAN_CHANGE_OR_HAS_ACTION(element)) { -#if 0 - if (!CAN_CHANGE(Back[x][y])) /* prevent permanent repetition */ - ChangeDelay[x][y] = 0; -#endif - return; } @@ -11475,19 +10188,56 @@ static void HandleElementChange(int x, int y, int page) if (change->can_change) { -#if 1 /* !!! not clear why graphic animation should be reset at all here !!! */ /* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */ -#if USE_GFX_RESET_WHEN_NOT_MOVING + /* !!! SOLUTION: do not reset if graphics engine set to 4 or above !!! */ + + /* + GRAPHICAL BUG ADDRESSED BY CHECKING GRAPHICS ENGINE VERSION: + + When using an animation frame delay of 1 (this only happens with + "sp_zonk.moving.left/right" in the classic graphics), the default + (non-moving) animation shows wrong animation frames (while the + moving animation, like "sp_zonk.moving.left/right", is correct, + so this graphical bug never shows up with the classic graphics). + For an animation with 4 frames, this causes wrong frames 0,0,1,2 + be drawn instead of the correct frames 0,1,2,3. This is caused by + "GfxFrame[][]" being reset *twice* (in two successive frames) after + an element change: First when the change delay ("ChangeDelay[][]") + counter has reached zero after decrementing, then a second time in + the next frame (after "GfxFrame[][]" was already incremented) when + "ChangeDelay[][]" is reset to the initial delay value again. + + This causes frame 0 to be drawn twice, while the last frame won't + be drawn anymore, resulting in the wrong frame sequence 0,0,1,2. + + As some animations may already be cleverly designed around this bug + (at least the "Snake Bite" snake tail animation does this), it cannot + simply be fixed here without breaking such existing animations. + Unfortunately, it cannot easily be detected if a graphics set was + designed "before" or "after" the bug was fixed. As a workaround, + a new graphics set option "game.graphics_engine_version" was added + to be able to specify the game's major release version for which the + graphics set was designed, which can then be used to decide if the + bugfix should be used (version 4 and above) or not (version 3 or + below, or if no version was specified at all, as with old sets). + + (The wrong/fixed animation frames can be tested with the test level set + "test_gfxframe" and level "000", which contains a specially prepared + custom element at level position (x/y) == (11/9) which uses the zonk + animation mentioned above. Using "game.graphics_engine_version: 4" + fixes the wrong animation frames, showing the correct frames 0,1,2,3. + This can also be seen from the debug output for this test element.) + */ + /* when a custom element is about to change (for example by change delay), do not reset graphic animation when the custom element is moving */ - if (!IS_MOVING(x, y)) -#endif + if (game.graphics_engine_version < 4 && + !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); } -#endif if (change->pre_change_function) change->pre_change_function(x, y); @@ -11527,14 +10277,12 @@ static void HandleElementChange(int x, int y, int page) return; } -#if 1 /* special case: set new level random seed before changing element */ if (change->has_action && change->action_type == CA_SET_LEVEL_RANDOM_SEED) handle_action_before_change = TRUE; if (change->has_action && handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); -#endif if (change->can_change) { @@ -11550,87 +10298,6 @@ static void HandleElementChange(int x, int y, int page) } } -#else - -static void HandleElementChange(int x, int y, int page) -{ - int element = MovingOrBlocked2Element(x, y); - struct ElementInfo *ei = &element_info[element]; - struct ElementChangeInfo *change = &ei->change_page[page]; - -#ifdef DEBUG - if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y])) - { - printf("\n\n"); - printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", - x, y, element, element_info[element].token_name); - printf("HandleElementChange(): This should never happen!\n"); - printf("\n\n"); - } -#endif - - /* this can happen with classic bombs on walkable, changing elements */ - if (!CAN_CHANGE(element)) - { -#if 0 - if (!CAN_CHANGE(Back[x][y])) /* prevent permanent repetition */ - ChangeDelay[x][y] = 0; -#endif - - return; - } - - if (ChangeDelay[x][y] == 0) /* initialize element change */ - { - ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; - - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); - - if (change->pre_change_function) - change->pre_change_function(x, y); - } - - ChangeDelay[x][y]--; - - if (ChangeDelay[x][y] != 0) /* continue element change */ - { - int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); - - if (IS_ANIMATED(graphic)) - DrawLevelGraphicAnimationIfNeeded(x, y, graphic); - - if (change->change_function) - change->change_function(x, y); - } - else /* finish element change */ - { - if (ChangePage[x][y] != -1) /* remember page from delayed change */ - { - page = ChangePage[x][y]; - ChangePage[x][y] = -1; - - change = &ei->change_page[page]; - } - - if (IS_MOVING(x, y)) /* never change a running system ;-) */ - { - ChangeDelay[x][y] = 1; /* try change after next move step */ - ChangePage[x][y] = page; /* remember page to use for change */ - - return; - } - - if (ChangeElement(x, y, element, page)) - { - if (change->post_change_function) - change->post_change_function(x, y); - } - } -} - -#endif - static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, int trigger_element, int trigger_event, @@ -11645,12 +10312,6 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, if (!(trigger_events[trigger_element][trigger_event])) return FALSE; -#if 0 - printf("::: CheckTriggeredElementChangeExt %d ... [%d, %d, %d, '%s']\n", - trigger_event, recursion_loop_depth, recursion_loop_detected, - recursion_loop_element, EL_NAME(recursion_loop_element)); -#endif - RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -11681,11 +10342,6 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); -#if 0 - printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d\n", - element, EL_NAME(element), p); -#endif - if ((change->can_change && !change_done) || change->has_action) { int x, y; @@ -11696,7 +10352,6 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { if (change->can_change && !change_done) { -#if USE_FIX_NO_ACTION_AFTER_CHANGE /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ @@ -11704,22 +10359,14 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; -#endif - -#if 0 - printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- CHANGE\n", - element, EL_NAME(element), p); -#endif ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; HandleElementChange(x, y, p); } -#if USE_NEW_DELAYED_ACTION else if (change->has_action) { -#if USE_FIX_NO_ACTION_AFTER_CHANGE /* if element already changed in this frame, not only prevent another element change (checked in ChangeElement()), but also prevent additional element actions for this element */ @@ -11727,24 +10374,10 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) continue; -#endif - -#if 0 - printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- ACTION\n", - element, EL_NAME(element), p); -#endif - - ExecuteCustomElementAction(x, y, element, p); - PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); - } -#else - if (change->has_action) - { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } -#endif } } @@ -11752,12 +10385,6 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { change_done = TRUE; change_done_any = TRUE; - -#if 0 - printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- DONE\n", - element, EL_NAME(element), p); -#endif - } } } @@ -11789,11 +10416,6 @@ static boolean CheckElementChangeExt(int x, int y, element = Feld[x][y]; } -#if 0 - /* check if element has already changed */ - if (Feld[x][y] != element) - return FALSE; -#else /* check if element has already changed or is about to change after moving */ if ((game.engine_version < VERSION_IDENT(3,2,0,7) && Feld[x][y] != element) || @@ -11802,20 +10424,9 @@ static boolean CheckElementChangeExt(int x, int y, (ChangeCount[x][y] >= game.max_num_changes_per_frame || ChangePage[x][y] != -1))) return FALSE; -#endif - -#if 0 - printf("::: CheckElementChangeExt %d ... [%d, %d, %d, '%s']\n", - trigger_event, recursion_loop_depth, recursion_loop_detected, - recursion_loop_element, EL_NAME(recursion_loop_element)); -#endif RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); -#if 0 - printf("::: X: trigger_player_bits == %d\n", trigger_player); -#endif - for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; @@ -11828,10 +10439,7 @@ static boolean CheckElementChangeExt(int x, int y, (trigger_event == CE_TOUCHING_X || trigger_event == CE_HITTING_X || trigger_event == CE_HIT_BY_X || -#if 1 - /* this one was forgotten until 3.2.3 */ - trigger_event == CE_DIGGING_X); -#endif + trigger_event == CE_DIGGING_X); /* this one was forgotten until 3.2.3 */ if (change->can_change_or_has_action && change->has_event[trigger_event] && @@ -11880,19 +10488,11 @@ static boolean CheckElementChangeExt(int x, int y, change_done = TRUE; } -#if USE_NEW_DELAYED_ACTION else if (change->has_action) { ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } -#else - if (change->has_action) - { - ExecuteCustomElementAction(x, y, element, p); - PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); - } -#endif } } @@ -12083,18 +10683,49 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) } } +static void CheckSaveEngineSnapshot(struct PlayerInfo *player) +{ + if ((!player->is_moving && player->was_moving) || + (player->MovPos == 0 && player->was_moving) || + (player->is_snapping && !player->was_snapping) || + (player->is_dropping && !player->was_dropping)) + { + if (!CheckSaveEngineSnapshotToList()) + return; + + player->was_moving = FALSE; + player->was_snapping = TRUE; + player->was_dropping = TRUE; + } + else + { + if (player->is_moving) + player->was_moving = TRUE; + + if (!player->is_snapping) + player->was_snapping = FALSE; + + if (!player->is_dropping) + player->was_dropping = FALSE; + } +} + static void CheckSingleStepMode(struct PlayerInfo *player) { if (tape.single_step && tape.recording && !tape.pausing) { /* as it is called "single step mode", just return to pause mode when the player stopped moving after one tile (or never starts moving at all) */ - if (!player->is_moving && !player->is_pushing) + if (!player->is_moving && + !player->is_pushing && + !player->is_dropping_pressed) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); SnapField(player, 0, 0); /* stop snapping */ } } + + CheckSaveEngineSnapshot(player); } static byte PlayerActions(struct PlayerInfo *player, byte player_action) @@ -12220,18 +10851,11 @@ static void CheckLevelTime() if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); -#if 1 /* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value is reset from other values in UpdateGameDoorValues() -- FIX THIS */ game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; - /* (already called by UpdateAndDisplayGameControlValues() below) */ - // DisplayGameControlValues(); -#else - DrawGameValue_Time(TimeLeft); -#endif - if (!TimeLeft && setup.time_limit) { if (level.game_engine_type == GAME_ENGINE_TYPE_EM) @@ -12241,18 +10865,10 @@ static void CheckLevelTime() KillPlayer(&stored_player[i]); } } -#if 1 else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; - - /* (already called by UpdateAndDisplayGameControlValues() below) */ - // DisplayGameControlValues(); } -#else - else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ - DrawGameValue_Time(TimePlayed); -#endif level.native_em_level->lev->time = (game.no_time_limit ? TimePlayed : TimeLeft); @@ -12262,12 +10878,10 @@ static void CheckLevelTime() DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); } -#if 1 + if (tape.recording || tape.playing) + DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); + UpdateAndDisplayGameControlValues(); -#else - UpdateGameDoorValues(); - DrawGameDoorValues(); -#endif } void AdvanceFrameAndPlayerCounters(int player_nr) @@ -12288,7 +10902,6 @@ void AdvanceFrameAndPlayerCounters(int player_nr) if (!advance_player_counters) /* not all players may be affected */ continue; -#if USE_NEW_PLAYER_ANIM if (move_frames == 0) /* less than one move per game frame */ { int stepsize = TILEX / move_delay_value; @@ -12299,7 +10912,6 @@ void AdvanceFrameAndPlayerCounters(int player_nr) if (count % delay == 0) move_frames = 1; } -#endif stored_player[i].Frame += move_frames; @@ -12341,9 +10953,11 @@ void StartGameActions(boolean init_network_game, boolean record_tape, InitGame(); } -void GameActions() +void GameActionsExt() { +#if 0 static unsigned int game_frame_delay = 0; +#endif unsigned int game_frame_delay_value; byte *recorded_player_action; byte summarized_player_action = 0; @@ -12421,13 +11035,26 @@ void GameActions() if (tape.playing && tape.warp_forward && !tape.pausing) game_frame_delay_value = 0; + SetVideoFrameDelay(game_frame_delay_value); + +#if 0 +#if 0 /* ---------- main game synchronization point ---------- */ - WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); + int skip = WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); - if (network_playing && !network_player_action_received) - { - /* try to get network player actions in time */ + printf("::: skip == %d\n", skip); + +#else + /* ---------- main game synchronization point ---------- */ + + WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); +#endif +#endif + + if (network_playing && !network_player_action_received) + { + /* try to get network player actions in time */ #if defined(NETWORK_AVALIABLE) /* last chance to get network player actions without main loop delay */ @@ -12454,11 +11081,9 @@ void GameActions() /* when playing tape, read previously recorded player input from tape data */ recorded_player_action = (tape.playing ? TapePlayAction() : NULL); -#if 1 /* TapePlayAction() may return NULL when toggling to "pause before death" */ if (tape.pausing) return; -#endif if (tape.set_centered_player) { @@ -12470,13 +11095,8 @@ void GameActions() { summarized_player_action |= stored_player[i].action; -#if 1 if (!network_playing && (game.team_mode || tape.playing)) stored_player[i].effective_action = stored_player[i].action; -#else - if (!network_playing) - stored_player[i].effective_action = stored_player[i].action; -#endif } #if defined(NETWORK_AVALIABLE) @@ -12484,8 +11104,11 @@ void GameActions() SendToServer_MovePlayer(summarized_player_action); #endif + // summarize all actions at local players mapped input device position + // (this allows using different input devices in single player mode) if (!options.network && !game.team_mode) - local_player->effective_action = summarized_player_action; + stored_player[map_player_action[local_player->index_nr]].effective_action = + summarized_player_action; if (tape.recording && setup.team_mode && @@ -12505,19 +11128,13 @@ void GameActions() { tape_action[i] = stored_player[i].effective_action; -#if 1 /* (this may happen in the RND game engine if a player was not present on the playfield on level start, but appeared later from a custom element */ - if (tape.recording && - setup.team_mode && + if (setup.team_mode && + tape.recording && tape_action[i] && !tape.player_participates[i]) tape.player_participates[i] = TRUE; -#else - /* (this can only happen in the R'n'D game engine) */ - if (tape.recording && tape_action[i] && !tape.player_participates[i]) - tape.player_participates[i] = TRUE; /* player just appeared from CE */ -#endif } /* only record actions from input devices, but not programmed actions */ @@ -12525,9 +11142,9 @@ void GameActions() TapeRecordAction(tape_action); #if USE_NEW_PLAYER_ASSIGNMENTS -#if 1 - if (game.team_mode) -#endif + // !!! also map player actions in single player mode !!! + // if (game.team_mode) + if (1) { byte mapped_action[MAX_PLAYERS]; @@ -12561,40 +11178,20 @@ void GameActions() #endif #endif -#if 0 - printf("::: summarized_player_action == %d\n", - local_player->effective_action); -#endif - - - - -#if 0 -#if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status (final):\n"); - - for (i = 0; i < MAX_PLAYERS; i++) - { - struct PlayerInfo *player = &stored_player[i]; - - printf("- player %d: present == %d, connected == %d, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } - } -#endif -#endif + for (i = 0; i < MAX_PLAYERS; i++) + { + // allow engine snapshot in case of changed movement attempt + if ((game.snapshot.last_action[i] & KEY_MOTION) != + (stored_player[i].effective_action & KEY_MOTION)) + game.snapshot.changed_action = TRUE; + // allow engine snapshot in case of snapping/dropping attempt + if ((game.snapshot.last_action[i] & KEY_BUTTON) == 0 && + (stored_player[i].effective_action & KEY_BUTTON) != 0) + game.snapshot.changed_action = TRUE; + game.snapshot.last_action[i] = stored_player[i].effective_action; + } if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -12606,10 +11203,53 @@ void GameActions() } else { - GameActions_RND(); + GameActions_RND_Main(); + } + + BlitScreenToBitmap(backbuffer); + + CheckLevelTime(); + + AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ + + if (options.debug) /* calculate frames per second */ + { + static unsigned int fps_counter = 0; + static int fps_frames = 0; + unsigned int fps_delay_ms = Counter() - fps_counter; + + fps_frames++; + + if (fps_delay_ms >= 500) /* calculate fps every 0.5 seconds */ + { + global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; + + fps_frames = 0; + fps_counter = Counter(); + } + + redraw_mask |= REDRAW_FPS; } } +static void GameActions_CheckSaveEngineSnapshot() +{ + if (!game.snapshot.save_snapshot) + return; + + // clear flag for saving snapshot _before_ saving snapshot + game.snapshot.save_snapshot = FALSE; + + SaveEngineSnapshotToList(); +} + +void GameActions() +{ + GameActionsExt(); + + GameActions_CheckSaveEngineSnapshot(); +} + void GameActions_EM_Main() { byte effective_action[MAX_PLAYERS]; @@ -12620,10 +11260,6 @@ void GameActions_EM_Main() effective_action[i] = stored_player[i].effective_action; GameActions_EM(effective_action, warp_mode); - - CheckLevelTime(); - - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ } void GameActions_SP_Main() @@ -12637,19 +11273,27 @@ void GameActions_SP_Main() GameActions_SP(effective_action, warp_mode); - CheckLevelTime(); + for (i = 0; i < MAX_PLAYERS; i++) + { + if (stored_player[i].force_dropping) + stored_player[i].action |= KEY_BUTTON_DROP; - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ + stored_player[i].force_dropping = FALSE; + } +} + +void GameActions_RND_Main() +{ + GameActions_RND(); } void GameActions_RND() { int magic_wall_x = 0, magic_wall_y = 0; - int i, x, y, element, graphic; + int i, x, y, element, graphic, last_gfx_frame; InitPlayfieldScanModeVars(); -#if USE_ONE_MORE_CHANGE_PER_FRAME if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { SCAN_PLAYFIELD(x, y) @@ -12658,7 +11302,6 @@ void GameActions_RND() ChangeEvent[x][y] = -1; } } -#endif if (game.set_centered_player) { @@ -12758,10 +11401,6 @@ void GameActions_RND() } } -#if 0 - debug_print_timestamp(0, "start main loop profiling"); -#endif - SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; @@ -12775,7 +11414,6 @@ void GameActions_RND() RemoveField(x, y); } -#if USE_NEW_SNAP_DELAY if (Feld[x][y] == EL_ELEMENT_SNAPPING) { MovDelay[x][y]--; @@ -12787,7 +11425,6 @@ void GameActions_RND() TestIfElementTouchesCustomElement(x, y); /* for empty space */ } } -#endif #if DEBUG if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1) @@ -12836,69 +11473,16 @@ void GameActions_RND() #endif } -#if 0 - debug_print_timestamp(0, "- time for pre-main loop:"); -#endif - -#if 0 // -------------------- !!! TEST ONLY !!! -------------------- SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + last_gfx_frame = GfxFrame[x][y]; -#if 1 - { -#if 1 - int element2 = element; - int graphic2 = graphic; -#else - int element2 = Feld[x][y]; - int graphic2 = el_act_dir2img(element2, GfxAction[x][y], GfxDir[x][y]); -#endif - int last_gfx_frame = GfxFrame[x][y]; - - if (graphic_info[graphic2].anim_global_sync) - GfxFrame[x][y] = FrameCounter; - else if (ANIM_MODE(graphic2) == ANIM_CE_VALUE) - GfxFrame[x][y] = CustomValue[x][y]; - else if (ANIM_MODE(graphic2) == ANIM_CE_SCORE) - GfxFrame[x][y] = element_info[element2].collect_score; - else if (ANIM_MODE(graphic2) == ANIM_CE_DELAY) - GfxFrame[x][y] = ChangeDelay[x][y]; - - if (redraw && GfxFrame[x][y] != last_gfx_frame) - DrawLevelGraphicAnimation(x, y, graphic2); - } -#else - ResetGfxFrame(x, y, TRUE); -#endif - -#if 1 - if (ANIM_MODE(graphic) == ANIM_RANDOM && - IS_NEXT_FRAME(GfxFrame[x][y], graphic)) - ResetRandomAnimationValue(x, y); -#endif - -#if 1 - SetRandomAnimationValue(x, y); -#endif - -#if 1 - PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); -#endif - } -#endif // -------------------- !!! TEST ONLY !!! -------------------- - -#if 0 - debug_print_timestamp(0, "- time for TEST loop: -->"); -#endif - - SCAN_PLAYFIELD(x, y) - { - element = Feld[x][y]; - graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + ResetGfxFrame(x, y); - ResetGfxFrame(x, y, TRUE); + if (GfxFrame[x][y] != last_gfx_frame && !Stop[x][y]) + DrawLevelGraphicAnimation(x, y, graphic); if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) @@ -12922,22 +11506,12 @@ void GameActions_RND() { int page = element_info[element].event_page_nr[CE_DELAY]; -#if 1 HandleElementChange(x, y, page); -#else - if (CAN_CHANGE(element)) - HandleElementChange(x, y, page); - - if (HAS_ACTION(element)) - ExecuteCustomElementAction(x, y, element, page); -#endif element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); } -#if 0 // --------------------------------------------------------------------- - if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); @@ -12953,143 +11527,12 @@ void GameActions_RND() if (IS_GEM(element) || element == EL_SP_INFOTRON) TEST_DrawTwinkleOnField(x, y); } - else if (IS_MOVING(x, y)) - ContinueMoving(x, y); - else + else if (element == EL_ACID) { - switch (element) - { - case EL_ACID: - case EL_EXIT_OPEN: - case EL_EM_EXIT_OPEN: - case EL_SP_EXIT_OPEN: - case EL_STEEL_EXIT_OPEN: - case EL_EM_STEEL_EXIT_OPEN: - case EL_SP_TERMINAL: - case EL_SP_TERMINAL_ACTIVE: - case EL_EXTRA_TIME: - case EL_SHIELD_NORMAL: - case EL_SHIELD_DEADLY: - if (IS_ANIMATED(graphic)) - DrawLevelGraphicAnimationIfNeeded(x, y, graphic); - break; - - case EL_DYNAMITE_ACTIVE: - case EL_EM_DYNAMITE_ACTIVE: - case EL_DYNABOMB_PLAYER_1_ACTIVE: - case EL_DYNABOMB_PLAYER_2_ACTIVE: - case EL_DYNABOMB_PLAYER_3_ACTIVE: - case EL_DYNABOMB_PLAYER_4_ACTIVE: - case EL_SP_DISK_RED_ACTIVE: - CheckDynamite(x, y); - break; - - case EL_AMOEBA_GROWING: - AmoebeWaechst(x, y); - break; - - case EL_AMOEBA_SHRINKING: - AmoebaDisappearing(x, y); - break; - -#if !USE_NEW_AMOEBA_CODE - case EL_AMOEBA_WET: - case EL_AMOEBA_DRY: - case EL_AMOEBA_FULL: - case EL_BD_AMOEBA: - case EL_EMC_DRIPPER: - AmoebeAbleger(x, y); - break; -#endif - - case EL_GAME_OF_LIFE: - case EL_BIOMAZE: - Life(x, y); - break; - - case EL_EXIT_CLOSED: - CheckExit(x, y); - break; - - case EL_EM_EXIT_CLOSED: - CheckExitEM(x, y); - break; - - case EL_STEEL_EXIT_CLOSED: - CheckExitSteel(x, y); - break; - - case EL_EM_STEEL_EXIT_CLOSED: - CheckExitSteelEM(x, y); - break; - - case EL_SP_EXIT_CLOSED: - CheckExitSP(x, y); - break; - - case EL_EXPANDABLE_WALL_GROWING: - case EL_EXPANDABLE_STEELWALL_GROWING: - MauerWaechst(x, y); - break; - - case EL_EXPANDABLE_WALL: - case EL_EXPANDABLE_WALL_HORIZONTAL: - case EL_EXPANDABLE_WALL_VERTICAL: - case EL_EXPANDABLE_WALL_ANY: - case EL_BD_EXPANDABLE_WALL: - MauerAbleger(x, y); - break; - - case EL_EXPANDABLE_STEELWALL_HORIZONTAL: - case EL_EXPANDABLE_STEELWALL_VERTICAL: - case EL_EXPANDABLE_STEELWALL_ANY: - MauerAblegerStahl(x, y); - break; - - case EL_FLAMES: - CheckForDragon(x, y); - break; - - case EL_EXPLOSION: - break; - - case EL_ELEMENT_SNAPPING: - case EL_DIAGONAL_SHRINKING: - case EL_DIAGONAL_GROWING: - { - graphic = - el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); - - DrawLevelGraphicAnimationIfNeeded(x, y, graphic); - break; - } - - default: - if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) - DrawLevelGraphicAnimationIfNeeded(x, y, graphic); - break; - } - } - -#else // --------------------------------------------------------------------- - - if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) - { - StartMoving(x, y); - - element = Feld[x][y]; - graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); - - if (IS_ANIMATED(graphic) && - !IS_MOVING(x, y) && - !Stop[x][y]) + if (!Stop[x][y]) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); - - if (IS_GEM(element) || element == EL_SP_INFOTRON) - TEST_DrawTwinkleOnField(x, y); } - else if ((element == EL_ACID || - element == EL_EXIT_OPEN || + else if ((element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || element == EL_SP_EXIT_OPEN || element == EL_STEEL_EXIT_OPEN || @@ -13155,8 +11598,6 @@ void GameActions_RND() else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); -#endif // --------------------------------------------------------------------- - if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); @@ -13182,10 +11623,6 @@ void GameActions_RND() } } -#if 0 - debug_print_timestamp(0, "- time for MAIN loop: -->"); -#endif - #if USE_NEW_AMOEBA_CODE /* new experimental amoeba growth stuff */ if (!(FrameCounter % 8)) @@ -13218,27 +11655,22 @@ void GameActions_RND() } #endif -#if 0 - if (game.explosions_delayed) -#endif - { - game.explosions_delayed = FALSE; - - SCAN_PLAYFIELD(x, y) - { - element = Feld[x][y]; + game.explosions_delayed = FALSE; - if (ExplodeField[x][y]) - Explode(x, y, EX_PHASE_START, ExplodeField[x][y]); - else if (element == EL_EXPLOSION) - Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL); + SCAN_PLAYFIELD(x, y) + { + element = Feld[x][y]; - ExplodeField[x][y] = EX_TYPE_NONE; - } + if (ExplodeField[x][y]) + Explode(x, y, EX_PHASE_START, ExplodeField[x][y]); + else if (element == EL_EXPLOSION) + Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL); - game.explosions_delayed = TRUE; + ExplodeField[x][y] = EX_TYPE_NONE; } + game.explosions_delayed = TRUE; + if (game.magic_wall_active) { if (!(game.magic_wall_time_left % 4)) @@ -13340,12 +11772,7 @@ void GameActions_RND() #if USE_DELAYED_GFX_REDRAW SCAN_PLAYFIELD(x, y) { -#if 1 if (GfxRedraw[x][y] != GFX_REDRAW_NONE) -#else - if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)) && - GfxRedraw[x][y] != GFX_REDRAW_NONE) -#endif { /* !!! PROBLEM: THIS REDRAWS THE PLAYFIELD _AFTER_ THE SCAN, BUT TILES !!! MAY HAVE CHANGED AFTER BEING DRAWN DURING PLAYFIELD SCAN !!! */ @@ -13367,32 +11794,9 @@ void GameActions_RND() } #endif - CheckLevelTime(); - DrawAllPlayers(); PlayAllPlayersSound(); - if (options.debug) /* calculate frames per second */ - { - static unsigned int fps_counter = 0; - static int fps_frames = 0; - unsigned int fps_delay_ms = Counter() - fps_counter; - - fps_frames++; - - if (fps_delay_ms >= 500) /* calculate fps every 0.5 seconds */ - { - global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; - - fps_frames = 0; - fps_counter = Counter(); - } - - redraw_mask |= REDRAW_FPS; - } - - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ - if (local_player->show_envelope != 0 && local_player->MovPos == 0) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); @@ -13400,11 +11804,6 @@ void GameActions_RND() local_player->show_envelope = 0; } -#if 0 - debug_print_timestamp(0, "stop main loop profiling "); - printf("----------------------------------------------------------\n"); -#endif - /* use random number generator in every frame to make it less predictable */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); @@ -13451,101 +11850,16 @@ static boolean AllPlayersInVisibleScreen() void ScrollLevel(int dx, int dy) { -#if 0 - /* (directly solved in BlitBitmap() now) */ - static Bitmap *bitmap_db_field2 = NULL; - int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); - int x, y; -#else + int scroll_offset = 2 * TILEX_VAR; int x, y; -#endif - -#if 0 - /* !!! THIS IS APPARENTLY WRONG FOR PLAYER RELOCATION !!! */ - /* only horizontal XOR vertical scroll direction allowed */ - if ((dx == 0 && dy == 0) || (dx != 0 && dy != 0)) - return; -#endif - -#if 0 - /* (directly solved in BlitBitmap() now) */ - if (bitmap_db_field2 == NULL) - bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); - - /* needed when blitting directly to same bitmap -- should not be needed with - recent SDL libraries, but apparently does not work in 1.2.11 directly */ - BlitBitmap(drawto_field, bitmap_db_field2, - FX + TILEX * (dx == -1) - softscroll_offset, - FY + TILEY * (dy == -1) - softscroll_offset, - SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, - SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, - FX + TILEX * (dx == 1) - softscroll_offset, - FY + TILEY * (dy == 1) - softscroll_offset); - BlitBitmap(bitmap_db_field2, drawto_field, - FX + TILEX * (dx == 1) - softscroll_offset, - FY + TILEY * (dy == 1) - softscroll_offset, - SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, - SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, - FX + TILEX * (dx == 1) - softscroll_offset, - FY + TILEY * (dy == 1) - softscroll_offset); - -#else - -#if 0 - /* !!! DOES NOT WORK FOR DIAGONAL PLAYER RELOCATION !!! */ - int xsize = (BX2 - BX1 + 1); - int ysize = (BY2 - BY1 + 1); - int start = (dx != 0 ? (dx == -1 ? BX1 : BX2) : (dy == -1 ? BY1 : BY2)); - int end = (dx != 0 ? (dx == -1 ? BX2 : BX1) : (dy == -1 ? BY2 : BY1)); - int step = (start < end ? +1 : -1); - - for (i = start; i != end; i += step) - { - BlitBitmap(drawto_field, drawto_field, - FX + TILEX * (dx != 0 ? i + step : 0), - FY + TILEY * (dy != 0 ? i + step : 0), - TILEX * (dx != 0 ? 1 : xsize), - TILEY * (dy != 0 ? 1 : ysize), - FX + TILEX * (dx != 0 ? i : 0), - FY + TILEY * (dy != 0 ? i : 0)); - } - -#else - -#if NEW_TILESIZE -#if NEW_SCROLL - int softscroll_offset = (setup.soft_scrolling ? 2 * TILEX_VAR : 0); -#else - int softscroll_offset = (setup.soft_scrolling ? TILEX_VAR : 0); -#endif -#else -#if NEW_SCROLL - int softscroll_offset = (setup.soft_scrolling ? 2 * TILEX : 0); -#else - int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); -#endif -#endif -#if NEW_TILESIZE BlitBitmap(drawto_field, drawto_field, - FX + TILEX_VAR * (dx == -1) - softscroll_offset, - FY + TILEY_VAR * (dy == -1) - softscroll_offset, - SXSIZE - TILEX_VAR * (dx != 0) + 2 * softscroll_offset, - SYSIZE - TILEY_VAR * (dy != 0) + 2 * softscroll_offset, - FX + TILEX_VAR * (dx == 1) - softscroll_offset, - FY + TILEY_VAR * (dy == 1) - softscroll_offset); -#else - BlitBitmap(drawto_field, drawto_field, - FX + TILEX * (dx == -1) - softscroll_offset, - FY + TILEY * (dy == -1) - softscroll_offset, - SXSIZE - TILEX * (dx != 0) + 2 * softscroll_offset, - SYSIZE - TILEY * (dy != 0) + 2 * softscroll_offset, - FX + TILEX * (dx == 1) - softscroll_offset, - FY + TILEY * (dy == 1) - softscroll_offset); -#endif - -#endif -#endif + FX + TILEX_VAR * (dx == -1) - scroll_offset, + FY + TILEY_VAR * (dy == -1) - scroll_offset, + SXSIZE - TILEX_VAR * (dx != 0) + 2 * scroll_offset, + SYSIZE - TILEY_VAR * (dy != 0) + 2 * scroll_offset, + FX + TILEX_VAR * (dx == 1) - scroll_offset, + FY + TILEY_VAR * (dy == 1) - scroll_offset); if (dx != 0) { @@ -13608,11 +11922,7 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir) static void CheckGravityMovement(struct PlayerInfo *player) { -#if USE_PLAYER_GRAVITY if (player->gravity && !player->programmed_action) -#else - if (game.gravity && !player->programmed_action) -#endif { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; @@ -13634,11 +11944,7 @@ static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player) { return CheckGravityMovement(player); -#if USE_PLAYER_GRAVITY if (player->gravity && !player->programmed_action) -#else - if (game.gravity && !player->programmed_action) -#endif { int jx = player->jx, jy = player->jy; boolean field_under_player_is_free = @@ -13665,9 +11971,6 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, { int jx = player->jx, jy = player->jy; int new_jx = jx + dx, new_jy = jy + dy; -#if !USE_FIXED_DONT_RUN_INTO - int element; -#endif int can_move; boolean player_can_move = !player->cannot_move; @@ -13694,36 +11997,9 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, } } -#if 1 if (!options.network && game.centered_player_nr == -1 && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; -#else - if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) - return MP_NO_ACTION; -#endif - -#if !USE_FIXED_DONT_RUN_INTO - element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); - - /* (moved to DigField()) */ - if (player_can_move && DONT_RUN_INTO(element)) - { - if (element == EL_ACID && dx == 0 && dy == 1) - { - SplashAcid(new_jx, new_jy); - Feld[jx][jy] = EL_PLAYER_1; - InitMovingField(jx, jy, MV_DOWN); - Store[jx][jy] = EL_ACID; - ContinueMoving(jx, jy); - BuryPlayer(player); - } - else - TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); - - return MP_MOVING; - } -#endif can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG); if (can_move != MP_MOVING) @@ -13753,9 +12029,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, PlayerVisit[jx][jy] = FrameCounter; -#if USE_UFAST_PLAYER_EXIT_BUGFIX player->is_moving = TRUE; -#endif #if 1 /* should better be called in MovePlayer(), but this breaks some tapes */ @@ -13822,7 +12096,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) AdvanceFrameAndPlayerCounters(player->index_nr); DrawAllPlayers(); - BackToFront(); + BackToFront_WithFrameDelay(0); } player->move_delay_value = original_move_delay_value; @@ -13841,7 +12115,6 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) moved |= MovePlayerOneStep(player, 0, dy, dx, dy); } -#if USE_FIXED_BORDER_RUNNING_GFX if (!moved && !player->is_active) { player->is_moving = FALSE; @@ -13850,19 +12123,13 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->is_snapping = FALSE; player->is_pushing = FALSE; } -#endif jx = player->jx; jy = player->jy; -#if 1 if (moved & MP_MOVING && !ScreenMovPos && (player->index_nr == game.centered_player_nr || game.centered_player_nr == -1)) -#else - if (moved & MP_MOVING && !ScreenMovPos && - (player == local_player || !options.network)) -#endif { int old_scroll_x = scroll_x, old_scroll_y = scroll_y; int offset = game.scroll_delay_value; @@ -13917,7 +12184,6 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) if (scroll_x != old_scroll_x || scroll_y != old_scroll_y) { -#if 1 if (!options.network && game.centered_player_nr == -1 && !AllPlayersInVisibleScreen()) { @@ -13925,14 +12191,6 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) scroll_y = old_scroll_y; } else -#else - if (!options.network && !AllPlayersInVisibleScreen()) - { - scroll_x = old_scroll_x; - scroll_y = old_scroll_y; - } - else -#endif { ScrollScreen(player, SCROLL_INIT); ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y); @@ -14000,16 +12258,11 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) int last_jx = player->last_jx, last_jy = player->last_jy; int move_stepsize = TILEX / player->move_delay_value; -#if USE_NEW_PLAYER_SPEED if (!player->active) return; if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ return; -#else - if (!player->active || player->MovPos == 0) - return; -#endif if (mode == SCROLL_INIT) { @@ -14028,13 +12281,8 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) last_field_block_delay += player->move_delay_value; /* when blocking enabled, prevent moving up despite gravity */ -#if USE_PLAYER_GRAVITY if (player->gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; -#else - if (game.gravity && player->MovDir == MV_UP) - block_delay_adjustment = -1; -#endif } /* add block delay adjustment (also possible when not blocking) */ @@ -14044,17 +12292,12 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } -#if USE_NEW_PLAYER_SPEED if (player->MovPos != 0) /* player has not yet reached destination */ return; -#else - return; -#endif } else if (!FrameReached(&player->actual_frame_counter, 1)) return; -#if USE_NEW_PLAYER_SPEED if (player->MovPos != 0) { player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; @@ -14064,14 +12307,6 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (player->MovPos == 0) CheckGravityMovement(player); } -#else - player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; - player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); - - /* before DrawPlayer() to draw correct player graphic for this case */ - if (player->MovPos == 0) - CheckGravityMovement(player); -#endif if (player->MovPos == 0) /* player reached destination field */ { @@ -14094,14 +12329,10 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (Feld[jx][jy] == EL_EXIT_OPEN || Feld[jx][jy] == EL_EM_EXIT_OPEN || -#if 1 Feld[jx][jy] == EL_EM_EXIT_OPENING || -#endif Feld[jx][jy] == EL_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN || -#if 1 Feld[jx][jy] == EL_EM_STEEL_EXIT_OPENING || -#endif Feld[jx][jy] == EL_SP_EXIT_OPEN || Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ { @@ -14140,13 +12371,8 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) CE_PLAYER_ENTERS_X, player->index_bit, enter_side); -#if USE_FIX_CE_ACTION_WITH_PLAYER CheckTriggeredElementChangeBySide(jx, jy, player->initial_element, CE_MOVE_OF_X, move_direction); -#else - CheckTriggeredElementChangeBySide(jx, jy, player->element_nr, - CE_MOVE_OF_X, move_direction); -#endif } if (game.engine_version >= VERSION_IDENT(3,0,7,0)) @@ -14176,34 +12402,28 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); -#if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); -#else - DrawGameValue_Time(TimeLeft); -#endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } -#if 1 else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } -#else - else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ - DrawGameValue_Time(TimePlayed); -#endif } if (tape.single_step && tape.recording && !tape.pausing && !player->programmed_action) TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + + if (!player->programmed_action) + CheckSaveEngineSnapshot(player); } } @@ -14292,7 +12512,6 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CE_PLAYER_TOUCHES_X, player->index_bit, border_side); -#if USE_FIX_CE_ACTION_WITH_PLAYER { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number @@ -14303,7 +12522,6 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckElementChangeBySide(xx, yy, border_element, player_element, CE_TOUCHING_X, border_side); } -#endif } else if (IS_PLAYER(xx, yy)) /* player found at border element */ { @@ -14321,7 +12539,6 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CE_PLAYER_TOUCHES_X, player->index_bit, center_side); -#if USE_FIX_CE_ACTION_WITH_PLAYER { /* use player element that is initially defined in the level playfield, not the player element that corresponds to the runtime player number @@ -14332,15 +12549,12 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, center_side); } -#endif break; } } } -#if USE_ELEMENT_TOUCHING_BUGFIX - void TestIfElementTouchesCustomElement(int x, int y) { static int xy[4][2] = @@ -14426,7 +12640,6 @@ void TestIfElementTouchesCustomElement(int x, int y) CheckElementChangeBySide(x, y, center_element, border_element, CE_TOUCHING_X, border_side); -#if USE_FIX_CE_ACTION_WITH_PLAYER if (IS_PLAYER(xx, yy)) { /* use player element that is initially defined in the level playfield, @@ -14438,74 +12651,9 @@ void TestIfElementTouchesCustomElement(int x, int y) CheckElementChangeBySide(x, y, center_element, player_element, CE_TOUCHING_X, border_side); } -#endif - } -} - -#else - -void TestIfElementTouchesCustomElement_OLD(int x, int y) -{ - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; - static int trigger_sides[4][2] = - { - /* center side border side */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ - }; - static int touch_dir[4] = - { - MV_LEFT | MV_RIGHT, - MV_UP | MV_DOWN, - MV_UP | MV_DOWN, - MV_LEFT | MV_RIGHT - }; - boolean change_center_element = FALSE; - int center_element = Feld[x][y]; /* should always be non-moving! */ - int i; - - for (i = 0; i < NUM_DIRECTIONS; i++) - { - int xx = x + xy[i][0]; - int yy = y + xy[i][1]; - int center_side = trigger_sides[i][0]; - int border_side = trigger_sides[i][1]; - int border_element; - - if (!IN_LEV_FIELD(xx, yy)) - continue; - - if (game.engine_version < VERSION_IDENT(3,0,7,0)) - border_element = Feld[xx][yy]; /* may be moving! */ - else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) - border_element = Feld[xx][yy]; - else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ - border_element = MovingOrBlocked2Element(xx, yy); - else - continue; /* center and border element do not touch */ - - /* check for change of center element (but change it only once) */ - if (!change_center_element) - change_center_element = - CheckElementChangeBySide(x, y, center_element, border_element, - CE_TOUCHING_X, border_side); - - /* check for change of border element */ - CheckElementChangeBySide(xx, yy, border_element, center_element, - CE_TOUCHING_X, center_side); } } -#endif - void TestIfElementHitsCustomElement(int x, int y, int direction) { int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); @@ -14542,7 +12690,6 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, CE_HIT_BY_SOMETHING, opposite_direction); -#if USE_FIX_CE_ACTION_WITH_PLAYER if (IS_PLAYER(hitx, hity)) { /* use player element that is initially defined in the level playfield, @@ -14554,7 +12701,6 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) CheckElementChangeBySide(x, y, hitting_element, player_element, CE_HITTING_X, touched_side); } -#endif } } @@ -14563,69 +12709,6 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) CE_HITTING_SOMETHING, direction); } -#if 0 -void TestIfElementSmashesCustomElement(int x, int y, int direction) -{ - int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); - int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); - int hitx = x + dx, hity = y + dy; - int hitting_element = Feld[x][y]; - int touched_element; -#if 0 - boolean object_hit = (IN_LEV_FIELD(hitx, hity) && - !IS_FREE(hitx, hity) && - (!IS_MOVING(hitx, hity) || - MovDir[hitx][hity] != direction || - ABS(MovPos[hitx][hity]) <= TILEY / 2)); -#endif - - if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity)) - return; - -#if 0 - if (IN_LEV_FIELD(hitx, hity) && !object_hit) - return; -#endif - - touched_element = (IN_LEV_FIELD(hitx, hity) ? - MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL); - - CheckElementChangeBySide(x, y, hitting_element, touched_element, - EP_CAN_SMASH_EVERYTHING, direction); - - if (IN_LEV_FIELD(hitx, hity)) - { - int opposite_direction = MV_DIR_OPPOSITE(direction); - int hitting_side = direction; - int touched_side = opposite_direction; -#if 0 - int touched_element = MovingOrBlocked2Element(hitx, hity); -#endif -#if 1 - boolean object_hit = (!IS_MOVING(hitx, hity) || - MovDir[hitx][hity] != direction || - ABS(MovPos[hitx][hity]) <= TILEY / 2); - - object_hit = TRUE; -#endif - - if (object_hit) - { - int i; - - CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, - CE_SMASHED_BY_SOMETHING, opposite_direction); - - CheckElementChangeBySide(x, y, hitting_element, touched_element, - CE_OTHER_IS_SMASHING, touched_side); - - CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, - CE_OTHER_GETS_SMASHED, hitting_side); - } - } -} -#endif - void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) { int i, kill_x = -1, kill_y = -1; @@ -14957,19 +13040,10 @@ void KillPlayer(struct PlayerInfo *player) player->killed, player->active, player->reanimated); #endif -#if USE_PLAYER_REANIMATION -#if 1 if (player->reanimated) /* killed player may have been reanimated */ player->killed = player->reanimated = FALSE; else BuryPlayer(player); -#else - if (player->killed) /* player may have been reanimated */ - BuryPlayer(player); -#endif -#else - BuryPlayer(player); -#endif } static void KillPlayerUnlessEnemyProtected(int x, int y) @@ -15023,7 +13097,6 @@ void RemovePlayer(struct PlayerInfo *player) ExitY = ZY = jy; } -#if USE_NEW_SNAP_DELAY static void setFieldForSnapping(int x, int y, int element, int direction) { struct ElementInfo *ei = &element_info[element]; @@ -15042,7 +13115,6 @@ static void setFieldForSnapping(int x, int y, int element, int direction) GfxDir[x][y] = direction; GfxFrame[x][y] = -1; } -#endif /* ============================================================================= @@ -15099,11 +13171,7 @@ static int DigField(struct PlayerInfo *player, int opposite_direction = MV_DIR_OPPOSITE(move_direction); int dig_side = MV_DIR_OPPOSITE(move_direction); int old_element = Feld[jx][jy]; -#if USE_FIXED_DONT_RUN_INTO int element = MovingOrBlocked2ElementIfNotLeaving(x, y); -#else - int element; -#endif int collect_count; if (is_player) /* function can also be called by EL_PENGUIN */ @@ -15126,11 +13194,6 @@ static int DigField(struct PlayerInfo *player, } } -#if !USE_FIXED_DONT_RUN_INTO - if (IS_MOVING(x, y) || IS_PLAYER(x, y)) - return MP_NO_ACTION; -#endif - if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; @@ -15145,7 +13208,6 @@ static int DigField(struct PlayerInfo *player, if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) return MP_NO_ACTION; /* field has no opening in this direction */ -#if USE_FIXED_DONT_RUN_INTO if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) { SplashAcid(x, y); @@ -15158,25 +13220,16 @@ static int DigField(struct PlayerInfo *player, return MP_DONT_RUN_INTO; } -#endif -#if USE_FIXED_DONT_RUN_INTO if (player_can_move && DONT_RUN_INTO(element)) { TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir); return MP_DONT_RUN_INTO; } -#endif -#if USE_FIXED_DONT_RUN_INTO if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MP_NO_ACTION; -#endif - -#if !USE_FIXED_DONT_RUN_INTO - element = Feld[x][y]; -#endif collect_count = element_info[element].collect_count_initial; @@ -15203,17 +13256,10 @@ static int DigField(struct PlayerInfo *player, return MP_NO_ACTION; } -#if USE_PLAYER_GRAVITY if (player->gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MP_NO_ACTION; /* player cannot walk here due to gravity */ -#else - if (game.gravity && is_player && !player->is_auto_moving && - canFallDown(player) && move_direction != MV_DOWN && - !canMoveToValidFieldWithGravity(jx, jy, move_direction)) - return MP_NO_ACTION; /* player cannot walk here due to gravity */ -#endif if (player_can_move && IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) @@ -15238,14 +13284,10 @@ static int DigField(struct PlayerInfo *player, } else if (element == EL_EXIT_OPEN || element == EL_EM_EXIT_OPEN || -#if 1 element == EL_EM_EXIT_OPENING || -#endif element == EL_STEEL_EXIT_OPEN || element == EL_EM_STEEL_EXIT_OPEN || -#if 1 element == EL_EM_STEEL_EXIT_OPENING || -#endif element == EL_SP_EXIT_OPEN || element == EL_SP_EXIT_OPENING) { @@ -15316,29 +13358,17 @@ static int DigField(struct PlayerInfo *player, element == EL_SP_GRAVITY_PORT_RIGHT || element == EL_SP_GRAVITY_PORT_UP || element == EL_SP_GRAVITY_PORT_DOWN) -#if USE_PLAYER_GRAVITY player->gravity = !player->gravity; -#else - game.gravity = !game.gravity; -#endif else if (element == EL_SP_GRAVITY_ON_PORT_LEFT || element == EL_SP_GRAVITY_ON_PORT_RIGHT || element == EL_SP_GRAVITY_ON_PORT_UP || element == EL_SP_GRAVITY_ON_PORT_DOWN) -#if USE_PLAYER_GRAVITY player->gravity = TRUE; -#else - game.gravity = TRUE; -#endif else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT || element == EL_SP_GRAVITY_OFF_PORT_RIGHT || element == EL_SP_GRAVITY_OFF_PORT_UP || element == EL_SP_GRAVITY_OFF_PORT_DOWN) -#if USE_PLAYER_GRAVITY - player->gravity = FALSE; -#else - game.gravity = FALSE; -#endif + player->gravity = FALSE; } /* automatically move to the next field with double speed */ @@ -15370,14 +13400,10 @@ static int DigField(struct PlayerInfo *player, if (mode == DF_SNAP) { -#if USE_NEW_SNAP_DELAY if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#else - TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#endif CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); @@ -15401,13 +13427,9 @@ static int DigField(struct PlayerInfo *player, { TimeLeft += level.extra_time; -#if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); -#else - DrawGameValue_Time(TimeLeft); -#endif } else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) { @@ -15486,13 +13508,11 @@ static int DigField(struct PlayerInfo *player, if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; -#if 1 + game.snapshot.collected_item = TRUE; + game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); -#else - DrawGameValue_Emeralds(local_player->gems_still_needed); -#endif } RaiseScoreElement(element); @@ -15504,14 +13524,10 @@ static int DigField(struct PlayerInfo *player, if (mode == DF_SNAP) { -#if USE_NEW_SNAP_DELAY if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#else - TestIfElementTouchesCustomElement(x, y); /* for empty space */ -#endif CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); @@ -15623,13 +13639,8 @@ static int DigField(struct PlayerInfo *player, PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); -#if 1 if (local_player->sokobanfields_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) -#else - if (local_player->sokobanfields_still_needed == 0 && - game.emulation == EMU_SOKOBAN) -#endif { PlayerWins(player); @@ -15697,9 +13708,16 @@ static int DigField(struct PlayerInfo *player, SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) + { Bang(xx, yy); + } else if (Feld[xx][yy] == EL_SP_TERMINAL) + { Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE; + + ResetGfxAnimation(xx, yy); + TEST_DrawLevelField(xx, yy); + } } } else if (IS_BELT_SWITCH(element)) @@ -15754,13 +13772,9 @@ static int DigField(struct PlayerInfo *player, TimeLeft += level.time_orb_time; game.no_time_limit = FALSE; -#if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); -#else - DrawGameValue_Time(TimeLeft); -#endif } ResetGfxAnimation(x, y); @@ -15887,20 +13901,9 @@ static boolean DigFieldByCE(int x, int y, int digging_element) Store[x][y] = EL_EMPTY; -#if 1 /* this makes it possible to leave the removed element again */ if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) Store[x][y] = element; -#else - if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) - { - int move_leave_element = element_info[digging_element].move_leave_element; - - /* this makes it possible to leave the removed element again */ - Store[x][y] = (move_leave_element == EL_TRIGGER_ELEMENT ? - element : move_leave_element); - } -#endif return TRUE; } @@ -15942,14 +13945,9 @@ static boolean SnapField(struct PlayerInfo *player, int dx, int dy) return FALSE; } -#if USE_NEW_CONTINUOUS_SNAPPING /* prevent snapping with already pressed snap key when not allowed */ if (player->is_snapping && !can_continue_snapping) return FALSE; -#else - if (player->is_snapping) - return FALSE; -#endif player->MovDir = snap_direction; @@ -15991,19 +13989,7 @@ static boolean DropElement(struct PlayerInfo *player) int dropx = player->jx, dropy = player->jy; int drop_direction = player->MovDir; int drop_side = drop_direction; -#if 1 int drop_element = get_next_dropped_element(player); -#else - int drop_element = (player->inventory_size > 0 ? - player->inventory_element[player->inventory_size - 1] : - player->inventory_infinite_element != EL_UNDEFINED ? - player->inventory_infinite_element : - player->dynabombs_left > 0 ? - EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : - EL_UNDEFINED); -#endif - - player->is_dropping_pressed = TRUE; /* do not drop an element on top of another element; when holding drop key pressed without moving, dropped element must move away before the next @@ -16032,6 +14018,9 @@ static boolean DropElement(struct PlayerInfo *player) if (new_element == EL_UNDEFINED) return FALSE; + /* only set if player has anything that can be dropped */ + player->is_dropping_pressed = TRUE; + /* check if drop key was pressed long enough for EM style dynamite */ if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40) return FALSE; @@ -16107,28 +14096,13 @@ static boolean DropElement(struct PlayerInfo *player) if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) { -#if 0 - int move_direction; - int nextx, nexty; -#endif - if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) MovDir[dropx][dropy] = drop_direction; -#if 0 - move_direction = MovDir[dropx][dropy]; - nextx = dropx + GET_DX_FROM_DIR(move_direction); - nexty = dropy + GET_DY_FROM_DIR(move_direction); -#endif - ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ -#if USE_FIX_IMPACT_COLLISION /* do not cause impact style collision by dropping elements that can fall */ CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; -#else - CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; -#endif } player->drop_delay = GET_NEW_DROP_DELAY(drop_element); @@ -16429,10 +14403,6 @@ void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) int x = xx - offset; int y = yy - offset; -#if 0 - printf("::: %d -> %d\n", element_sp, action_sp); -#endif - PlayLevelSoundElementAction(x, y, element, action); } @@ -16440,13 +14410,9 @@ void RaiseScore(int value) { local_player->score += value; -#if 1 game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); -#else - DrawGameValue_Score(local_player->score); -#endif } void RaiseScoreElement(int element) @@ -16533,11 +14499,9 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) { if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED)) { -#if 1 /* closing door required in case of envelope style request dialogs */ if (!skip_request) CloseDoor(DOOR_CLOSE_1); -#endif #if defined(NETWORK_AVALIABLE) if (options.network) @@ -16546,37 +14510,11 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) #endif { if (quick_quit) - { -#if 1 - -#if 1 FadeSkipNextFadeIn(); -#else - fading = fading_none; -#endif - -#else - OpenDoor(DOOR_CLOSE_1); -#endif - - game_status = GAME_MODE_MAIN; - -#if 1 - DrawAndFadeInMainMenu(REDRAW_FIELD); -#else - DrawMainMenu(); -#endif - } - else - { -#if 0 - FadeOut(REDRAW_FIELD); -#endif - game_status = GAME_MODE_MAIN; + SetGameStatus(GAME_MODE_MAIN); - DrawAndFadeInMainMenu(REDRAW_FIELD); - } + DrawMainMenu(); } } else /* continue playing the game */ @@ -16609,18 +14547,7 @@ unsigned int InitEngineRandom_RND(int seed) { game.num_random_calls = 0; -#if 0 - unsigned int rnd_seed = InitEngineRandom(seed); - - printf("::: START RND: %d\n", rnd_seed); - - return rnd_seed; -#else - return InitEngineRandom(seed); - -#endif - } unsigned int RND(int max) @@ -16742,24 +14669,23 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshot() +void FreeEngineSnapshotSingle() { - FreeEngineSnapshotBuffers(); + FreeSnapshotSingle(); setString(&snapshot_level_identifier, NULL); snapshot_level_nr = -1; } -void SaveEngineSnapshot() +void FreeEngineSnapshotList() { - /* do not save snapshots from editor */ - if (level_editor_test_game) - return; + FreeSnapshotList(); +} - /* free previous snapshot buffers, if needed */ - FreeEngineSnapshotBuffers(); +ListNode *SaveEngineSnapshotBuffers() +{ + ListNode *buffers = NULL; -#if 1 /* copy some special values to a structure better suited for the snapshot */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) @@ -16767,100 +14693,82 @@ void SaveEngineSnapshot() if (level.game_engine_type == GAME_ENGINE_TYPE_EM) SaveEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - SaveEngineSnapshotValues_SP(); + SaveEngineSnapshotValues_SP(&buffers); /* save values stored in special snapshot structure */ if (level.game_engine_type == GAME_ENGINE_TYPE_RND) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); -#else - /* copy some special values to a structure better suited for the snapshot */ - - SaveEngineSnapshotValues_RND(); - SaveEngineSnapshotValues_EM(); - SaveEngineSnapshotValues_SP(); - - /* save values stored in special snapshot structure */ - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); -#endif + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); /* save further RND engine values */ - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(stored_player)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(game)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(tape)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ZY)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitX)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExitY)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(TapeTime)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Feld)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovPos)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDir)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(MovDelay)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangePage)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CustomValue)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Store2)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Back)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxElement)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxAction)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(GfxDir)); - - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_x)); - SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(scroll_y)); - - /* save level identification information */ - - setString(&snapshot_level_identifier, leveldir_current->identifier); - snapshot_level_nr = level_nr; + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(stored_player)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(game)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(tape)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZX)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZY)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitX)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitY)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeLeft)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTime)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovPos)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenGfxPos)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Feld)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovPos)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDir)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangePage)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CustomValue)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Store2)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(StorePlayer)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Back)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaNr)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustMoving)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(WasJustFalling)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckCollision)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(CheckImpact)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Stop)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Pushed)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeCount)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ChangeEvent)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodePhase)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeDelay)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExplodeField)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(RunnerVisit)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(PlayerVisit)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir)); + + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_x)); + SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(scroll_y)); #if 0 ListNode *node = engine_snapshot_list_rnd; @@ -16875,100 +14783,155 @@ void SaveEngineSnapshot() printf("::: size of engine snapshot: %d bytes\n", num_bytes); #endif + + return buffers; +} + +void SaveEngineSnapshotSingle() +{ + ListNode *buffers = SaveEngineSnapshotBuffers(); + + /* finally save all snapshot buffers to single snapshot */ + SaveSnapshotSingle(buffers); + + /* save level identification information */ + setString(&snapshot_level_identifier, leveldir_current->identifier); + snapshot_level_nr = level_nr; +} + +boolean CheckSaveEngineSnapshotToList() +{ + boolean save_snapshot = + ((game.snapshot.mode == SNAPSHOT_MODE_EVERY_STEP) || + (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE && + game.snapshot.changed_action) || + (game.snapshot.mode == SNAPSHOT_MODE_EVERY_COLLECT && + game.snapshot.collected_item)); + + game.snapshot.changed_action = FALSE; + game.snapshot.collected_item = FALSE; + game.snapshot.save_snapshot = save_snapshot; + + return save_snapshot; +} + +void SaveEngineSnapshotToList() +{ + if (game.snapshot.mode == SNAPSHOT_MODE_OFF || + tape.quick_resume) + return; + + ListNode *buffers = SaveEngineSnapshotBuffers(); + + /* finally save all snapshot buffers to snapshot list */ + SaveSnapshotToList(buffers); } -void LoadEngineSnapshot() +void SaveEngineSnapshotToListInitial() { - /* restore generically stored snapshot buffers */ + FreeEngineSnapshotList(); - LoadEngineSnapshotBuffers(); + SaveEngineSnapshotToList(); +} +void LoadEngineSnapshotValues() +{ /* restore special values from snapshot structure */ -#if 1 if (level.game_engine_type == GAME_ENGINE_TYPE_RND) LoadEngineSnapshotValues_RND(); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) LoadEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) LoadEngineSnapshotValues_SP(); -#else - LoadEngineSnapshotValues_RND(); - LoadEngineSnapshotValues_EM(); - LoadEngineSnapshotValues_SP(); -#endif +} -#if 0 - printf("::: %d, %d (LoadEngineSnapshot / 1)\n", scroll_x, scroll_y); -#endif +void LoadEngineSnapshotSingle() +{ + LoadSnapshotSingle(); -#if 0 - // needed if tile size was different when saving and loading engine snapshot - if (local_player->present) - { - scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : - local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : - local_player->jx - MIDPOSX); + LoadEngineSnapshotValues(); +} - scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : - local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : - local_player->jy - MIDPOSY); - } -#endif +void LoadEngineSnapshot_Undo(int steps) +{ + LoadSnapshotFromList_Older(steps); -#if 0 - printf("::: %d, %d (LoadEngineSnapshot / 1)\n", scroll_x, scroll_y); -#endif + LoadEngineSnapshotValues(); +} + +void LoadEngineSnapshot_Redo(int steps) +{ + LoadSnapshotFromList_Newer(steps); + + LoadEngineSnapshotValues(); } -boolean CheckEngineSnapshot() +boolean CheckEngineSnapshotSingle() { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } +boolean CheckEngineSnapshotList() +{ + return CheckSnapshotList(); +} + /* ---------- new game button stuff ---------------------------------------- */ static struct { int graphic; - struct Rect *pos; + struct XY *pos; int gadget_id; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = { { - IMG_GAME_BUTTON_GFX_STOP, &game.button.stop, + IMG_GFX_GAME_BUTTON_STOP, &game.button.stop, GAME_CTRL_ID_STOP, "stop game" }, { - IMG_GAME_BUTTON_GFX_PAUSE, &game.button.pause, + IMG_GFX_GAME_BUTTON_PAUSE, &game.button.pause, GAME_CTRL_ID_PAUSE, "pause game" }, { - IMG_GAME_BUTTON_GFX_PLAY, &game.button.play, + IMG_GFX_GAME_BUTTON_PLAY, &game.button.play, GAME_CTRL_ID_PLAY, "play game" }, { - IMG_GAME_BUTTON_GFX_SOUND_MUSIC, &game.button.sound_music, - SOUND_CTRL_ID_MUSIC, "background music on/off" + IMG_GFX_GAME_BUTTON_UNDO, &game.button.undo, + GAME_CTRL_ID_UNDO, "undo step" }, { - IMG_GAME_BUTTON_GFX_SOUND_LOOPS, &game.button.sound_loops, - SOUND_CTRL_ID_LOOPS, "sound loops on/off" + IMG_GFX_GAME_BUTTON_REDO, &game.button.redo, + GAME_CTRL_ID_REDO, "redo step" }, { - IMG_GAME_BUTTON_GFX_SOUND_SIMPLE, &game.button.sound_simple, - SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" + IMG_GFX_GAME_BUTTON_SAVE, &game.button.save, + GAME_CTRL_ID_SAVE, "save game" }, { - IMG_GAME_BUTTON_GFX_SAVE, &game.button.save, - GAME_CTRL_ID_SAVE, "save game" + IMG_GFX_GAME_BUTTON_PAUSE2, &game.button.pause2, + GAME_CTRL_ID_PAUSE2, "pause game" }, { - IMG_GAME_BUTTON_GFX_LOAD, &game.button.load, + IMG_GFX_GAME_BUTTON_LOAD, &game.button.load, GAME_CTRL_ID_LOAD, "load game" + }, + { + IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music, + SOUND_CTRL_ID_MUSIC, "background music on/off" + }, + { + IMG_GFX_GAME_BUTTON_SOUND_LOOPS, &game.button.sound_loops, + SOUND_CTRL_ID_LOOPS, "sound loops on/off" + }, + { + IMG_GFX_GAME_BUTTON_SOUND_SIMPLE, &game.button.sound_simple, + SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } }; @@ -16979,7 +14942,7 @@ void CreateGameButtons() for (i = 0; i < NUM_GAME_BUTTONS; i++) { struct GraphicInfo *gfx = &graphic_info[gamebutton_info[i].graphic]; - struct Rect *pos = gamebutton_info[i].pos; + struct XY *pos = gamebutton_info[i].pos; struct GadgetInfo *gi; int button_type; boolean checked; @@ -17004,7 +14967,6 @@ void CreateGameButtons() } if (id == GAME_CTRL_ID_STOP || - id == GAME_CTRL_ID_PAUSE || id == GAME_CTRL_ID_PLAY || id == GAME_CTRL_ID_SAVE || id == GAME_CTRL_ID_LOAD) @@ -17013,6 +14975,13 @@ void CreateGameButtons() checked = FALSE; event_mask = GD_EVENT_RELEASED; } + else if (id == GAME_CTRL_ID_UNDO || + id == GAME_CTRL_ID_REDO) + { + button_type = GD_TYPE_NORMAL_BUTTON; + checked = FALSE; + event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED; + } else { button_type = GD_TYPE_CHECK_BUTTON; @@ -17056,12 +15025,80 @@ void FreeGameButtons() FreeGadget(game_gadget[i]); } +static void UnmapGameButtonsAtSamePosition(int id) +{ + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + if (i != id && + gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && + gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) + UnmapGadget(game_gadget[i]); +} + +static void UnmapGameButtonsAtSamePosition_All() +{ + if (setup.show_snapshot_buttons) + { + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD); + } + else + { + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PLAY); + } +} + +static void MapGameButtonsAtSamePosition(int id) +{ + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + if (i != id && + gamebutton_info[i].pos->x == gamebutton_info[id].pos->x && + gamebutton_info[i].pos->y == gamebutton_info[id].pos->y) + MapGadget(game_gadget[i]); + + UnmapGameButtonsAtSamePosition_All(); +} + +void MapUndoRedoButtons() +{ + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); + + MapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + MapGadget(game_gadget[GAME_CTRL_ID_REDO]); + + ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, TRUE, GDI_END); +} + +void UnmapUndoRedoButtons() +{ + UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]); + UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]); + + MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); + MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); + + ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); +} + void MapGameButtons() { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) - MapGadget(game_gadget[i]); + if (i != GAME_CTRL_ID_UNDO && + i != GAME_CTRL_ID_REDO) + MapGadget(game_gadget[i]); + + UnmapGameButtonsAtSamePosition_All(); + + RedrawGameButtons(); } void UnmapGameButtons() @@ -17083,8 +15120,47 @@ void RedrawGameButtons() redraw_mask &= ~REDRAW_ALL; } -static void HandleGameButtonsExt(int id) +void GameUndoRedoExt() +{ + ClearPlayerAction(); + + tape.pausing = TRUE; + + RedrawPlayfield(); + UpdateAndDisplayGameControlValues(); + + DrawCompleteVideoDisplay(); + DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); + DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter); + DrawVideoDisplay(VIDEO_STATE_1STEP(tape.single_step), 0); + + BackToFront(); +} + +void GameUndo(int steps) +{ + if (!CheckEngineSnapshotList()) + return; + + LoadEngineSnapshot_Undo(steps); + + GameUndoRedoExt(); +} + +void GameRedo(int steps) +{ + if (!CheckEngineSnapshotList()) + return; + + LoadEngineSnapshot_Redo(steps); + + GameUndoRedoExt(); +} + +static void HandleGameButtonsExt(int id, int button) { + static boolean game_undo_executed = FALSE; + int steps = BUTTON_STEPSIZE(button); boolean handle_game_buttons = (game_status == GAME_MODE_PLAYING || (game_status == GAME_MODE_MAIN && tape.show_game_buttons)); @@ -17106,6 +15182,7 @@ static void HandleGameButtonsExt(int id) break; case GAME_CTRL_ID_PAUSE: + case GAME_CTRL_ID_PAUSE2: if (options.network && game_status == GAME_MODE_PLAYING) { #if defined(NETWORK_AVALIABLE) @@ -17117,6 +15194,9 @@ static void HandleGameButtonsExt(int id) } else TapeTogglePause(TAPE_TOGGLE_MANUAL); + + game_undo_executed = FALSE; + break; case GAME_CTRL_ID_PLAY: @@ -17131,13 +15211,37 @@ static void HandleGameButtonsExt(int id) SendToServer_ContinuePlaying(); else #endif - { - tape.pausing = FALSE; - DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0); - } + TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE); } break; + case GAME_CTRL_ID_UNDO: + // Important: When using "save snapshot when collecting an item" mode, + // load last (current) snapshot for first "undo" after pressing "pause" + // (else the last-but-one snapshot would be loaded, because the snapshot + // pointer already points to the last snapshot when pressing "pause", + // which is fine for "every step/move" mode, but not for "every collect") + if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_COLLECT && + !game_undo_executed) + steps--; + + game_undo_executed = TRUE; + + GameUndo(steps); + break; + + case GAME_CTRL_ID_REDO: + GameRedo(steps); + break; + + case GAME_CTRL_ID_SAVE: + TapeQuickSave(); + break; + + case GAME_CTRL_ID_LOAD: + TapeQuickLoad(); + break; + case SOUND_CTRL_ID_MUSIC: if (setup.sound_music) { @@ -17177,14 +15281,6 @@ static void HandleGameButtonsExt(int id) } break; - case GAME_CTRL_ID_SAVE: - TapeQuickSave(); - break; - - case GAME_CTRL_ID_LOAD: - TapeQuickLoad(); - break; - default: break; } @@ -17192,24 +15288,16 @@ static void HandleGameButtonsExt(int id) static void HandleGameButtons(struct GadgetInfo *gi) { - HandleGameButtonsExt(gi->custom_id); + HandleGameButtonsExt(gi->custom_id, gi->event.button); } void HandleSoundButtonKeys(Key key) { -#if 1 + if (key == setup.shortcut.sound_simple) ClickOnGadget(game_gadget[SOUND_CTRL_ID_SIMPLE], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_loops) ClickOnGadget(game_gadget[SOUND_CTRL_ID_LOOPS], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_music) ClickOnGadget(game_gadget[SOUND_CTRL_ID_MUSIC], MB_LEFTBUTTON); -#else - if (key == setup.shortcut.sound_simple) - HandleGameButtonsExt(SOUND_CTRL_ID_SIMPLE); - else if (key == setup.shortcut.sound_loops) - HandleGameButtonsExt(SOUND_CTRL_ID_LOOPS); - else if (key == setup.shortcut.sound_music) - HandleGameButtonsExt(SOUND_CTRL_ID_MUSIC); -#endif }