X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=17981be5ad1d002cd3d615a05896e6b5dc109c00;hb=04cfb5daeff6cbceef152fc01ad5852407c0c918;hp=843956362443cfc5e95da1e4f338e71620ef54cd;hpb=80a9825ee7983ea810b89f4e827efc85e01b69bc;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 84395636..17981be5 100644 --- a/src/game.c +++ b/src/game.c @@ -59,6 +59,8 @@ #define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) #define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1) + /* for DigField() */ #define DF_NO_PUSH 0 @@ -85,27 +87,39 @@ #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) +#if 1 +#define PANEL_OFF() (local_player->LevelSolved_PanelOff) +#define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) +#define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p)) +#define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p)) +#else #define PANEL_DEACTIVATED(p) ((p).x < 0 || (p).y < 0) +#define PANEL_XPOS(p) (ALIGNED_XPOS((p).x, (p).width, (p).align)) +#define PANEL_YPOS(p) ((p).y) +#endif /* special positions in the game control window (relative to control window) */ -#define XX_LEVEL1 (game.panel.level.x) -#define XX_LEVEL2 (game.panel.level.x - 1) -#define YY_LEVEL (game.panel.level.y) -#define XX_EMERALDS (game.panel.gems.x) -#define YY_EMERALDS (game.panel.gems.y) -#define XX_DYNAMITE (game.panel.inventory.x) -#define YY_DYNAMITE (game.panel.inventory.y) -#define XX_KEYS (game.panel.keys.x) -#define YY_KEYS (game.panel.keys.y) -#define XX_SCORE (game.panel.score.x) -#define YY_SCORE (game.panel.score.y) -#define XX_TIME1 (game.panel.time.x) -#define XX_TIME2 (game.panel.time.x + 1) -#define YY_TIME (game.panel.time.y) +#define XX_LEVEL1 (PANEL_XPOS(game.panel.level)) +#define XX_LEVEL2 (PANEL_XPOS(game.panel.level) - 1) +#define XX_LEVEL (PANEL_XPOS(game.panel.level)) +#define YY_LEVEL (PANEL_YPOS(game.panel.level)) +#define XX_EMERALDS (PANEL_XPOS(game.panel.gems)) +#define YY_EMERALDS (PANEL_YPOS(game.panel.gems)) +#define XX_DYNAMITE (PANEL_XPOS(game.panel.inventory)) +#define YY_DYNAMITE (PANEL_YPOS(game.panel.inventory)) +#define XX_KEYS (PANEL_XPOS(game.panel.keys)) +#define YY_KEYS (PANEL_YPOS(game.panel.keys)) +#define XX_SCORE (PANEL_XPOS(game.panel.score)) +#define YY_SCORE (PANEL_YPOS(game.panel.score)) +#define XX_TIME1 (PANEL_XPOS(game.panel.time)) +#define XX_TIME2 (PANEL_XPOS(game.panel.time) + 1) +#define XX_TIME (PANEL_XPOS(game.panel.time)) +#define YY_TIME (PANEL_YPOS(game.panel.time)) /* special positions in the game control window (relative to main window) */ #define DX_LEVEL1 (DX + XX_LEVEL1) #define DX_LEVEL2 (DX + XX_LEVEL2) +#define DX_LEVEL (DX + XX_LEVEL) #define DY_LEVEL (DY + YY_LEVEL) #define DX_EMERALDS (DX + XX_EMERALDS) #define DY_EMERALDS (DY + YY_EMERALDS) @@ -117,8 +131,459 @@ #define DY_SCORE (DY + YY_SCORE) #define DX_TIME1 (DX + XX_TIME1) #define DX_TIME2 (DX + XX_TIME2) +#define DX_TIME (DX + XX_TIME) #define DY_TIME (DY + YY_TIME) +#if 0 +/* game panel display and control definitions */ + +#define GAME_CONTROL_LEVEL 0 +#define GAME_CONTROL_GEMS 1 +#define GAME_CONTROL_INVENTORY 2 +#define GAME_CONTROL_KEY_1 3 +#define GAME_CONTROL_KEY_2 4 +#define GAME_CONTROL_KEY_3 5 +#define GAME_CONTROL_KEY_4 6 +#define GAME_CONTROL_KEY_5 7 +#define GAME_CONTROL_KEY_6 8 +#define GAME_CONTROL_KEY_7 9 +#define GAME_CONTROL_KEY_8 10 +#define GAME_CONTROL_KEY_WHITE 11 +#define GAME_CONTROL_KEY_WHITE_COUNT 12 +#define GAME_CONTROL_SCORE 13 +#define GAME_CONTROL_TIME 14 +#define GAME_CONTROL_TIME_HH 15 +#define GAME_CONTROL_TIME_MM 16 +#define GAME_CONTROL_TIME_SS 17 +#define GAME_CONTROL_DROP_NEXT_1 18 +#define GAME_CONTROL_DROP_NEXT_2 19 +#define GAME_CONTROL_DROP_NEXT_3 20 +#define GAME_CONTROL_DROP_NEXT_4 21 +#define GAME_CONTROL_DROP_NEXT_5 22 +#define GAME_CONTROL_DROP_NEXT_6 23 +#define GAME_CONTROL_DROP_NEXT_7 24 +#define GAME_CONTROL_DROP_NEXT_8 25 +#define GAME_CONTROL_SHIELD_NORMAL 26 +#define GAME_CONTROL_SHIELD_NORMAL_TIME 27 +#define GAME_CONTROL_SHIELD_DEADLY 28 +#define GAME_CONTROL_SHIELD_DEADLY_TIME 29 +#define GAME_CONTROL_EXIT 30 +#define GAME_CONTROL_EM_EXIT 31 +#define GAME_CONTROL_SP_EXIT 32 +#define GAME_CONTROL_STEEL_EXIT 33 +#define GAME_CONTROL_EM_STEEL_EXIT 34 +#define GAME_CONTROL_EMC_MAGIC_BALL 35 +#define GAME_CONTROL_EMC_MAGIC_BALL_TIME 36 +#define GAME_CONTROL_LIGHT_SWITCH 37 +#define GAME_CONTROL_LIGHT_SWITCH_TIME 38 +#define GAME_CONTROL_TIMEGATE_SWITCH 39 +#define GAME_CONTROL_TIMEGATE_SWITCH_TIME 40 +#define GAME_CONTROL_SWITCHGATE_SWITCH 41 +#define GAME_CONTROL_EMC_LENSES 42 +#define GAME_CONTROL_EMC_LENSES_TIME 43 +#define GAME_CONTROL_EMC_MAGNIFIER 44 +#define GAME_CONTROL_EMC_MAGNIFIER_TIME 45 +#define GAME_CONTROL_BALLOON_SWITCH 46 +#define GAME_CONTROL_DYNABOMB_NUMBER 47 +#define GAME_CONTROL_DYNABOMB_SIZE 48 +#define GAME_CONTROL_DYNABOMB_POWER 49 +#define GAME_CONTROL_PENGUINS 50 +#define GAME_CONTROL_SOKOBAN_OBJECTS 51 +#define GAME_CONTROL_SOKOBAN_FIELDS 52 +#define GAME_CONTROL_ROBOT_WHEEL 53 +#define GAME_CONTROL_CONVEYOR_BELT_1 54 +#define GAME_CONTROL_CONVEYOR_BELT_1_SWITCH 55 +#define GAME_CONTROL_CONVEYOR_BELT_2 56 +#define GAME_CONTROL_CONVEYOR_BELT_2_SWITCH 57 +#define GAME_CONTROL_CONVEYOR_BELT_3 58 +#define GAME_CONTROL_CONVEYOR_BELT_3_SWITCH 59 +#define GAME_CONTROL_CONVEYOR_BELT_4 60 +#define GAME_CONTROL_CONVEYOR_BELT_4_SWITCH 61 +#define GAME_CONTROL_MAGIC_WALL 62 +#define GAME_CONTROL_MAGIC_WALL_TIME 63 +#define GAME_CONTROL_BD_MAGIC_WALL 64 +#define GAME_CONTROL_DC_MAGIC_WALL 65 +#define GAME_CONTROL_PLAYER_NAME 66 +#define GAME_CONTROL_LEVEL_NAME 67 +#define GAME_CONTROL_LEVEL_AUTHOR 68 + +struct GameControlInfo +{ + int nr; + + struct TextPosInfo *pos_text; + int type; + void *ptr; +}; + +static struct GameControlInfo game_controls[] = +{ + { + GAME_CONTROL_LEVEL, + &game.panel.level, + TYPE_INTEGER, + }, + { + GAME_CONTROL_GEMS, + &game.panel.gems, + TYPE_INTEGER, + }, + { + GAME_CONTROL_INVENTORY, + &game.panel.inventory, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEYS, + &game.panel.keys, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SCORE, + &game.panel.score, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIME, + &game.panel.time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIME_HH, + &game.panel.time_hh, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIME_MM, + &game.panel.time_mm, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIME_SS, + &game.panel.time_ss, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_1, + &game.panel.drop_next_1, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_2, + &game.panel.drop_next_2, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_3, + &game.panel.drop_next_3, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_4, + &game.panel.drop_next_4, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_5, + &game.panel.drop_next_5, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_6, + &game.panel.drop_next_6, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_7, + &game.panel.drop_next_7, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DROP_NEXT_8, + &game.panel.drop_next_8, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_KEYS, + &game.panel.emc_keys, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_1, + &game.panel.key_1, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_2, + &game.panel.key_2, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_3, + &game.panel.key_3, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_4, + &game.panel.key_4, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_5, + &game.panel.key_5, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_6, + &game.panel.key_6, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_7, + &game.panel.key_7, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_8, + &game.panel.key_8, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_WHITE, + &game.panel.key_white, + TYPE_INTEGER, + }, + { + GAME_CONTROL_KEY_WHITE_COUNT, + &game.panel.key_white_count, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SHIELD_NORMAL, + &game.panel.shield_normal, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SHIELD_NORMAL_TIME, + &game.panel.shield_normal_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SHIELD_DEADLY, + &game.panel.shield_deadly, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SHIELD_DEADLY_TIME, + &game.panel.shield_deadly_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EXIT, + &game.panel.exit, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EM_EXIT, + &game.panel.em_exit, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SP_EXIT, + &game.panel.sp_exit, + TYPE_INTEGER, + }, + { + GAME_CONTROL_STEEL_EXIT, + &game.panel.steel_exit, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EM_STEEL_EXIT, + &game.panel.em_steel_exit, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_MAGIC_BALL, + &game.panel.emc_magic_ball, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_MAGIC_BALL_TIME, + &game.panel.emc_magic_ball_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_LIGHT_SWITCH, + &game.panel.light_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_LIGHT_SWITCH_TIME, + &game.panel.light_switch_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIMEGATE_SWITCH, + &game.panel.timegate_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_TIMEGATE_SWITCH_TIME, + &game.panel.timegate_switch_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SWITCHGATE_SWITCH, + &game.panel.switchgate_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_LENSES, + &game.panel.emc_lenses, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_LENSES_TIME, + &game.panel.emc_lenses_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_MAGNIFIER, + &game.panel.emc_magnifier, + TYPE_INTEGER, + }, + { + GAME_CONTROL_EMC_MAGNIFIER_TIME, + &game.panel.emc_magnifier_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_BALLOON_SWITCH, + &game.panel.balloon_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DYNABOMB_NUMBER, + &game.panel.dynabomb_number, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DYNABOMB_SIZE, + &game.panel.dynabomb_size, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DYNABOMB_POWER, + &game.panel.dynabomb_power, + TYPE_INTEGER, + }, + { + GAME_CONTROL_PENGUINS, + &game.panel.penguins, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SOKOBAN_OBJECTS, + &game.panel.sokoban_objects, + TYPE_INTEGER, + }, + { + GAME_CONTROL_SOKOBAN_FIELDS, + &game.panel.sokoban_fields, + TYPE_INTEGER, + }, + { + GAME_CONTROL_ROBOT_WHEEL, + &game.panel.robot_wheel, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_1, + &game.panel.conveyor_belt_1, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_1_SWITCH, + &game.panel.conveyor_belt_1_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_2, + &game.panel.conveyor_belt_2, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_2_SWITCH, + &game.panel.conveyor_belt_2_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_3, + &game.panel.conveyor_belt_3, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_3_SWITCH, + &game.panel.conveyor_belt_3_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_4, + &game.panel.conveyor_belt_4, + TYPE_INTEGER, + }, + { + GAME_CONTROL_CONVEYOR_BELT_4_SWITCH, + &game.panel.conveyor_belt_4_switch, + TYPE_INTEGER, + }, + { + GAME_CONTROL_MAGIC_WALL, + &game.panel.magic_wall, + TYPE_INTEGER, + }, + { + GAME_CONTROL_MAGIC_WALL_TIME, + &game.panel.magic_wall_time, + TYPE_INTEGER, + }, + { + GAME_CONTROL_BD_MAGIC_WALL, + &game.panel.bd_magic_wall, + TYPE_INTEGER, + }, + { + GAME_CONTROL_DC_MAGIC_WALL, + &game.panel.dc_magic_wall, + TYPE_INTEGER, + }, + { + GAME_CONTROL_PLAYER_NAME, + &game.panel.player_name, + TYPE_INTEGER, + }, + { + GAME_CONTROL_LEVEL_NAME, + &game.panel.level_name, + TYPE_INTEGER, + }, + { + GAME_CONTROL_LEVEL_AUTHOR, + &game.panel.level_author, + TYPE_INTEGER, + }, + + { + -1, + NULL, + -1, + NULL + } +}; +#endif + + /* values for delayed check of falling and moving elements and for collision */ #define CHECK_DELAY_MOVING 3 #define CHECK_DELAY_FALLING CHECK_DELAY_MOVING @@ -245,7 +710,9 @@ #define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN || \ + Feld[x][y] == EL_EM_EXIT_OPEN || \ Feld[x][y] == EL_STEEL_EXIT_OPEN || \ + Feld[x][y] == EL_EM_STEEL_EXIT_OPEN || \ IS_FOOD_PENGUIN(Feld[x][y]))) #define DRAGON_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) @@ -381,8 +848,8 @@ static int getInvisibleFromInvisibleActiveElement(int); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; /* for detection of endless loops, caused by custom element programming */ -/* (using "MAX_PLAYFIELD_WIDTH" here is just a rough approximation...) */ -#define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH) +/* (using maximal playfield width x 10 is just a rough approximation) */ +#define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH * 10) #define RECURSION_LOOP_DETECTION_START(e, rc) \ { \ @@ -491,6 +958,46 @@ static struct ChangingElementInfo change_delay_list[] = NULL, NULL }, + { + EL_EM_EXIT_OPENING, + EL_EM_EXIT_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_EM_EXIT_CLOSING, +#if 1 + EL_EMPTY, +#else + EL_EM_EXIT_CLOSED, +#endif + 29, + NULL, + NULL, + NULL + }, + { + EL_EM_STEEL_EXIT_OPENING, + EL_EM_STEEL_EXIT_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_EM_STEEL_EXIT_CLOSING, +#if 1 + EL_STEELWALL, +#else + EL_EM_STEEL_EXIT_CLOSED, +#endif + 29, + NULL, + NULL, + NULL + }, { EL_SP_EXIT_OPENING, EL_SP_EXIT_OPEN, @@ -692,10 +1199,14 @@ move_stepsize_list[] = { EL_AMOEBA_DROPPING, 2 }, { EL_QUICKSAND_FILLING, 1 }, { EL_QUICKSAND_EMPTYING, 1 }, + { EL_QUICKSAND_FAST_FILLING, 2 }, + { EL_QUICKSAND_FAST_EMPTYING, 2 }, { EL_MAGIC_WALL_FILLING, 2 }, - { EL_BD_MAGIC_WALL_FILLING, 2 }, { EL_MAGIC_WALL_EMPTYING, 2 }, + { EL_BD_MAGIC_WALL_FILLING, 2 }, { EL_BD_MAGIC_WALL_EMPTYING, 2 }, + { EL_DC_MAGIC_WALL_FILLING, 2 }, + { EL_DC_MAGIC_WALL_EMPTYING, 2 }, { EL_UNDEFINED, 0 }, }; @@ -782,7 +1293,7 @@ static int playfield_scan_delta_y = 1; (y) += playfield_scan_delta_y) \ for ((x) = playfield_scan_start_x; \ (x) >= 0 && (x) <= lev_fieldx - 1; \ - (x) += playfield_scan_delta_x) \ + (x) += playfield_scan_delta_x) #ifdef DEBUG void DEBUG_SetMaximumDynamite() @@ -861,6 +1372,8 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, void GetPlayerConfig() { + GameFrameDelay = setup.game_frame_delay; + if (!audio.sound_available) setup.sound_simple = FALSE; @@ -879,58 +1392,7 @@ void GetPlayerConfig() InitJoysticks(); } -static int getBeltNrFromBeltElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3); -} - -static int getBeltNrFromBeltActiveElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3); -} - -static int getBeltNrFromBeltSwitchElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3); -} - -static int getBeltDirNrFromBeltSwitchElement(int element) -{ - static int belt_base_element[4] = - { - EL_CONVEYOR_BELT_1_SWITCH_LEFT, - EL_CONVEYOR_BELT_2_SWITCH_LEFT, - EL_CONVEYOR_BELT_3_SWITCH_LEFT, - EL_CONVEYOR_BELT_4_SWITCH_LEFT - }; - - int belt_nr = getBeltNrFromBeltSwitchElement(element); - int belt_dir_nr = element - belt_base_element[belt_nr]; - - return (belt_dir_nr % 3); -} - -static int getBeltDirFromBeltSwitchElement(int element) -{ - static int belt_move_dir[3] = - { - MV_LEFT, - MV_NONE, - MV_RIGHT - }; - - int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element); - - return belt_move_dir[belt_dir_nr]; -} - -static int get_element_from_group_element(int element) +int GetElementFromGroupElement(int element) { if (IS_GROUP_ELEMENT(element)) { @@ -1228,7 +1690,7 @@ static void InitField(int x, int y, boolean init_game) } else if (IS_GROUP_ELEMENT(element)) { - Feld[x][y] = get_element_from_group_element(element); + Feld[x][y] = GetElementFromGroupElement(element); InitField(x, y, init_game); } @@ -1271,65 +1733,284 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) */ } -inline void DrawGameValue_Emeralds(int value) +#if 1 + +void DrawGameValue_Emeralds(int value) { - int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + struct TextPosInfo *pos = &game.panel.gems; +#if 1 + int font_nr = pos->font; +#else + int font_nr = FONT_TEXT_2; +#endif + int font_width = getFontWidth(font_nr); + int chars = pos->chars; - if (PANEL_DEACTIVATED(game.panel.gems)) + if (PANEL_DEACTIVATED(pos)) return; - DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2); + pos->width = chars * font_width; + + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } -inline void DrawGameValue_Dynamite(int value) +void DrawGameValue_Dynamite(int value) { - int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + struct TextPosInfo *pos = &game.panel.inventory; +#if 1 + int font_nr = pos->font; +#else + int font_nr = FONT_TEXT_2; +#endif + int font_width = getFontWidth(font_nr); + int chars = pos->chars; - if (PANEL_DEACTIVATED(game.panel.inventory)) + 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; +#if 1 + int font_nr = pos->font; +#else + int font_nr = FONT_TEXT_2; +#endif + int font_width = getFontWidth(font_nr); + int chars = pos->chars; + + 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->chars; +#if 1 + int font1_nr = pos->font; + int font2_nr = pos->font_alt; +#else + int font1_nr = FONT_TEXT_2; + int font2_nr = FONT_TEXT_1; +#endif + int font_nr = font1_nr; + boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); + + if (PANEL_DEACTIVATED(pos)) return; - DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2); + 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->chars; +#if 1 + int font1_nr = pos->font; + int font2_nr = pos->font_alt; +#else + int font1_nr = FONT_TEXT_2; + int font2_nr = FONT_TEXT_1; +#endif + int font_nr = font1_nr; + boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); + + 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); } -inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) +void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) { +#if 0 + struct TextPosInfo *pos = &game.panel.keys; +#endif +#if 0 int base_key_graphic = EL_KEY_1; +#endif int i; - if (PANEL_DEACTIVATED(game.panel.keys)) +#if 0 + if (PANEL_DEACTIVATED(pos)) return; +#endif +#if 0 if (level.game_engine_type == GAME_ENGINE_TYPE_EM) base_key_graphic = EL_EM_KEY_1; +#endif +#if 0 + pos->width = 4 * MINI_TILEX; +#endif + +#if 1 + for (i = 0; i < MAX_NUM_KEYS; i++) +#else /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) +#endif { - int x = XX_KEYS + i * MINI_TILEX; - int y = YY_KEYS; +#if 1 + struct TextPosInfo *pos = &game.panel.key[i]; +#endif + int src_x = DOOR_GFX_PAGEX5 + 18; + int src_y = DOOR_GFX_PAGEY1 + 123; +#if 1 + int dst_x = PANEL_XPOS(pos); + int dst_y = PANEL_YPOS(pos); +#else + int dst_x = PANEL_XPOS(pos) + i * MINI_TILEX; + int dst_y = PANEL_YPOS(pos); +#endif + +#if 1 + 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); +#endif + +#if 1 + if (PANEL_DEACTIVATED(pos)) + continue; +#endif + +#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]) - DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); + { +#if 0 + int graphic = el2edimg(base_key_graphic + i); +#endif + 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 1 + if (key[i]) + DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, + MINI_TILEX, MINI_TILEY, dst_x, dst_y); +#else + if (key[i]) + DrawMiniGraphicExt(drawto, dst_x, dst_y, el2edimg(base_key_graphic + i)); + else + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, + MINI_TILEX, MINI_TILEY, dst_x, dst_y); +#endif +#endif } } -inline void DrawGameValue_Score(int value) +#else + +void DrawGameValue_Emeralds(int value) +{ + int font_nr = FONT_TEXT_2; + int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; + + if (PANEL_DEACTIVATED(game.panel.gems)) + return; + + DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), font_nr); +} + +void DrawGameValue_Dynamite(int value) { - int xpos = (5 * 14 - 5 * getFontWidth(FONT_TEXT_2)) / 2; + int font_nr = FONT_TEXT_2; + int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; + + if (PANEL_DEACTIVATED(game.panel.inventory)) + return; + + DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); +} + +void DrawGameValue_Score(int value) +{ + int font_nr = FONT_TEXT_2; + int xpos = (5 * 14 - 5 * getFontWidth(font_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.score)) return; - DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), FONT_TEXT_2); + DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), font_nr); } -inline void DrawGameValue_Time(int value) +void DrawGameValue_Time(int value) { - int xpos3 = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; - int xpos4 = (4 * 10 - 4 * getFontWidth(FONT_LEVEL_NUMBER)) / 2; + int font1_nr = FONT_TEXT_2; +#if 1 + int font2_nr = FONT_TEXT_1; +#else + int font2_nr = FONT_LEVEL_NUMBER; +#endif + int xpos3 = (3 * 14 - 3 * getFontWidth(font1_nr)) / 2; + int xpos4 = (4 * 10 - 4 * getFontWidth(font2_nr)) / 2; if (PANEL_DEACTIVATED(game.panel.time)) return; @@ -1339,22 +2020,56 @@ inline void DrawGameValue_Time(int value) ClearRectangleOnBackground(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); if (value < 1000) - DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), FONT_TEXT_2); + DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), font1_nr); else - DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER); + DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), font2_nr); } -inline void DrawGameValue_Level(int value) +void DrawGameValue_Level(int value) { + int font1_nr = FONT_TEXT_2; +#if 1 + int font2_nr = FONT_TEXT_1; +#else + int font2_nr = FONT_LEVEL_NUMBER; +#endif + if (PANEL_DEACTIVATED(game.panel.level)) return; if (level_nr < 100) - DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), FONT_TEXT_2); + DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), font1_nr); else - DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), FONT_LEVEL_NUMBER); + DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), font2_nr); +} + +void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) +{ + int base_key_graphic = EL_KEY_1; + int i; + + if (PANEL_DEACTIVATED(game.panel.keys)) + return; + + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + base_key_graphic = EL_EM_KEY_1; + + /* currently only 4 of 8 possible keys are displayed */ + for (i = 0; i < STD_NUM_KEYS; i++) + { + int x = XX_KEYS + i * MINI_TILEX; + int y = YY_KEYS; + + if (key[i]) + DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); + else + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, + DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); + } } +#endif + void DrawAllGameValues(int emeralds, int dynamite, int score, int time, int key_bits) { @@ -1924,6 +2639,8 @@ void InitGame() for (j = 0; j < MAX_NUM_KEYS; j++) player->key[j] = FALSE; + player->num_white_keys = 0; + player->dynabomb_count = 0; player->dynabomb_size = 1; player->dynabombs_left = 0; @@ -2016,7 +2733,9 @@ void InitGame() player->LevelSolved = FALSE; player->GameOver = FALSE; + player->LevelSolved_GameWon = FALSE; player->LevelSolved_GameEnd = FALSE; + player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; } @@ -2748,10 +3467,12 @@ void GameWon() { static int time, time_final; static int score, score_final; - static int game_over_delay = 0; - int game_over_delay_value = 50; + static int game_over_delay_1 = 0; + static int game_over_delay_2 = 0; + int game_over_delay_value_1 = 50; + int game_over_delay_value_2 = 50; - if (!local_player->LevelSolved_GameEnd) + if (!local_player->LevelSolved_GameWon) { int i; @@ -2759,7 +3480,7 @@ void GameWon() if (local_player->MovPos) return; - local_player->LevelSolved_GameEnd = TRUE; + local_player->LevelSolved_GameWon = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; @@ -2770,7 +3491,8 @@ void GameWon() TapeStop(); #endif - game_over_delay = game_over_delay_value; + game_over_delay_1 = game_over_delay_value_1; + game_over_delay_2 = game_over_delay_value_2; time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; @@ -2802,18 +3524,33 @@ void GameWon() if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */ { /* close exit door after last player */ - if (AllPlayersGone && - (Feld[ExitX][ExitY] == EL_EXIT_OPEN || - Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || - Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) + if ((AllPlayersGone && + (Feld[ExitX][ExitY] == EL_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) || + Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN) { int element = Feld[ExitX][ExitY]; - Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : - element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: - EL_STEEL_EXIT_CLOSING); - - PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); +#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); + } } /* player disappears */ @@ -2837,9 +3574,9 @@ void GameWon() PlaySound(SND_GAME_WINNING); } - if (game_over_delay > 0) + if (game_over_delay_1 > 0) { - game_over_delay--; + game_over_delay_1--; return; } @@ -2862,7 +3599,22 @@ void GameWon() PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); + + return; } + + local_player->LevelSolved_PanelOff = TRUE; + + if (game_over_delay_2 > 0) + { + game_over_delay_2--; + + return; + } + +#if 1 + GameEnd(); +#endif } void GameEnd() @@ -2870,6 +3622,8 @@ void GameEnd() int hi_pos; boolean raise_level = FALSE; + local_player->LevelSolved_GameEnd = TRUE; + CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) @@ -3096,7 +3850,12 @@ void InitMovingField(int x, int y, int direction) /* 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 @@ -3280,8 +4039,10 @@ void RemoveMovingField(int x, int y) if (element == EL_BLOCKED && (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING || + Feld[oldx][oldy] == EL_QUICKSAND_FAST_EMPTYING || Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING || + Feld[oldx][oldy] == EL_DC_MAGIC_WALL_EMPTYING || Feld[oldx][oldy] == EL_AMOEBA_DROPPING)) next_element = get_next_element(Feld[oldx][oldy]); @@ -4044,6 +4805,10 @@ 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; @@ -4556,6 +5321,16 @@ void Impact(int x, int y) object_hit = TRUE; } + + if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTYING && object_hit == FALSE) + { + RemoveMovingField(x, y + 1); + Feld[x][y + 1] = EL_QUICKSAND_FAST_EMPTY; + Feld[x][y + 2] = EL_ROCK; + DrawLevelField(x, y + 2); + + object_hit = TRUE; + } #endif if (object_hit) @@ -4584,7 +5359,8 @@ void Impact(int x, int y) Bang(x, y); return; } - else if (impact && element == EL_PEARL) + else if (impact && element == EL_PEARL && + smashed != EL_DC_MAGIC_WALL && smashed != EL_DC_MAGIC_WALL_ACTIVE) { ResetGfxAnimation(x, y); @@ -4617,26 +5393,33 @@ void Impact(int x, int y) if (object_hit) /* check which object was hit */ { - if (CAN_PASS_MAGIC_WALL(element) && - (smashed == EL_MAGIC_WALL || - smashed == EL_BD_MAGIC_WALL)) + if ((CAN_PASS_MAGIC_WALL(element) && + (smashed == EL_MAGIC_WALL || + smashed == EL_BD_MAGIC_WALL)) || + (CAN_PASS_DC_MAGIC_WALL(element) && + smashed == EL_DC_MAGIC_WALL)) { int xx, yy; int activated_magic_wall = (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE : - EL_BD_MAGIC_WALL_ACTIVE); + smashed == EL_BD_MAGIC_WALL ? EL_BD_MAGIC_WALL_ACTIVE : + EL_DC_MAGIC_WALL_ACTIVE); /* activate magic wall / mill */ SCAN_PLAYFIELD(xx, yy) + { if (Feld[xx][yy] == smashed) Feld[xx][yy] = activated_magic_wall; + } game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND; game.magic_wall_active = TRUE; PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ? SND_MAGIC_WALL_ACTIVATING : - SND_BD_MAGIC_WALL_ACTIVATING)); + smashed == EL_BD_MAGIC_WALL ? + SND_BD_MAGIC_WALL_ACTIVATING : + SND_DC_MAGIC_WALL_ACTIVATING)); } if (IS_PLAYER(x, y + 1)) @@ -4751,12 +5534,15 @@ void Impact(int x, int y) /* play sound of magic wall / mill */ if (!last_line && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || - Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) + Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE || + Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)) { if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING); else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING); + else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) + PlayLevelSound(x, y, SND_DC_MAGIC_WALL_FILLING); return; } @@ -5114,7 +5900,9 @@ inline static void TurnRoundExt(int x, int y) int ey = y + xy[i][1]; if (IN_LEV_FIELD(ex, ey) && (Feld[ex][ey] == EL_EXIT_OPEN || - Feld[ex][ey] == EL_STEEL_EXIT_OPEN)) + Feld[ex][ey] == EL_EM_EXIT_OPEN || + Feld[ex][ey] == EL_STEEL_EXIT_OPEN || + Feld[ex][ey] == EL_EM_STEEL_EXIT_OPEN)) { attr_x = ex; attr_y = ey; @@ -5671,6 +6459,43 @@ void StartMoving(int x, int y) PlayLevelSoundAction(x, y, ACTION_FILLING); } } + else if (element == EL_QUICKSAND_FAST_FULL) + { + if (IS_FREE(x, y + 1)) + { + InitMovingField(x, y, MV_DOWN); + started_moving = TRUE; + + Feld[x][y] = EL_QUICKSAND_FAST_EMPTYING; +#if USE_QUICKSAND_BD_ROCK_BUGFIX + if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK) + Store[x][y] = EL_ROCK; +#else + Store[x][y] = EL_ROCK; +#endif + + PlayLevelSoundAction(x, y, ACTION_EMPTYING); + } + else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) + { + if (!MovDelay[x][y]) + MovDelay[x][y] = TILEY + 1; + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + } + + Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; + Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL; + Store[x][y + 1] = Store[x][y]; + Store[x][y] = 0; + + PlayLevelSoundAction(x, y, ACTION_FILLING); + } + } else if ((element == EL_ROCK || element == EL_BD_ROCK) && Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { @@ -5682,6 +6507,17 @@ void StartMoving(int x, int y) PlayLevelSoundAction(x, y, ACTION_FILLING); } + else if ((element == EL_ROCK || element == EL_BD_ROCK) && + Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) + { + InitMovingField(x, y, MV_DOWN); + started_moving = TRUE; + + Feld[x][y] = EL_QUICKSAND_FAST_FILLING; + Store[x][y] = element; + + PlayLevelSoundAction(x, y, ACTION_FILLING); + } else if (element == EL_MAGIC_WALL_FULL) { if (IS_FREE(x, y + 1)) @@ -5718,7 +6554,7 @@ void StartMoving(int x, int y) started_moving = TRUE; Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING; - Store[x][y] = EL_CHANGED2(Store[x][y]); + Store[x][y] = EL_CHANGED_BD(Store[x][y]); } else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) { @@ -5734,20 +6570,52 @@ void StartMoving(int x, int y) Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE; Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL; - Store[x][y + 1] = EL_CHANGED2(Store[x][y]); + Store[x][y + 1] = EL_CHANGED_BD(Store[x][y]); Store[x][y] = 0; } } - else if (CAN_PASS_MAGIC_WALL(element) && - (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || - Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) + else if (element == EL_DC_MAGIC_WALL_FULL) + { + if (IS_FREE(x, y + 1)) + { + InitMovingField(x, y, MV_DOWN); + started_moving = TRUE; + + Feld[x][y] = EL_DC_MAGIC_WALL_EMPTYING; + Store[x][y] = EL_CHANGED_DC(Store[x][y]); + } + else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) + { + if (!MovDelay[x][y]) + MovDelay[x][y] = TILEY/4 + 1; + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + } + + Feld[x][y] = EL_DC_MAGIC_WALL_ACTIVE; + Feld[x][y + 1] = EL_DC_MAGIC_WALL_FULL; + Store[x][y + 1] = EL_CHANGED_DC(Store[x][y]); + Store[x][y] = 0; + } + } + else if ((CAN_PASS_MAGIC_WALL(element) && + (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || + Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) || + (CAN_PASS_DC_MAGIC_WALL(element) && + (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE))) + { InitMovingField(x, y, MV_DOWN); started_moving = TRUE; Feld[x][y] = (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING : - EL_BD_MAGIC_WALL_FILLING); + Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ? EL_BD_MAGIC_WALL_FILLING : + EL_DC_MAGIC_WALL_FILLING); Store[x][y] = element; } else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID) @@ -6112,7 +6980,9 @@ void StartMoving(int x, int y) else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy)) { if (Feld[newx][newy] == EL_EXIT_OPEN || - Feld[newx][newy] == EL_STEEL_EXIT_OPEN) + Feld[newx][newy] == EL_EM_EXIT_OPEN || + Feld[newx][newy] == EL_STEEL_EXIT_OPEN || + Feld[newx][newy] == EL_EM_STEEL_EXIT_OPEN) { RemoveField(x, y); DrawLevelField(x, y); @@ -6530,6 +7400,17 @@ 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 + DrawLevelField(x, y); return; /* element is still moving */ @@ -6551,12 +7432,22 @@ void ContinueMoving(int x, int y) DrawLevelFieldCrumbledSandNeighbours(x, y); } - else if (element == EL_QUICKSAND_FILLING) + else if (element == EL_QUICKSAND_FILLING) + { + element = Feld[newx][newy] = get_next_element(element); + Store[newx][newy] = Store[x][y]; + } + else if (element == EL_QUICKSAND_EMPTYING) + { + Feld[x][y] = get_next_element(element); + element = Feld[newx][newy] = Store[x][y]; + } + else if (element == EL_QUICKSAND_FAST_FILLING) { element = Feld[newx][newy] = get_next_element(element); Store[newx][newy] = Store[x][y]; } - else if (element == EL_QUICKSAND_EMPTYING) + else if (element == EL_QUICKSAND_FAST_EMPTYING) { Feld[x][y] = get_next_element(element); element = Feld[newx][newy] = Store[x][y]; @@ -6593,6 +7484,24 @@ 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) + { + element = Feld[newx][newy] = get_next_element(element); + if (!game.magic_wall_active) + element = Feld[newx][newy] = EL_DC_MAGIC_WALL_DEAD; + Store[newx][newy] = Store[x][y]; + } + else if (element == EL_DC_MAGIC_WALL_EMPTYING) + { + Feld[x][y] = get_next_element(element); + if (!game.magic_wall_active) + 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 @@ -7096,7 +8005,8 @@ void AmoebeAbleger(int ax, int ay) if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || - Feld[x][y] == EL_QUICKSAND_EMPTY) + Feld[x][y] == EL_QUICKSAND_EMPTY || + Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; @@ -7121,7 +8031,8 @@ void AmoebeAbleger(int ax, int ay) if (IS_FREE(x, y) || CAN_GROW_INTO(Feld[x][y]) || - Feld[x][y] == EL_QUICKSAND_EMPTY) + Feld[x][y] == EL_QUICKSAND_EMPTY || + Feld[x][y] == EL_QUICKSAND_FAST_EMPTY) { newax = x; neway = y; @@ -7373,6 +8284,29 @@ void CheckExit(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING); } +void CheckExitEM(int x, int y) +{ + if (local_player->gems_still_needed > 0 || + local_player->sokobanfields_still_needed > 0 || + local_player->lights_still_needed > 0) + { + int element = Feld[x][y]; + int graphic = el2img(element); + + if (IS_ANIMATED(graphic)) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + + return; + } + + if (AllPlayersGone) /* do not re-open exit door closed after last player */ + return; + + Feld[x][y] = EL_EM_EXIT_OPENING; + + PlayLevelSoundNearest(x, y, SND_CLASS_EM_EXIT_OPENING); +} + void CheckExitSteel(int x, int y) { if (local_player->gems_still_needed > 0 || @@ -7396,6 +8330,29 @@ void CheckExitSteel(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_STEEL_EXIT_OPENING); } +void CheckExitSteelEM(int x, int y) +{ + if (local_player->gems_still_needed > 0 || + local_player->sokobanfields_still_needed > 0 || + local_player->lights_still_needed > 0) + { + int element = Feld[x][y]; + int graphic = el2img(element); + + if (IS_ANIMATED(graphic)) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + + return; + } + + if (AllPlayersGone) /* do not re-open exit door closed after last player */ + return; + + Feld[x][y] = EL_EM_STEEL_EXIT_OPENING; + + PlayLevelSoundNearest(x, y, SND_CLASS_EM_STEEL_EXIT_OPENING); +} + void CheckExitSP(int x, int y) { if (local_player->gems_still_needed > 0) @@ -8314,7 +9271,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) static void CreateFieldExt(int x, int y, int element, boolean is_change) { int old_element = Feld[x][y]; - int new_element = get_element_from_group_element(element); + int new_element = GetElementFromGroupElement(element); int previous_move_direction = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; @@ -8646,8 +9603,19 @@ static void HandleElementChange(int x, int y, int page) if (change->can_change) { - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); +#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 + /* 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 + { + ResetGfxAnimation(x, y); + ResetRandomAnimationValue(x, y); + } +#endif if (change->pre_change_function) change->pre_change_function(x, y); @@ -9442,7 +10410,7 @@ void GameActions() AllPlayersGone = TRUE; } - if (local_player->LevelSolved) + if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) @@ -9679,13 +10647,15 @@ void GameActions_RND() /* continue moving after pushing (this is actually a bug) */ if (!IS_MOVING(x, y)) - { Stop[x][y] = FALSE; - } } } } +#if 0 + debug_print_timestamp(0, "start main loop profiling"); +#endif + SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; @@ -9760,6 +10730,63 @@ 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]); + +#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]; @@ -9803,6 +10830,143 @@ void GameActions_RND() 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); + + 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]) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + + if (IS_GEM(element) || element == EL_SP_INFOTRON) + DrawTwinkleOnField(x, y); + } + else if (IS_MOVING(x, y)) + ContinueMoving(x, y); + else + { + 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); @@ -9820,8 +10984,10 @@ void GameActions_RND() } else if ((element == EL_ACID || element == EL_EXIT_OPEN || + element == EL_EM_EXIT_OPEN || element == EL_SP_EXIT_OPEN || element == EL_STEEL_EXIT_OPEN || + element == EL_EM_STEEL_EXIT_OPEN || element == EL_SP_TERMINAL || element == EL_SP_TERMINAL_ACTIVE || element == EL_EXTRA_TIME || @@ -9847,8 +11013,12 @@ void GameActions_RND() Life(x, y); else if (element == EL_EXIT_CLOSED) CheckExit(x, y); + else if (element == EL_EM_EXIT_CLOSED) + CheckExitEM(x, y); else if (element == EL_STEEL_EXIT_CLOSED) CheckExitSteel(x, y); + else if (element == EL_EM_STEEL_EXIT_CLOSED) + CheckExitSteelEM(x, y); else if (element == EL_SP_EXIT_CLOSED) CheckExitSP(x, y); else if (element == EL_EXPANDABLE_WALL_GROWING || @@ -9879,6 +11049,8 @@ 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); @@ -9892,7 +11064,10 @@ void GameActions_RND() element == EL_MAGIC_WALL_EMPTYING || element == EL_BD_MAGIC_WALL_FULL || element == EL_BD_MAGIC_WALL_ACTIVE || - element == EL_BD_MAGIC_WALL_EMPTYING) && + element == EL_BD_MAGIC_WALL_EMPTYING || + element == EL_DC_MAGIC_WALL_FULL || + element == EL_DC_MAGIC_WALL_ACTIVE || + element == EL_DC_MAGIC_WALL_EMPTYING) && ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy)) { magic_wall_x = x; @@ -9901,6 +11076,10 @@ 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)) @@ -9917,6 +11096,7 @@ void GameActions_RND() (element == EL_EMPTY || CAN_GROW_INTO(element) || element == EL_QUICKSAND_EMPTY || + element == EL_QUICKSAND_FAST_EMPTY || element == EL_ACID_SPLASH_LEFT || element == EL_ACID_SPLASH_RIGHT)) { @@ -9963,6 +11143,10 @@ void GameActions_RND() element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_EMPTYING) PlayLevelSound(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE); + else if (element == EL_DC_MAGIC_WALL_FULL || + element == EL_DC_MAGIC_WALL_ACTIVE || + element == EL_DC_MAGIC_WALL_EMPTYING) + PlayLevelSound(magic_wall_x, magic_wall_y, SND_DC_MAGIC_WALL_ACTIVE); else PlayLevelSound(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE); } @@ -9988,6 +11172,12 @@ void GameActions_RND() Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; DrawLevelField(x, y); } + else if (element == EL_DC_MAGIC_WALL_ACTIVE || + element == EL_DC_MAGIC_WALL_FULL) + { + Feld[x][y] = EL_DC_MAGIC_WALL_DEAD; + DrawLevelField(x, y); + } } game.magic_wall_active = FALSE; @@ -10073,6 +11263,11 @@ 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); @@ -10119,25 +11314,85 @@ static boolean AllPlayersInVisibleScreen() void ScrollLevel(int dx, int dy) { +#if 1 + static Bitmap *bitmap_db_field2 = NULL; int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); int x, y; +#else + int i, 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 1 + 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 1 + /* !!! 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 + + int softscroll_offset = (setup.soft_scrolling ? TILEX : 0); 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, + 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 - if (dx) + if (dx != 0) { x = (dx == 1 ? BX1 : BX2); for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); } - if (dy) + if (dy != 0) { y = (dy == 1 ? BY1 : BY2); for (x = BX1; x <= BX2; x++) @@ -10676,7 +11931,9 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) player->last_jy = jy; if (Feld[jx][jy] == EL_EXIT_OPEN || + Feld[jx][jy] == EL_EM_EXIT_OPEN || Feld[jx][jy] == EL_STEEL_EXIT_OPEN || + Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_SP_EXIT_OPEN || Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ { @@ -11645,7 +12902,9 @@ int DigField(struct PlayerInfo *player, return MP_NO_ACTION; } else if (element == EL_EXIT_OPEN || + element == EL_EM_EXIT_OPEN || element == EL_STEEL_EXIT_OPEN || + element == EL_EM_STEEL_EXIT_OPEN || element == EL_SP_EXIT_OPEN || element == EL_SP_EXIT_OPENING) { @@ -11701,6 +12960,15 @@ int DigField(struct PlayerInfo *player, if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)]) return MP_NO_ACTION; } + else if (element == EL_DC_GATE_WHITE || + element == EL_DC_GATE_WHITE_GRAY || + element == EL_DC_GATE_WHITE_GRAY_ACTIVE) + { + if (player->num_white_keys == 0) + return MP_NO_ACTION; + + player->num_white_keys--; + } else if (IS_SP_PORT(element)) { if (element == EL_SP_GRAVITY_PORT_LEFT || @@ -11827,6 +13095,13 @@ int DigField(struct PlayerInfo *player, DrawGameDoorValues(); } + else if (element == EL_DC_KEY_WHITE) + { + player->num_white_keys++; + + /* display white keys? */ + /* DrawGameDoorValues(); */ + } else if (IS_ENVELOPE(element)) { player->show_envelope = element; @@ -12803,6 +14078,7 @@ void RaiseScoreElement(int element) case EL_EMC_KEY_6: case EL_EMC_KEY_7: case EL_EMC_KEY_8: + case EL_DC_KEY_WHITE: RaiseScore(level.score[SC_KEY]); break; default: @@ -13013,9 +14289,9 @@ static void LoadEngineSnapshotValues_RND() if (game.num_random_calls != num_random_calls) { - Error(ERR_RETURN, "number of random calls out of sync"); - Error(ERR_RETURN, "number of random calls should be %d", num_random_calls); - Error(ERR_RETURN, "number of random calls is %d", game.num_random_calls); + Error(ERR_INFO, "number of random calls out of sync"); + Error(ERR_INFO, "number of random calls should be %d", num_random_calls); + Error(ERR_INFO, "number of random calls is %d", game.num_random_calls); Error(ERR_EXIT, "this should not happen -- please debug"); } } @@ -13188,11 +14464,50 @@ boolean CheckEngineSnapshot() static struct { - int x, y; + int *x, *y; + int gd_x, gd_y; int gadget_id; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = { +#if 1 + { + &game.button.stop.x, &game.button.stop.y, + GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_STOP, + "stop game" + }, + { + &game.button.pause.x, &game.button.pause.y, + GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_PAUSE, + "pause game" + }, + { + &game.button.play.x, &game.button.play.y, + GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_PLAY, + "play game" + }, + { + &game.button.sound_music.x, &game.button.sound_music.y, + SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_MUSIC, + "background music on/off" + }, + { + &game.button.sound_loops.x, &game.button.sound_loops.y, + SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_LOOPS, + "sound loops on/off" + }, + { + &game.button.sound_simple.x,&game.button.sound_simple.y, + SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_SIMPLE, + "normal sounds on/off" + } +#else { GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS, GAME_CTRL_ID_STOP, @@ -13223,6 +14538,7 @@ static struct SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } +#endif }; void CreateGameButtons() @@ -13236,12 +14552,15 @@ void CreateGameButtons() int button_type; boolean checked; unsigned long event_mask; + int x, y; int gd_xoffset, gd_yoffset; int gd_x1, gd_x2, gd_y1, gd_y2; int id = i; - gd_xoffset = gamebutton_info[i].x; - gd_yoffset = gamebutton_info[i].y; + x = DX + *gamebutton_info[i].x; + y = DY + *gamebutton_info[i].y; + gd_xoffset = gamebutton_info[i].gd_x; + gd_yoffset = gamebutton_info[i].gd_y; gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset; gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset; @@ -13269,8 +14588,13 @@ void CreateGameButtons() gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, gamebutton_info[i].infotext, +#if 1 + GDI_X, x, + GDI_Y, y, +#else GDI_X, DX + gd_xoffset, GDI_Y, DY + gd_yoffset, +#endif GDI_WIDTH, GAME_BUTTON_XSIZE, GDI_HEIGHT, GAME_BUTTON_YSIZE, GDI_TYPE, button_type,