X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=a88b3f04ec1a8525e904b45e13418c94580ea9c3;hp=2540719756174cfe22a6558eca9b6df9d0c55a3f;hb=1e422c29292f0583391b0ce9e9c872b38f035ac0;hpb=a1810845210edd7c609a0ce30d235c487a79a1c0 diff --git a/src/game.c b/src/game.c index 25407197..a88b3f04 100644 --- a/src/game.c +++ b/src/game.c @@ -58,9 +58,37 @@ #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) + +#if USE_DELAYED_GFX_REDRAW +#define TEST_DrawLevelField(x, y) \ + GfxRedraw[x][y] |= GFX_REDRAW_TILE +#define TEST_DrawLevelFieldCrumbled(x, y) \ + GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED +#define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ + GfxRedraw[x][y] |= GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS +#define TEST_DrawTwinkleOnField(x, y) \ + GfxRedraw[x][y] |= GFX_REDRAW_TILE_TWINKLED +#else +#define TEST_DrawLevelField(x, y) \ + DrawLevelField(x, y) +#define TEST_DrawLevelFieldCrumbled(x, y) \ + DrawLevelFieldCrumbled(x, y) +#define TEST_DrawLevelFieldCrumbledNeighbours(x, y) \ + DrawLevelFieldCrumbledNeighbours(x, y) +#define TEST_DrawTwinkleOnField(x, y) \ + DrawTwinkleOnField(x, y) +#endif + /* for DigField() */ #define DF_NO_PUSH 0 @@ -131,433 +159,713 @@ #if 1 /* game panel display and control definitions */ -#define GAME_CONTROL_LEVEL_NUMBER 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_SWITCH 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 - -#define NUM_GAME_CONTROLS 69 - -int game_control_value[NUM_GAME_CONTROLS]; -int last_game_control_value[NUM_GAME_CONTROLS]; - -struct GameControlInfo +#define GAME_PANEL_LEVEL_NUMBER 0 +#define GAME_PANEL_GEMS 1 +#define GAME_PANEL_INVENTORY_COUNT 2 +#define GAME_PANEL_INVENTORY_FIRST_1 3 +#define GAME_PANEL_INVENTORY_FIRST_2 4 +#define GAME_PANEL_INVENTORY_FIRST_3 5 +#define GAME_PANEL_INVENTORY_FIRST_4 6 +#define GAME_PANEL_INVENTORY_FIRST_5 7 +#define GAME_PANEL_INVENTORY_FIRST_6 8 +#define GAME_PANEL_INVENTORY_FIRST_7 9 +#define GAME_PANEL_INVENTORY_FIRST_8 10 +#define GAME_PANEL_INVENTORY_LAST_1 11 +#define GAME_PANEL_INVENTORY_LAST_2 12 +#define GAME_PANEL_INVENTORY_LAST_3 13 +#define GAME_PANEL_INVENTORY_LAST_4 14 +#define GAME_PANEL_INVENTORY_LAST_5 15 +#define GAME_PANEL_INVENTORY_LAST_6 16 +#define GAME_PANEL_INVENTORY_LAST_7 17 +#define GAME_PANEL_INVENTORY_LAST_8 18 +#define GAME_PANEL_KEY_1 19 +#define GAME_PANEL_KEY_2 20 +#define GAME_PANEL_KEY_3 21 +#define GAME_PANEL_KEY_4 22 +#define GAME_PANEL_KEY_5 23 +#define GAME_PANEL_KEY_6 24 +#define GAME_PANEL_KEY_7 25 +#define GAME_PANEL_KEY_8 26 +#define GAME_PANEL_KEY_WHITE 27 +#define GAME_PANEL_KEY_WHITE_COUNT 28 +#define GAME_PANEL_SCORE 29 +#define GAME_PANEL_HIGHSCORE 30 +#define GAME_PANEL_TIME 31 +#define GAME_PANEL_TIME_HH 32 +#define GAME_PANEL_TIME_MM 33 +#define GAME_PANEL_TIME_SS 34 +#define GAME_PANEL_FRAME 35 +#define GAME_PANEL_SHIELD_NORMAL 36 +#define GAME_PANEL_SHIELD_NORMAL_TIME 37 +#define GAME_PANEL_SHIELD_DEADLY 38 +#define GAME_PANEL_SHIELD_DEADLY_TIME 39 +#define GAME_PANEL_EXIT 40 +#define GAME_PANEL_EMC_MAGIC_BALL 41 +#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 42 +#define GAME_PANEL_LIGHT_SWITCH 43 +#define GAME_PANEL_LIGHT_SWITCH_TIME 44 +#define GAME_PANEL_TIMEGATE_SWITCH 45 +#define GAME_PANEL_TIMEGATE_SWITCH_TIME 46 +#define GAME_PANEL_SWITCHGATE_SWITCH 47 +#define GAME_PANEL_EMC_LENSES 48 +#define GAME_PANEL_EMC_LENSES_TIME 49 +#define GAME_PANEL_EMC_MAGNIFIER 50 +#define GAME_PANEL_EMC_MAGNIFIER_TIME 51 +#define GAME_PANEL_BALLOON_SWITCH 52 +#define GAME_PANEL_DYNABOMB_NUMBER 53 +#define GAME_PANEL_DYNABOMB_SIZE 54 +#define GAME_PANEL_DYNABOMB_POWER 55 +#define GAME_PANEL_PENGUINS 56 +#define GAME_PANEL_SOKOBAN_OBJECTS 57 +#define GAME_PANEL_SOKOBAN_FIELDS 58 +#define GAME_PANEL_ROBOT_WHEEL 59 +#define GAME_PANEL_CONVEYOR_BELT_1 60 +#define GAME_PANEL_CONVEYOR_BELT_2 61 +#define GAME_PANEL_CONVEYOR_BELT_3 62 +#define GAME_PANEL_CONVEYOR_BELT_4 63 +#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 64 +#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 65 +#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 66 +#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 67 +#define GAME_PANEL_MAGIC_WALL 68 +#define GAME_PANEL_MAGIC_WALL_TIME 69 +#define GAME_PANEL_GRAVITY_STATE 70 +#define GAME_PANEL_GRAPHIC_1 71 +#define GAME_PANEL_GRAPHIC_2 72 +#define GAME_PANEL_GRAPHIC_3 73 +#define GAME_PANEL_GRAPHIC_4 74 +#define GAME_PANEL_GRAPHIC_5 75 +#define GAME_PANEL_GRAPHIC_6 76 +#define GAME_PANEL_GRAPHIC_7 77 +#define GAME_PANEL_GRAPHIC_8 78 +#define GAME_PANEL_ELEMENT_1 79 +#define GAME_PANEL_ELEMENT_2 80 +#define GAME_PANEL_ELEMENT_3 81 +#define GAME_PANEL_ELEMENT_4 82 +#define GAME_PANEL_ELEMENT_5 83 +#define GAME_PANEL_ELEMENT_6 84 +#define GAME_PANEL_ELEMENT_7 85 +#define GAME_PANEL_ELEMENT_8 86 +#define GAME_PANEL_ELEMENT_COUNT_1 87 +#define GAME_PANEL_ELEMENT_COUNT_2 88 +#define GAME_PANEL_ELEMENT_COUNT_3 89 +#define GAME_PANEL_ELEMENT_COUNT_4 90 +#define GAME_PANEL_ELEMENT_COUNT_5 91 +#define GAME_PANEL_ELEMENT_COUNT_6 92 +#define GAME_PANEL_ELEMENT_COUNT_7 93 +#define GAME_PANEL_ELEMENT_COUNT_8 94 +#define GAME_PANEL_CE_SCORE_1 95 +#define GAME_PANEL_CE_SCORE_2 96 +#define GAME_PANEL_CE_SCORE_3 97 +#define GAME_PANEL_CE_SCORE_4 98 +#define GAME_PANEL_CE_SCORE_5 99 +#define GAME_PANEL_CE_SCORE_6 100 +#define GAME_PANEL_CE_SCORE_7 101 +#define GAME_PANEL_CE_SCORE_8 102 +#define GAME_PANEL_CE_SCORE_1_ELEMENT 103 +#define GAME_PANEL_CE_SCORE_2_ELEMENT 104 +#define GAME_PANEL_CE_SCORE_3_ELEMENT 105 +#define GAME_PANEL_CE_SCORE_4_ELEMENT 106 +#define GAME_PANEL_CE_SCORE_5_ELEMENT 107 +#define GAME_PANEL_CE_SCORE_6_ELEMENT 108 +#define GAME_PANEL_CE_SCORE_7_ELEMENT 109 +#define GAME_PANEL_CE_SCORE_8_ELEMENT 110 +#define GAME_PANEL_PLAYER_NAME 111 +#define GAME_PANEL_LEVEL_NAME 112 +#define GAME_PANEL_LEVEL_AUTHOR 113 + +#define NUM_GAME_PANEL_CONTROLS 114 + +struct GamePanelOrderInfo +{ + int nr; + int sort_priority; +}; + +static struct GamePanelOrderInfo game_panel_order[NUM_GAME_PANEL_CONTROLS]; + +struct GamePanelControlInfo { int nr; struct TextPosInfo *pos; int type; + + int value, last_value; + int frame, last_frame; + int gfx_frame; + int gfx_random; }; -static struct GameControlInfo game_controls[] = +static struct GamePanelControlInfo game_panel_controls[] = { { - GAME_CONTROL_LEVEL_NUMBER, + GAME_PANEL_LEVEL_NUMBER, &game.panel.level_number, TYPE_INTEGER, }, { - GAME_CONTROL_GEMS, + GAME_PANEL_GEMS, &game.panel.gems, TYPE_INTEGER, }, { - GAME_CONTROL_INVENTORY, - &game.panel.inventory, + GAME_PANEL_INVENTORY_COUNT, + &game.panel.inventory_count, TYPE_INTEGER, }, { - GAME_CONTROL_KEY_1, - &game.panel.key[0], + GAME_PANEL_INVENTORY_FIRST_1, + &game.panel.inventory_first[0], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_2, - &game.panel.key[1], + GAME_PANEL_INVENTORY_FIRST_2, + &game.panel.inventory_first[1], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_3, - &game.panel.key[2], + GAME_PANEL_INVENTORY_FIRST_3, + &game.panel.inventory_first[2], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_4, - &game.panel.key[3], + GAME_PANEL_INVENTORY_FIRST_4, + &game.panel.inventory_first[3], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_5, - &game.panel.key[4], + GAME_PANEL_INVENTORY_FIRST_5, + &game.panel.inventory_first[4], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_6, - &game.panel.key[5], + GAME_PANEL_INVENTORY_FIRST_6, + &game.panel.inventory_first[5], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_7, - &game.panel.key[6], + GAME_PANEL_INVENTORY_FIRST_7, + &game.panel.inventory_first[6], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_8, - &game.panel.key[7], + GAME_PANEL_INVENTORY_FIRST_8, + &game.panel.inventory_first[7], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_WHITE, - &game.panel.key_white, + GAME_PANEL_INVENTORY_LAST_1, + &game.panel.inventory_last[0], TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_WHITE_COUNT, - &game.panel.key_white_count, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_2, + &game.panel.inventory_last[1], + TYPE_ELEMENT, }, { - GAME_CONTROL_SCORE, - &game.panel.score, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_3, + &game.panel.inventory_last[2], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME, - &game.panel.time, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_4, + &game.panel.inventory_last[3], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_HH, - &game.panel.time_hh, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_5, + &game.panel.inventory_last[4], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_MM, - &game.panel.time_mm, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_6, + &game.panel.inventory_last[5], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_SS, - &game.panel.time_ss, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_7, + &game.panel.inventory_last[6], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_1, - &game.panel.drop_next_1, + GAME_PANEL_INVENTORY_LAST_8, + &game.panel.inventory_last[7], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_2, - &game.panel.drop_next_2, + GAME_PANEL_KEY_1, + &game.panel.key[0], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_3, - &game.panel.drop_next_3, + GAME_PANEL_KEY_2, + &game.panel.key[1], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_4, - &game.panel.drop_next_4, + GAME_PANEL_KEY_3, + &game.panel.key[2], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_5, - &game.panel.drop_next_5, + GAME_PANEL_KEY_4, + &game.panel.key[3], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_6, - &game.panel.drop_next_6, + GAME_PANEL_KEY_5, + &game.panel.key[4], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_7, - &game.panel.drop_next_7, + GAME_PANEL_KEY_6, + &game.panel.key[5], TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_8, - &game.panel.drop_next_8, + GAME_PANEL_KEY_7, + &game.panel.key[6], TYPE_ELEMENT, }, { - GAME_CONTROL_SHIELD_NORMAL, - &game.panel.shield_normal, + GAME_PANEL_KEY_8, + &game.panel.key[7], TYPE_ELEMENT, }, { - GAME_CONTROL_SHIELD_NORMAL_TIME, - &game.panel.shield_normal_time, + GAME_PANEL_KEY_WHITE, + &game.panel.key_white, + TYPE_ELEMENT, + }, + { + GAME_PANEL_KEY_WHITE_COUNT, + &game.panel.key_white_count, TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_DEADLY, - &game.panel.shield_deadly, - TYPE_ELEMENT, + GAME_PANEL_SCORE, + &game.panel.score, + TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_DEADLY_TIME, - &game.panel.shield_deadly_time, + GAME_PANEL_HIGHSCORE, + &game.panel.highscore, TYPE_INTEGER, }, { - GAME_CONTROL_EXIT, - &game.panel.exit, - TYPE_ELEMENT, + GAME_PANEL_TIME, + &game.panel.time, + TYPE_INTEGER, }, { - GAME_CONTROL_EM_EXIT, - &game.panel.em_exit, - TYPE_ELEMENT, + GAME_PANEL_TIME_HH, + &game.panel.time_hh, + TYPE_INTEGER, }, { - GAME_CONTROL_SP_EXIT, - &game.panel.sp_exit, + GAME_PANEL_TIME_MM, + &game.panel.time_mm, + TYPE_INTEGER, + }, + { + GAME_PANEL_TIME_SS, + &game.panel.time_ss, + TYPE_INTEGER, + }, + { + GAME_PANEL_FRAME, + &game.panel.frame, + TYPE_INTEGER, + }, + { + GAME_PANEL_SHIELD_NORMAL, + &game.panel.shield_normal, TYPE_ELEMENT, }, { - GAME_CONTROL_STEEL_EXIT, - &game.panel.steel_exit, + GAME_PANEL_SHIELD_NORMAL_TIME, + &game.panel.shield_normal_time, + TYPE_INTEGER, + }, + { + GAME_PANEL_SHIELD_DEADLY, + &game.panel.shield_deadly, TYPE_ELEMENT, }, { - GAME_CONTROL_EM_STEEL_EXIT, - &game.panel.em_steel_exit, + GAME_PANEL_SHIELD_DEADLY_TIME, + &game.panel.shield_deadly_time, + TYPE_INTEGER, + }, + { + GAME_PANEL_EXIT, + &game.panel.exit, TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_MAGIC_BALL, + GAME_PANEL_EMC_MAGIC_BALL, &game.panel.emc_magic_ball, TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_MAGIC_BALL_SWITCH, + GAME_PANEL_EMC_MAGIC_BALL_SWITCH, &game.panel.emc_magic_ball_switch, TYPE_ELEMENT, }, { - GAME_CONTROL_LIGHT_SWITCH, + GAME_PANEL_LIGHT_SWITCH, &game.panel.light_switch, TYPE_ELEMENT, }, { - GAME_CONTROL_LIGHT_SWITCH_TIME, + GAME_PANEL_LIGHT_SWITCH_TIME, &game.panel.light_switch_time, TYPE_INTEGER, }, { - GAME_CONTROL_TIMEGATE_SWITCH, + GAME_PANEL_TIMEGATE_SWITCH, &game.panel.timegate_switch, TYPE_ELEMENT, }, { - GAME_CONTROL_TIMEGATE_SWITCH_TIME, + GAME_PANEL_TIMEGATE_SWITCH_TIME, &game.panel.timegate_switch_time, TYPE_INTEGER, }, { - GAME_CONTROL_SWITCHGATE_SWITCH, + GAME_PANEL_SWITCHGATE_SWITCH, &game.panel.switchgate_switch, TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_LENSES, + GAME_PANEL_EMC_LENSES, &game.panel.emc_lenses, TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_LENSES_TIME, + GAME_PANEL_EMC_LENSES_TIME, &game.panel.emc_lenses_time, TYPE_INTEGER, }, { - GAME_CONTROL_EMC_MAGNIFIER, + GAME_PANEL_EMC_MAGNIFIER, &game.panel.emc_magnifier, TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_MAGNIFIER_TIME, + GAME_PANEL_EMC_MAGNIFIER_TIME, &game.panel.emc_magnifier_time, TYPE_INTEGER, }, { - GAME_CONTROL_BALLOON_SWITCH, + GAME_PANEL_BALLOON_SWITCH, &game.panel.balloon_switch, TYPE_ELEMENT, }, { - GAME_CONTROL_DYNABOMB_NUMBER, + GAME_PANEL_DYNABOMB_NUMBER, &game.panel.dynabomb_number, TYPE_INTEGER, }, { - GAME_CONTROL_DYNABOMB_SIZE, + GAME_PANEL_DYNABOMB_SIZE, &game.panel.dynabomb_size, TYPE_INTEGER, }, { - GAME_CONTROL_DYNABOMB_POWER, + GAME_PANEL_DYNABOMB_POWER, &game.panel.dynabomb_power, TYPE_ELEMENT, }, { - GAME_CONTROL_PENGUINS, + GAME_PANEL_PENGUINS, &game.panel.penguins, TYPE_INTEGER, }, { - GAME_CONTROL_SOKOBAN_OBJECTS, + GAME_PANEL_SOKOBAN_OBJECTS, &game.panel.sokoban_objects, TYPE_INTEGER, }, { - GAME_CONTROL_SOKOBAN_FIELDS, + GAME_PANEL_SOKOBAN_FIELDS, &game.panel.sokoban_fields, TYPE_INTEGER, }, { - GAME_CONTROL_ROBOT_WHEEL, + GAME_PANEL_ROBOT_WHEEL, &game.panel.robot_wheel, TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_1, - &game.panel.conveyor_belt_1, + GAME_PANEL_CONVEYOR_BELT_1, + &game.panel.conveyor_belt[0], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_1_SWITCH, - &game.panel.conveyor_belt_1_switch, + GAME_PANEL_CONVEYOR_BELT_2, + &game.panel.conveyor_belt[1], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_2, - &game.panel.conveyor_belt_2, + GAME_PANEL_CONVEYOR_BELT_3, + &game.panel.conveyor_belt[2], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_2_SWITCH, - &game.panel.conveyor_belt_2_switch, + GAME_PANEL_CONVEYOR_BELT_4, + &game.panel.conveyor_belt[3], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_3, - &game.panel.conveyor_belt_3, + GAME_PANEL_CONVEYOR_BELT_1_SWITCH, + &game.panel.conveyor_belt_switch[0], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_3_SWITCH, - &game.panel.conveyor_belt_3_switch, + GAME_PANEL_CONVEYOR_BELT_2_SWITCH, + &game.panel.conveyor_belt_switch[1], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_4, - &game.panel.conveyor_belt_4, + GAME_PANEL_CONVEYOR_BELT_3_SWITCH, + &game.panel.conveyor_belt_switch[2], TYPE_ELEMENT, }, { - GAME_CONTROL_CONVEYOR_BELT_4_SWITCH, - &game.panel.conveyor_belt_4_switch, + GAME_PANEL_CONVEYOR_BELT_4_SWITCH, + &game.panel.conveyor_belt_switch[3], TYPE_ELEMENT, }, { - GAME_CONTROL_MAGIC_WALL, + GAME_PANEL_MAGIC_WALL, &game.panel.magic_wall, TYPE_ELEMENT, }, { - GAME_CONTROL_MAGIC_WALL_TIME, + GAME_PANEL_MAGIC_WALL_TIME, &game.panel.magic_wall_time, TYPE_INTEGER, }, { - GAME_CONTROL_BD_MAGIC_WALL, - &game.panel.bd_magic_wall, + GAME_PANEL_GRAVITY_STATE, + &game.panel.gravity_state, + TYPE_STRING, + }, + { + GAME_PANEL_GRAPHIC_1, + &game.panel.graphic[0], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_2, + &game.panel.graphic[1], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_3, + &game.panel.graphic[2], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_4, + &game.panel.graphic[3], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_5, + &game.panel.graphic[4], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_6, + &game.panel.graphic[5], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_7, + &game.panel.graphic[6], + TYPE_ELEMENT, + }, + { + GAME_PANEL_GRAPHIC_8, + &game.panel.graphic[7], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_1, + &game.panel.element[0], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_2, + &game.panel.element[1], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_3, + &game.panel.element[2], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_4, + &game.panel.element[3], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_5, + &game.panel.element[4], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_6, + &game.panel.element[5], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_7, + &game.panel.element[6], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_8, + &game.panel.element[7], + TYPE_ELEMENT, + }, + { + GAME_PANEL_ELEMENT_COUNT_1, + &game.panel.element_count[0], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_2, + &game.panel.element_count[1], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_3, + &game.panel.element_count[2], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_4, + &game.panel.element_count[3], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_5, + &game.panel.element_count[4], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_6, + &game.panel.element_count[5], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_7, + &game.panel.element_count[6], + TYPE_INTEGER, + }, + { + GAME_PANEL_ELEMENT_COUNT_8, + &game.panel.element_count[7], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_1, + &game.panel.ce_score[0], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_2, + &game.panel.ce_score[1], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_3, + &game.panel.ce_score[2], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_4, + &game.panel.ce_score[3], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_5, + &game.panel.ce_score[4], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_6, + &game.panel.ce_score[5], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_7, + &game.panel.ce_score[6], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_8, + &game.panel.ce_score[7], + TYPE_INTEGER, + }, + { + GAME_PANEL_CE_SCORE_1_ELEMENT, + &game.panel.ce_score_element[0], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_2_ELEMENT, + &game.panel.ce_score_element[1], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_3_ELEMENT, + &game.panel.ce_score_element[2], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_4_ELEMENT, + &game.panel.ce_score_element[3], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_5_ELEMENT, + &game.panel.ce_score_element[4], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_6_ELEMENT, + &game.panel.ce_score_element[5], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CE_SCORE_7_ELEMENT, + &game.panel.ce_score_element[6], TYPE_ELEMENT, }, { - GAME_CONTROL_DC_MAGIC_WALL, - &game.panel.dc_magic_wall, + GAME_PANEL_CE_SCORE_8_ELEMENT, + &game.panel.ce_score_element[7], TYPE_ELEMENT, }, { - GAME_CONTROL_PLAYER_NAME, + GAME_PANEL_PLAYER_NAME, &game.panel.player_name, TYPE_STRING, }, { - GAME_CONTROL_LEVEL_NAME, + GAME_PANEL_LEVEL_NAME, &game.panel.level_name, TYPE_STRING, }, { - GAME_CONTROL_LEVEL_AUTHOR, + GAME_PANEL_LEVEL_AUTHOR, &game.panel.level_author, TYPE_STRING, }, @@ -628,6 +936,9 @@ static struct GameControlInfo game_controls[] = (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ (be) + (e) - EL_SELF) +#define GET_PLAYER_FROM_BITS(p) \ + (EL_PLAYER_1 + ((p) != PLAYER_BITS_ANY ? log_2(p) : 0)) + #define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ @@ -746,6 +1057,8 @@ static struct GameControlInfo game_controls[] = static void CreateField(int, int, int); +static void ResetGfxAnimation(int, int); + static void SetPlayerWaiting(struct PlayerInfo *, boolean); static void AdvanceFrameAndPlayerCounters(int); @@ -754,7 +1067,10 @@ static boolean MovePlayer(struct PlayerInfo *, int, int); static void ScrollPlayer(struct PlayerInfo *, int); static void ScrollScreen(struct PlayerInfo *, int); -int DigField(struct PlayerInfo *, int, int, int, int, int, int, int); +static int DigField(struct PlayerInfo *, int, int, int, int, int, int, int); +static boolean DigFieldByCE(int, int, int); +static boolean SnapField(struct PlayerInfo *, int, int); +static boolean DropElement(struct PlayerInfo *); static void InitBeltMovement(void); static void CloseAllOpenTimegates(void); @@ -821,14 +1137,12 @@ void TestIfBadThingRunsIntoPlayer(int, int, int); void TestIfFriendTouchesBadThing(int, int); void TestIfBadThingTouchesFriend(int, int); void TestIfBadThingTouchesOtherBadThing(int, int); +void TestIfGoodThingGetsHitByBadThing(int, int, int); void KillPlayer(struct PlayerInfo *); void BuryPlayer(struct PlayerInfo *); void RemovePlayer(struct PlayerInfo *); -boolean SnapField(struct PlayerInfo *, int, int); -boolean DropElement(struct PlayerInfo *); - static int getInvisibleActiveFromInvisibleElement(int); static int getInvisibleFromInvisibleActiveElement(int); @@ -861,6 +1175,8 @@ static int recursion_loop_depth; static boolean recursion_loop_detected; static boolean recursion_loop_element; +static int map_player_action[MAX_PLAYERS]; + /* ------------------------------------------------------------------------- */ /* definition of elements that automatically change to other elements after */ @@ -1419,6 +1735,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) } else { + stored_player[0].initial_element = element; stored_player[0].use_murphy = TRUE; if (!level.use_artwork_element[0]) @@ -1477,6 +1794,17 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) player->jx = player->last_jx = x; player->jy = player->last_jy = y; } + +#if USE_PLAYER_REANIMATION + if (!init_game) + { + int player_nr = GET_PLAYER_NR(element); + struct PlayerInfo *player = &stored_player[player_nr]; + + 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) @@ -1664,6 +1992,34 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; break; + case EL_TRIGGER_PLAYER: + case EL_TRIGGER_ELEMENT: + case EL_TRIGGER_CE_VALUE: + case EL_TRIGGER_CE_SCORE: + case EL_SELF: + case EL_ANY_ELEMENT: + case EL_CURRENT_CE_VALUE: + case EL_CURRENT_CE_SCORE: + case EL_PREV_CE_1: + case EL_PREV_CE_2: + case EL_PREV_CE_3: + case EL_PREV_CE_4: + case EL_PREV_CE_5: + case EL_PREV_CE_6: + case EL_PREV_CE_7: + case EL_PREV_CE_8: + case EL_NEXT_CE_1: + case EL_NEXT_CE_2: + case EL_NEXT_CE_3: + case EL_NEXT_CE_4: + case EL_NEXT_CE_5: + case EL_NEXT_CE_6: + case EL_NEXT_CE_7: + case EL_NEXT_CE_8: + /* reference elements should not be used on the playfield */ + Feld[x][y] = EL_EMPTY; + break; + default: if (IS_CUSTOM_ELEMENT(element)) { @@ -1722,57 +2078,227 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) #if 1 +static int get_key_element_from_nr(int key_nr) +{ + int key_base_element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? + EL_EM_KEY_1 : EL_KEY_1); + + return key_base_element + key_nr; +} + +static int get_next_dropped_element(struct PlayerInfo *player) +{ + return (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); +} + +static int get_inventory_element_from_pos(struct PlayerInfo *player, int pos) +{ + /* pos >= 0: get element from bottom of the stack; + pos < 0: get element from top of the stack */ + + if (pos < 0) + { + int min_inventory_size = -pos; + int inventory_pos = player->inventory_size - min_inventory_size; + int min_dynabombs_left = min_inventory_size - player->inventory_size; + + return (player->inventory_size >= min_inventory_size ? + player->inventory_element[inventory_pos] : + player->inventory_infinite_element != EL_UNDEFINED ? + player->inventory_infinite_element : + player->dynabombs_left >= min_dynabombs_left ? + EL_DYNABOMB_PLAYER_1 + player->index_nr : + EL_UNDEFINED); + } + else + { + int min_dynabombs_left = pos + 1; + int min_inventory_size = pos + 1 - player->dynabombs_left; + int inventory_pos = pos - player->dynabombs_left; + + return (player->inventory_infinite_element != EL_UNDEFINED ? + player->inventory_infinite_element : + player->dynabombs_left >= min_dynabombs_left ? + EL_DYNABOMB_PLAYER_1 + player->index_nr : + player->inventory_size >= min_inventory_size ? + player->inventory_element[inventory_pos] : + EL_UNDEFINED); + } +} + +static int compareGamePanelOrderInfo(const void *object1, const void *object2) +{ + const struct GamePanelOrderInfo *gpo1 = (struct GamePanelOrderInfo *)object1; + const struct GamePanelOrderInfo *gpo2 = (struct GamePanelOrderInfo *)object2; + int compare_result; + + if (gpo1->sort_priority != gpo2->sort_priority) + compare_result = gpo1->sort_priority - gpo2->sort_priority; + else + compare_result = gpo1->nr - gpo2->nr; + + return compare_result; +} + void InitGameControlValues() { int i; - for (i = 0; i < NUM_GAME_CONTROLS; i++) - game_control_value[i] = last_game_control_value[i] = -1; - - for (i = 0; game_controls[i].nr != -1; i++) + for (i = 0; game_panel_controls[i].nr != -1; i++) { - int nr = game_controls[i].nr; - int type = game_controls[i].type; - struct TextPosInfo *pos = game_controls[i].pos; + struct GamePanelControlInfo *gpc = &game_panel_controls[i]; + struct GamePanelOrderInfo *gpo = &game_panel_order[i]; + struct TextPosInfo *pos = gpc->pos; + int nr = gpc->nr; + int type = gpc->type; - game_control_value[nr] = last_game_control_value[nr] = -1; + if (nr != i) + { + Error(ERR_INFO, "'game_panel_controls' structure corrupted at %d", i); + Error(ERR_EXIT, "this should not happen -- please debug"); + } + + /* force update of game controls after initialization */ + gpc->value = gpc->last_value = -1; + gpc->frame = gpc->last_frame = -1; + gpc->gfx_frame = -1; /* determine panel value width for later calculation of alignment */ if (type == TYPE_INTEGER || type == TYPE_STRING) - pos->width = pos->chars * getFontWidth(pos->font); + { + pos->width = pos->size * getFontWidth(pos->font); + pos->height = getFontHeight(pos->font); + } else if (type == TYPE_ELEMENT) - pos->width = MINI_TILESIZE; + { + pos->width = pos->size; + pos->height = pos->size; + } + + /* fill structure for game panel draw order */ + gpo->nr = gpc->nr; + gpo->sort_priority = pos->sort_priority; } + + /* sort game panel controls according to sort_priority and control number */ + qsort(game_panel_order, NUM_GAME_PANEL_CONTROLS, + sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo); } -void UpdateGameControlValues() +void UpdatePlayfieldElementCount() { - int i, j; + boolean use_element_count = FALSE; + int i, j, x, y; + + /* first check if it is needed at all to calculate playfield element count */ + for (i = GAME_PANEL_ELEMENT_COUNT_1; i <= GAME_PANEL_ELEMENT_COUNT_8; i++) + if (!PANEL_DEACTIVATED(game_panel_controls[i].pos)) + use_element_count = TRUE; + + if (!use_element_count) + return; + + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + element_info[i].element_count = 0; + + SCAN_PLAYFIELD(x, y) + { + element_info[Feld[x][y]].element_count++; + } - game_control_value[GAME_CONTROL_LEVEL_NUMBER] = level_nr; - game_control_value[GAME_CONTROL_GEMS] = local_player->gems_still_needed; + for (i = 0; i < NUM_GROUP_ELEMENTS; i++) + for (j = 0; j < MAX_NUM_ELEMENTS; j++) + if (IS_IN_GROUP(j, i)) + element_info[EL_GROUP_START + i].element_count += + element_info[j].element_count; +} - game_control_value[GAME_CONTROL_INVENTORY] = 0; +void UpdateGameControlValues() +{ + int i, k; + int time = (local_player->LevelSolved ? + local_player->LevelSolved_CountingTime : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->time : + level.game_engine_type == GAME_ENGINE_TYPE_SP ? + level.native_sp_level->game_sp->time_played : + level.time == 0 ? TimePlayed : TimeLeft); + int score = (local_player->LevelSolved ? + local_player->LevelSolved_CountingScore : + level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->score : + level.game_engine_type == GAME_ENGINE_TYPE_SP ? + level.native_sp_level->game_sp->score : + local_player->score); + int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->required : + level.game_engine_type == GAME_ENGINE_TYPE_SP ? + level.native_sp_level->game_sp->infotrons_still_needed : + local_player->gems_still_needed); + int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->required > 0 : + level.game_engine_type == GAME_ENGINE_TYPE_SP ? + level.native_sp_level->game_sp->infotrons_still_needed > 0 : + local_player->gems_still_needed > 0 || + local_player->sokobanfields_still_needed > 0 || + local_player->lights_still_needed > 0); + + UpdatePlayfieldElementCount(); + + /* update game panel control values */ + + game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr; + game_panel_controls[GAME_PANEL_GEMS].value = gems; + + game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0; for (i = 0; i < MAX_NUM_KEYS; i++) - game_control_value[GAME_CONTROL_KEY_1 + i] = 0; - game_control_value[GAME_CONTROL_KEY_WHITE] = 0; - game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] = 0; + game_panel_controls[GAME_PANEL_KEY_1 + i].value = EL_EMPTY; + game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_EMPTY; + game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value = 0; 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]) - game_control_value[GAME_CONTROL_KEY_1 + j] = 1; + /* only one player in Supaplex game engine */ + if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0) + break; - game_control_value[GAME_CONTROL_INVENTORY] += - stored_player[i].inventory_size; + for (k = 0; k < MAX_NUM_KEYS; k++) + { + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + { + if (level.native_em_level->ply[i]->keys & (1 << k)) + game_panel_controls[GAME_PANEL_KEY_1 + k].value = + get_key_element_from_nr(k); + } + else if (stored_player[i].key[k]) + game_panel_controls[GAME_PANEL_KEY_1 + k].value = + 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; if (stored_player[i].num_white_keys > 0) - game_control_value[GAME_CONTROL_KEY_WHITE] = 1; + game_panel_controls[GAME_PANEL_KEY_WHITE].value = + EL_DC_KEY_WHITE; - game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] += + game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[i].num_white_keys; } } @@ -1780,179 +2306,324 @@ void UpdateGameControlValues() { int player_nr = game.centered_player_nr; - for (i = 0; i < MAX_NUM_KEYS; i++) - if (stored_player[player_nr].key[i]) - game_control_value[GAME_CONTROL_KEY_1 + i] = 1; + for (k = 0; k < MAX_NUM_KEYS; k++) + { + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + { + if (level.native_em_level->ply[player_nr]->keys & (1 << k)) + game_panel_controls[GAME_PANEL_KEY_1 + k].value = + get_key_element_from_nr(k); + } + else if (stored_player[player_nr].key[k]) + game_panel_controls[GAME_PANEL_KEY_1 + k].value = + get_key_element_from_nr(k); + } - game_control_value[GAME_CONTROL_INVENTORY] += - stored_player[player_nr].inventory_size; + 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; if (stored_player[player_nr].num_white_keys > 0) - game_control_value[GAME_CONTROL_KEY_WHITE] = 1; + game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; - game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] += + game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += stored_player[player_nr].num_white_keys; } - game_control_value[GAME_CONTROL_SCORE] = (local_player->LevelSolved ? - local_player->score_final : - local_player->score); + for (i = 0; i < NUM_PANEL_INVENTORY; i++) + { + game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value = + get_inventory_element_from_pos(local_player, i); + game_panel_controls[GAME_PANEL_INVENTORY_LAST_1 + i].value = + get_inventory_element_from_pos(local_player, -i - 1); + } + + game_panel_controls[GAME_PANEL_SCORE].value = score; + game_panel_controls[GAME_PANEL_HIGHSCORE].value = highscore[0].Score; - game_control_value[GAME_CONTROL_TIME] = (level.time == 0 ? - TimePlayed : - TimeLeft); + game_panel_controls[GAME_PANEL_TIME].value = time; - game_control_value[GAME_CONTROL_TIME_HH] = TapeTime / 3600; - game_control_value[GAME_CONTROL_TIME_MM] = (TapeTime / 60) % 60; - game_control_value[GAME_CONTROL_TIME_SS] = TapeTime % 60; + game_panel_controls[GAME_PANEL_TIME_HH].value = time / 3600; + game_panel_controls[GAME_PANEL_TIME_MM].value = (time / 60) % 60; + game_panel_controls[GAME_PANEL_TIME_SS].value = time % 60; - for (i = 0; i < 8; i++) - game_control_value[GAME_CONTROL_DROP_NEXT_1 + i] = EL_UNDEFINED; + game_panel_controls[GAME_PANEL_FRAME].value = FrameCounter; - game_control_value[GAME_CONTROL_SHIELD_NORMAL] = + game_panel_controls[GAME_PANEL_SHIELD_NORMAL].value = (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE : EL_EMPTY); - game_control_value[GAME_CONTROL_SHIELD_NORMAL_TIME] = + game_panel_controls[GAME_PANEL_SHIELD_NORMAL_TIME].value = local_player->shield_normal_time_left; - game_control_value[GAME_CONTROL_SHIELD_DEADLY] = + game_panel_controls[GAME_PANEL_SHIELD_DEADLY].value = (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE : EL_EMPTY); - game_control_value[GAME_CONTROL_SHIELD_DEADLY_TIME] = + game_panel_controls[GAME_PANEL_SHIELD_DEADLY_TIME].value = local_player->shield_deadly_time_left; - if (local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0) - { - game_control_value[GAME_CONTROL_EXIT] = EL_EXIT_CLOSED; - game_control_value[GAME_CONTROL_EM_EXIT] = EL_EM_EXIT_CLOSED; - game_control_value[GAME_CONTROL_SP_EXIT] = EL_SP_EXIT_CLOSED; - game_control_value[GAME_CONTROL_STEEL_EXIT] = EL_STEEL_EXIT_CLOSED; - game_control_value[GAME_CONTROL_EM_STEEL_EXIT] = EL_EM_STEEL_EXIT_CLOSED; - } - else - { - game_control_value[GAME_CONTROL_EXIT] = EL_EXIT_OPEN; - game_control_value[GAME_CONTROL_EM_EXIT] = EL_EM_EXIT_OPEN; - game_control_value[GAME_CONTROL_SP_EXIT] = EL_SP_EXIT_OPEN; - game_control_value[GAME_CONTROL_STEEL_EXIT] = EL_STEEL_EXIT_OPEN; - game_control_value[GAME_CONTROL_EM_STEEL_EXIT] = EL_EM_STEEL_EXIT_OPEN; - } + game_panel_controls[GAME_PANEL_EXIT].value = + (exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN); - game_control_value[GAME_CONTROL_EMC_MAGIC_BALL] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_EMC_MAGIC_BALL_SWITCH] = EL_UNDEFINED; + game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL].value = + (game.ball_state ? EL_EMC_MAGIC_BALL_ACTIVE : EL_EMC_MAGIC_BALL); + game_panel_controls[GAME_PANEL_EMC_MAGIC_BALL_SWITCH].value = + (game.ball_state ? EL_EMC_MAGIC_BALL_SWITCH_ACTIVE : + EL_EMC_MAGIC_BALL_SWITCH); - game_control_value[GAME_CONTROL_LIGHT_SWITCH] = + game_panel_controls[GAME_PANEL_LIGHT_SWITCH].value = (game.light_time_left > 0 ? EL_LIGHT_SWITCH_ACTIVE : EL_LIGHT_SWITCH); - game_control_value[GAME_CONTROL_LIGHT_SWITCH_TIME] = game.light_time_left; + game_panel_controls[GAME_PANEL_LIGHT_SWITCH_TIME].value = + game.light_time_left; - game_control_value[GAME_CONTROL_TIMEGATE_SWITCH] = + game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH].value = (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED); - game_control_value[GAME_CONTROL_TIMEGATE_SWITCH_TIME] = + game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH_TIME].value = game.timegate_time_left; - game_control_value[GAME_CONTROL_SWITCHGATE_SWITCH] = EL_UNDEFINED; + game_panel_controls[GAME_PANEL_SWITCHGATE_SWITCH].value = + EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; - game_control_value[GAME_CONTROL_EMC_LENSES] = + game_panel_controls[GAME_PANEL_EMC_LENSES].value = (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY); - game_control_value[GAME_CONTROL_EMC_LENSES_TIME] = game.lenses_time_left; + game_panel_controls[GAME_PANEL_EMC_LENSES_TIME].value = + game.lenses_time_left; - game_control_value[GAME_CONTROL_EMC_MAGNIFIER] = + game_panel_controls[GAME_PANEL_EMC_MAGNIFIER].value = (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY); - game_control_value[GAME_CONTROL_EMC_MAGNIFIER_TIME] = game.magnify_time_left; + game_panel_controls[GAME_PANEL_EMC_MAGNIFIER_TIME].value = + game.magnify_time_left; - game_control_value[GAME_CONTROL_BALLOON_SWITCH] = + game_panel_controls[GAME_PANEL_BALLOON_SWITCH].value = (game.wind_direction == MV_LEFT ? EL_BALLOON_SWITCH_LEFT : game.wind_direction == MV_RIGHT ? EL_BALLOON_SWITCH_RIGHT : game.wind_direction == MV_UP ? EL_BALLOON_SWITCH_UP : game.wind_direction == MV_DOWN ? EL_BALLOON_SWITCH_DOWN : EL_BALLOON_SWITCH_NONE); - game_control_value[GAME_CONTROL_DYNABOMB_NUMBER] = + game_panel_controls[GAME_PANEL_DYNABOMB_NUMBER].value = local_player->dynabomb_count; - game_control_value[GAME_CONTROL_DYNABOMB_SIZE] = + game_panel_controls[GAME_PANEL_DYNABOMB_SIZE].value = local_player->dynabomb_size; - game_control_value[GAME_CONTROL_DYNABOMB_POWER] = + game_panel_controls[GAME_PANEL_DYNABOMB_POWER].value = (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY); - game_control_value[GAME_CONTROL_PENGUINS] = + game_panel_controls[GAME_PANEL_PENGUINS].value = local_player->friends_still_needed; - game_control_value[GAME_CONTROL_SOKOBAN_OBJECTS] = + game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = local_player->sokobanfields_still_needed; - game_control_value[GAME_CONTROL_SOKOBAN_FIELDS] = + game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = local_player->sokobanfields_still_needed; - game_control_value[GAME_CONTROL_ROBOT_WHEEL] = EL_UNDEFINED; + game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = + (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); - game_control_value[GAME_CONTROL_CONVEYOR_BELT_1] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_1_SWITCH] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_2] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_2_SWITCH] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_3] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_3_SWITCH] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_4] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_CONVEYOR_BELT_4_SWITCH] = EL_UNDEFINED; + for (i = 0; i < NUM_BELTS; i++) + { + game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1 + i].value = + (game.belt_dir[i] != MV_NONE ? EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE : + EL_CONVEYOR_BELT_1_MIDDLE) + i; + game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1_SWITCH + i].value = + getBeltSwitchElementFromBeltNrAndBeltDir(i, game.belt_dir[i]); + } - game_control_value[GAME_CONTROL_MAGIC_WALL] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_MAGIC_WALL_TIME] = + game_panel_controls[GAME_PANEL_MAGIC_WALL].value = + (game.magic_wall_active ? EL_MAGIC_WALL_ACTIVE : EL_MAGIC_WALL); + game_panel_controls[GAME_PANEL_MAGIC_WALL_TIME].value = game.magic_wall_time_left; - game_control_value[GAME_CONTROL_BD_MAGIC_WALL] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_DC_MAGIC_WALL] = EL_UNDEFINED; - game_control_value[GAME_CONTROL_PLAYER_NAME] = 0; - game_control_value[GAME_CONTROL_LEVEL_NAME] = 0; - game_control_value[GAME_CONTROL_LEVEL_AUTHOR] = 0; +#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; + + for (i = 0; i < NUM_PANEL_ELEMENTS; i++) + game_panel_controls[GAME_PANEL_ELEMENT_1 + i].value = + (IS_DRAWABLE_ELEMENT(game.panel.element[i].id) ? + game.panel.element[i].id : EL_UNDEFINED); + + for (i = 0; i < NUM_PANEL_ELEMENTS; i++) + game_panel_controls[GAME_PANEL_ELEMENT_COUNT_1 + i].value = + (IS_VALID_ELEMENT(game.panel.element_count[i].id) ? + element_info[game.panel.element_count[i].id].element_count : 0); + + for (i = 0; i < NUM_PANEL_CE_SCORE; i++) + game_panel_controls[GAME_PANEL_CE_SCORE_1 + i].value = + (IS_CUSTOM_ELEMENT(game.panel.ce_score[i].id) ? + element_info[game.panel.ce_score[i].id].collect_score : 0); + + for (i = 0; i < NUM_PANEL_CE_SCORE; i++) + game_panel_controls[GAME_PANEL_CE_SCORE_1_ELEMENT + i].value = + (IS_CUSTOM_ELEMENT(game.panel.ce_score_element[i].id) ? + element_info[game.panel.ce_score_element[i].id].collect_score : + EL_UNDEFINED); + + game_panel_controls[GAME_PANEL_PLAYER_NAME].value = 0; + game_panel_controls[GAME_PANEL_LEVEL_NAME].value = 0; + game_panel_controls[GAME_PANEL_LEVEL_AUTHOR].value = 0; + + /* update game panel control frames */ + + for (i = 0; game_panel_controls[i].nr != -1; i++) + { + struct GamePanelControlInfo *gpc = &game_panel_controls[i]; + + if (gpc->type == TYPE_ELEMENT) + { + if (gpc->value != EL_UNDEFINED && gpc->value != EL_EMPTY) + { + int last_anim_random_frame = gfx.anim_random_frame; + int element = gpc->value; + int graphic = el2panelimg(element); + + if (gpc->value != gpc->last_value) + { + gpc->gfx_frame = 0; + gpc->gfx_random = INIT_GFX_RANDOM(); + } + else + { + gpc->gfx_frame++; + + if (ANIM_MODE(graphic) == ANIM_RANDOM && + IS_NEXT_FRAME(gpc->gfx_frame, graphic)) + gpc->gfx_random = INIT_GFX_RANDOM(); + } + + if (ANIM_MODE(graphic) == ANIM_RANDOM) + gfx.anim_random_frame = gpc->gfx_random; + + if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + gpc->gfx_frame = element_info[element].collect_score; + + gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value), + gpc->gfx_frame); + + if (ANIM_MODE(graphic) == ANIM_RANDOM) + gfx.anim_random_frame = last_anim_random_frame; + } + } + } } void DisplayGameControlValues() { + boolean redraw_panel = FALSE; int i; - for (i = 0; game_controls[i].nr != -1; i++) + for (i = 0; game_panel_controls[i].nr != -1; i++) { - int nr = game_controls[i].nr; - int type = game_controls[i].type; - struct TextPosInfo *pos = game_controls[i].pos; - int value = game_control_value[nr]; - int last_value = last_game_control_value[nr]; - int chars = pos->chars; - int font = pos->font; + struct GamePanelControlInfo *gpc = &game_panel_controls[i]; - if (value == last_value) + if (PANEL_DEACTIVATED(gpc->pos)) continue; - last_game_control_value[nr] = value; + if (gpc->value == gpc->last_value && + gpc->frame == gpc->last_frame) + continue; + redraw_panel = TRUE; + } + + if (!redraw_panel) + 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; + +#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 - printf("::: value %d changed from %d to %d\n", nr, last_value, value); + 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; + int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_OPAQUE); 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_CONTROL_LEVEL_NUMBER || nr == GAME_CONTROL_TIME) + if (nr == GAME_PANEL_LEVEL_NUMBER || + nr == GAME_PANEL_TIME) { - boolean use_dynamic_chars = (pos->chars == -1 ? TRUE : FALSE); + boolean use_dynamic_size = (size == -1 ? TRUE : FALSE); - if (use_dynamic_chars) /* use dynamic number of chars */ + if (use_dynamic_size) /* use dynamic number of digits */ { - int value_change = (nr == GAME_CONTROL_LEVEL_NUMBER ? 100 : 1000); - int chars1 = (nr == GAME_CONTROL_LEVEL_NUMBER ? 2 : 3); - int chars2 = chars1 + 1; + int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000); + int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3); + int size2 = size1 + 1; int font1 = pos->font; int font2 = pos->font_alt; - chars = (value < value_change ? chars1 : chars2); - font = (value < value_change ? font1 : font2); + size = (value < value_change ? size1 : size2); + font = (value < value_change ? font1 : font2); - /* clear background if value just changed its size (dynamic chars) */ +#if 0 + /* clear background if value just changed its size (dynamic digits) */ if ((last_value < value_change) != (value < value_change)) { - int width1 = chars1 * getFontWidth(font1); - int width2 = chars2 * getFontWidth(font2); + int width1 = size1 * getFontWidth(font1); + int width2 = size2 * getFontWidth(font2); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); @@ -1961,53 +2632,139 @@ void DisplayGameControlValues() ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), max_width, max_height); } +#endif } - - pos->width = chars * getFontWidth(font); } - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font); +#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); } else if (type == TYPE_ELEMENT) { - if (nr >= GAME_CONTROL_KEY_1 && nr <= GAME_CONTROL_KEY_8) + int element, graphic; + Bitmap *src_bitmap; + int src_x, src_y; + int width, height; + int dst_x = PANEL_XPOS(pos); + int dst_y = PANEL_YPOS(pos); + +#if 1 + if (value != EL_UNDEFINED && value != EL_EMPTY) { - int key_nr = nr - GAME_CONTROL_KEY_1; - int src_x = DOOR_GFX_PAGEX5 + 18 + (key_nr % STD_NUM_KEYS) * MINI_TILEX; - int src_y = DOOR_GFX_PAGEY1 + 123; - int dst_x = PANEL_XPOS(pos); - int dst_y = PANEL_YPOS(pos); - int element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS : - level.game_engine_type == GAME_ENGINE_TYPE_EM ? - EL_EM_KEY_1 : EL_KEY_1) + key_nr; - int graphic = el2edimg(element); + element = value; + graphic = el2panelimg(value); + + // 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); - if (value) - DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); + width = graphic_info[graphic].width * size / TILESIZE; + 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(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, - MINI_TILEX, MINI_TILEY, dst_x, dst_y); + { + 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 if (value != EL_UNDEFINED) + else { - int graphic = el2edimg(value); - int dst_x = PANEL_XPOS(pos); - int dst_y = PANEL_YPOS(pos); + element = value; + graphic = el2panelimg(value); - DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); + 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) { - char *s = (nr == GAME_CONTROL_PLAYER_NAME ? setup.player_name : - nr == GAME_CONTROL_LEVEL_NAME ? level.name : - nr == GAME_CONTROL_LEVEL_AUTHOR ? level.author : NULL); + boolean active = (value != 0); + char *state_normal = "off"; + char *state_active = "on"; + char *state = (active ? state_active : state_normal); + char *s = (nr == GAME_PANEL_GRAVITY_STATE ? state : + nr == GAME_PANEL_PLAYER_NAME ? setup.player_name : + nr == GAME_PANEL_LEVEL_NAME ? level.name : + nr == GAME_PANEL_LEVEL_AUTHOR ? level.author : NULL); + + if (nr == GAME_PANEL_GRAVITY_STATE) + { + 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); + } if (s != NULL) { - char *s_cut = getStringCopyN(s, pos->chars); + char *s_cut; + +#if 1 + if (size <= 0) + { + /* don't truncate output if "chars" is zero or less */ + size = strlen(s); + + /* dynamically correct text alignment */ + pos->width = size * getFontWidth(font); + } +#endif + + s_cut = getStringCopyN(s, size); - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), s_cut, pos->font); + DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), + s_cut, font, mask_mode); free(s_cut); } @@ -2015,6 +2772,17 @@ void DisplayGameControlValues() redraw_mask |= REDRAW_DOOR_1; } + + game_status = GAME_MODE_PLAYING; +} + +void UpdateAndDisplayGameControlValues() +{ + if (tape.warp_forward) + return; + + UpdateGameControlValues(); + DisplayGameControlValues(); } void DrawGameValue_Emeralds(int value) @@ -2026,7 +2794,7 @@ void DrawGameValue_Emeralds(int value) int font_nr = FONT_TEXT_2; #endif int font_width = getFontWidth(font_nr); - int chars = pos->chars; + int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ @@ -2042,14 +2810,14 @@ void DrawGameValue_Emeralds(int value) void DrawGameValue_Dynamite(int value) { - struct TextPosInfo *pos = &game.panel.inventory; + struct TextPosInfo *pos = &game.panel.inventory_count; #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; + int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ @@ -2072,7 +2840,7 @@ void DrawGameValue_Score(int value) int font_nr = FONT_TEXT_2; #endif int font_width = getFontWidth(font_nr); - int chars = pos->chars; + int chars = pos->size; #if 1 return; /* !!! USE NEW STUFF !!! */ @@ -2092,7 +2860,7 @@ void DrawGameValue_Time(int value) static int last_value = -1; int chars1 = 3; int chars2 = 4; - int chars = pos->chars; + int chars = pos->size; #if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; @@ -2142,7 +2910,7 @@ void DrawGameValue_Level(int value) struct TextPosInfo *pos = &game.panel.level_number; int chars1 = 2; int chars2 = 3; - int chars = pos->chars; + int chars = pos->size; #if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; @@ -2290,7 +3058,7 @@ void DrawGameValue_Dynamite(int value) int font_nr = FONT_TEXT_2; int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; - if (PANEL_DEACTIVATED(game.panel.inventory)) + if (PANEL_DEACTIVATED(game.panel.inventory_count)) return; DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); @@ -2400,9 +3168,13 @@ void DrawAllGameValues(int emeralds, int dynamite, int score, int time, DrawGameValue_Keys(key); } -void DrawGameDoorValues() +void UpdateGameDoorValues() { UpdateGameControlValues(); +} + +void DrawGameDoorValues() +{ DisplayGameControlValues(); } @@ -2648,7 +3420,7 @@ static void InitGameEngine() SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE); } - /* ---------- initialize internal run-time variables ------------- */ + /* ---------- initialize internal run-time variables --------------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -2686,6 +3458,27 @@ static void InitGameEngine() } } +#if 1 + /* ---------- initialize reference elements in change conditions --------- */ + + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + struct ElementInfo *ei = &element_info[element]; + + for (j = 0; j < ei->num_change_pages; j++) + { + int trigger_element = ei->change_page[j].initial_trigger_element; + + if (trigger_element >= EL_PREV_CE_8 && + trigger_element <= EL_NEXT_CE_8) + trigger_element = RESOLVED_REFERENCE_ELEMENT(element, trigger_element); + + ei->change_page[j].trigger_element = trigger_element; + } + } +#endif + /* ---------- initialize run-time trigger player and element ------------- */ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -2695,7 +3488,8 @@ static void InitGameEngine() for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].actual_trigger_element = EL_EMPTY; - ei->change_page[j].actual_trigger_player = EL_PLAYER_1; + ei->change_page[j].actual_trigger_player = EL_EMPTY; + ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE; ei->change_page[j].actual_trigger_side = CH_SIDE_NONE; ei->change_page[j].actual_trigger_ce_value = 0; ei->change_page[j].actual_trigger_ce_score = 0; @@ -2875,6 +3669,13 @@ static void InitGameEngine() recursion_loop_depth = 0; recursion_loop_detected = FALSE; recursion_loop_element = EL_UNDEFINED; + + /* ---------- initialize graphics engine ---------------------------------- */ + game.scroll_delay_value = + (game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value : + setup.scroll_delay ? setup.scroll_delay_value : 0); + game.scroll_delay_value = + MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); } int get_num_special_action(int element, int action_first, int action_last) @@ -2916,11 +3717,25 @@ void InitGame() 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; game_status = GAME_MODE_PLAYING; +#if 1 + /* needed if different viewport properties defined for playing */ + ChangeViewportPropertiesIfNeeded(); +#endif + +#if 1 + DrawCompleteVideoDisplay(); +#endif + InitGameEngine(); InitGameControlValues(); @@ -2937,7 +3752,10 @@ void InitGame() player->present = FALSE; player->active = FALSE; + player->mapped = FALSE; + player->killed = FALSE; + player->reanimated = FALSE; player->action = 0; player->effective_action = 0; @@ -2961,18 +3779,19 @@ void InitGame() player->dynabombs_left = 0; player->dynabomb_xl = FALSE; - player->MovDir = MV_NONE; + player->MovDir = initial_move_dir; player->MovPos = 0; player->GfxPos = 0; - player->GfxDir = MV_NONE; + player->GfxDir = initial_move_dir; player->GfxAction = ACTION_DEFAULT; player->Frame = 0; player->StepFrame = 0; - player->use_murphy = FALSE; + player->initial_element = player->element_nr; player->artwork_element = (level.use_artwork_element[i] ? level.artwork_element[i] : player->element_nr); + player->use_murphy = FALSE; player->block_last_field = FALSE; /* initialized in InitPlayerField() */ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ @@ -2985,7 +3804,7 @@ void InitGame() player->step_counter = 0; - player->last_move_dir = MV_NONE; + player->last_move_dir = initial_move_dir; player->is_active = FALSE; @@ -3009,7 +3828,7 @@ void InitGame() player->anim_delay_counter = 0; player->post_delay_counter = 0; - player->dir_waiting = MV_NONE; + player->dir_waiting = initial_move_dir; player->action_waiting = ACTION_DEFAULT; player->last_action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; @@ -3042,6 +3861,26 @@ void InitGame() player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; + if (level.use_initial_inventory[i]) + { + for (j = 0; j < level.initial_inventory_size[i]; j++) + { + int element = level.initial_inventory_content[i][j]; + int collect_count = element_info[element].collect_count_initial; + int k; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = element; + } + } + DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); @@ -3053,6 +3892,10 @@ void InitGame() player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; + player->LevelSolved_CountingTime = 0; + player->LevelSolved_CountingScore = 0; + + map_player_action[i] = i; } network_player_action_received = FALSE; @@ -3081,6 +3924,7 @@ void InitGame() AllPlayersGone = FALSE; game.yamyam_content_nr = 0; + game.robot_wheel_active = FALSE; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; game.light_time_left = 0; @@ -3155,6 +3999,7 @@ void InitGame() GfxElement[x][y] = EL_UNDEFINED; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MV_NONE; + GfxRedraw[x][y] = GFX_REDRAW_NONE; } SCAN_PLAYFIELD(x, y) @@ -3167,6 +4012,8 @@ void InitGame() emulate_sp = FALSE; InitField(x, y, TRUE); + + ResetGfxAnimation(x, y); } InitBeltMovement(); @@ -3241,6 +4088,124 @@ void InitGame() if (game.belt_dir[i] == MV_NONE) game.belt_dir_nr[i] = 3; /* not moving, next moving left */ +#if USE_NEW_PLAYER_ASSIGNMENTS + /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ + /* choose default local player */ + local_player = &stored_player[0]; + + for (i = 0; i < MAX_PLAYERS; i++) + stored_player[i].connected = FALSE; + + local_player->connected = TRUE; + /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ + + if (tape.playing) + { + /* 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; + } + else if (setup.team_mode && !options.network) + { + /* 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 (setup.input[i].use_joystick || + setup.input[i].key.left != KSYM_UNDEFINED) + stored_player[i].connected = TRUE; + } + +#if 0 + for (i = 0; i < MAX_PLAYERS; i++) + printf("::: player %d: %s\n", i, + (stored_player[i].connected ? "connected" : "not connected")); + + for (i = 0; i < MAX_PLAYERS; i++) + printf("::: player %d: %s\n", i, + (stored_player[i].present ? "present" : "not present")); +#endif + + /* check if any connected player was not found in playfield */ + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + if (player->connected && !player->present) + { + struct PlayerInfo *field_player = NULL; + +#if 0 + printf("::: looking for field player for player %d ...\n", i); +#endif + + /* assign first free player found that is present in the playfield */ + + /* 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]; + + if (field_player != NULL) + { + int jx = field_player->jx, jy = field_player->jy; + +#if 0 + printf("::: found player figure %d\n", field_player->index_nr); +#endif + + player->present = FALSE; + player->active = FALSE; + + field_player->present = TRUE; + field_player->active = TRUE; + + /* + player->initial_element = field_player->initial_element; + player->artwork_element = field_player->artwork_element; + + player->block_last_field = field_player->block_last_field; + player->block_delay_adjustment = field_player->block_delay_adjustment; + */ + + StorePlayer[jx][jy] = field_player->element_nr; + + field_player->jx = field_player->last_jx = jx; + field_player->jy = field_player->last_jy = jy; + + if (local_player == player) + local_player = field_player; + + map_player_action[field_player->index_nr] = i; + + field_player->mapped = TRUE; + +#if 0 + printf("::: map_player_action[%d] == %d\n", + field_player->index_nr, i); +#endif + } + } + + if (player->connected && player->present) + player->mapped = TRUE; + } + +#else + /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { @@ -3250,24 +4215,26 @@ void InitGame() { for (j = 0; j < MAX_PLAYERS; j++) { - struct PlayerInfo *some_player = &stored_player[j]; - int jx = some_player->jx, jy = some_player->jy; + struct PlayerInfo *field_player = &stored_player[j]; + int jx = field_player->jx, jy = field_player->jy; /* assign first free player found that is present in the playfield */ - if (some_player->present && !some_player->connected) + if (field_player->present && !field_player->connected) { player->present = TRUE; player->active = TRUE; - some_player->present = FALSE; - some_player->active = FALSE; + field_player->present = FALSE; + field_player->active = FALSE; - player->artwork_element = some_player->artwork_element; + player->initial_element = field_player->initial_element; + player->artwork_element = field_player->artwork_element; - player->block_last_field = some_player->block_last_field; - player->block_delay_adjustment = some_player->block_delay_adjustment; + player->block_last_field = field_player->block_last_field; + player->block_delay_adjustment = field_player->block_delay_adjustment; StorePlayer[jx][jy] = player->element_nr; + player->jx = player->last_jx = jx; player->jy = player->last_jy = jy; @@ -3276,14 +4243,35 @@ void InitGame() } } } +#endif + +#if 0 + printf("::: local_player->present == %d\n", local_player->present); +#endif if (tape.playing) { /* when playing a tape, eliminate all players who do not participate */ +#if USE_NEW_PLAYER_ASSIGNMENTS + for (i = 0; i < MAX_PLAYERS; i++) + { + 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; + + player->active = FALSE; + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_EMPTY; + } + } +#else for (i = 0; i < MAX_PLAYERS; i++) { - if (stored_player[i].active && !tape.player_participates[i]) + if (stored_player[i].active && + !tape.player_participates[i]) { struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; @@ -3293,6 +4281,7 @@ void InitGame() Feld[jx][jy] = EL_EMPTY; } } +#endif } else if (!options.network && !setup.team_mode) /* && !tape.playing */ { @@ -3323,9 +4312,15 @@ void InitGame() /* when recording the game, store which players take part in the game */ if (tape.recording) { +#if USE_NEW_PLAYER_ASSIGNMENTS + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].connected) + tape.player_participates[i] = TRUE; +#else for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) tape.player_participates[i] = TRUE; +#endif } if (options.debug) @@ -3403,7 +4398,8 @@ void InitGame() content = element_info[element].change_page[i].target_element; is_player = ELEM_IS_PLAYER(content); - if (is_player && (found_rating < 3 || element < found_element)) + if (is_player && (found_rating < 3 || + (found_rating == 3 && element < found_element))) { start_x = x; start_y = y; @@ -3420,7 +4416,8 @@ void InitGame() content = element_info[element].content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); - if (is_player && (found_rating < 2 || element < found_element)) + if (is_player && (found_rating < 2 || + (found_rating == 2 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; @@ -3440,7 +4437,8 @@ void InitGame() is_player = ELEM_IS_PLAYER(content); - if (is_player && (found_rating < 1 || element < found_element)) + if (is_player && (found_rating < 1 || + (found_rating == 1 && element < found_element))) { start_x = x + xx - 1; start_y = y + yy - 1; @@ -3471,6 +4469,11 @@ void InitGame() local_player->jy - MIDPOSY); } +#if 0 + /* do not use PLAYING mask for fading out from main screen */ + game_status = GAME_MODE_MAIN; +#endif + StopAnimation(); if (!game.restart_level) @@ -3480,7 +4483,7 @@ void InitGame() if (level_editor_test_game) FadeSkipNextFadeIn(); else - FadeSetStartItem(); + FadeSetEnterScreen(); #else if (level_editor_test_game) fading = fading_none; @@ -3495,6 +4498,10 @@ void InitGame() FadeOut(REDRAW_FIELD); #endif +#if 0 + game_status = GAME_MODE_PLAYING; +#endif + /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -3503,6 +4510,13 @@ void InitGame() /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_EM(backbuffer); } + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + { + InitGameEngine_SP(); + + /* blit playfield from scroll buffer to normal back buffer for fading in */ + BlitScreenToBitmap_SP(backbuffer); + } else { DrawLevel(); @@ -3532,14 +4546,35 @@ void InitGame() 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) { @@ -3796,6 +4831,9 @@ static void PlayerWins(struct PlayerInfo *player) player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : player->score); + + player->LevelSolved_CountingTime = (level.time == 0 ? TimePlayed : TimeLeft); + player->LevelSolved_CountingScore = player->score_final; } void GameWon() @@ -3851,8 +4889,11 @@ void GameWon() score = score_final; #if 1 - game_control_value[GAME_CONTROL_TIME] = time; - game_control_value[GAME_CONTROL_SCORE] = score; + local_player->LevelSolved_CountingTime = time; + local_player->LevelSolved_CountingScore = score; + + game_panel_controls[GAME_PANEL_TIME].value = time; + game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); #else @@ -3933,8 +4974,11 @@ void GameWon() score += time_count_steps * level.score[SC_TIME_BONUS]; #if 1 - game_control_value[GAME_CONTROL_TIME] = time; - game_control_value[GAME_CONTROL_SCORE] = score; + local_player->LevelSolved_CountingTime = time; + local_player->LevelSolved_CountingScore = score; + + game_panel_controls[GAME_PANEL_TIME].value = time; + game_panel_controls[GAME_PANEL_SCORE].value = score; DisplayGameControlValues(); #else @@ -4357,6 +5401,10 @@ static void RemoveField(int x, int y) 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) @@ -4382,7 +5430,7 @@ void RemoveMovingField(int x, int y) Store[oldx][oldy] = Store2[oldx][oldy] = 0; - DrawLevelField(oldx, oldy); + TEST_DrawLevelField(oldx, oldy); return; } @@ -4411,8 +5459,8 @@ void RemoveMovingField(int x, int y) if (next_element != EL_UNDEFINED) Feld[oldx][oldy] = next_element; - DrawLevelField(oldx, oldy); - DrawLevelField(newx, newy); + TEST_DrawLevelField(oldx, oldy); + TEST_DrawLevelField(newx, newy); } void DrawDynamite(int x, int y) @@ -4520,8 +5568,6 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, if (quick_relocation) { - int offset = (setup.scroll_delay ? 3 : 0); - if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen) { if (!level.shifted_relocation || center_screen) @@ -4562,8 +5608,47 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, } 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); + + 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 /* 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); @@ -4579,6 +5664,7 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, /* 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 } RedrawPlayfield(TRUE, 0,0,0,0); @@ -4744,10 +5830,19 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) Feld[jx][jy] = el_player; InitPlayerField(jx, jy, el_player, TRUE); + /* "InitPlayerField()" above sets Feld[jx][jy] to EL_EMPTY, but it may be + possible that the relocation target field did not contain a player element, + but a walkable element, to which the new player was relocated -- in this + case, restore that (already initialized!) element on the player field */ if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */ { - Feld[jx][jy] = 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 */ @@ -4763,6 +5858,21 @@ 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 + a new element to be treated as also switched directly after relocation + (this is important for teleporter switches that teleport the player to + a place where another teleporter switch is in the same direction, which + would then incorrectly be treated as immediately switched before the + direction key that caused the switch was released) */ + + player->switch_x += jx - old_jx; + player->switch_y += jy - old_jy; + } +#endif } void Explode(int ex, int ey, int phase, int mode) @@ -5075,12 +6185,12 @@ void Explode(int ex, int ey, int phase, int mode) InitField_WithBug2(x, y, FALSE); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); if (GFX_CRUMBLED(element)) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present) StorePlayer[x][y] = 0; @@ -5094,7 +6204,7 @@ void Explode(int ex, int ey, int phase, int mode) int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (phase == delay) - DrawLevelFieldCrumbledSand(x, y); + TEST_DrawLevelFieldCrumbled(x, y); if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY) { @@ -5171,8 +6281,12 @@ 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]) { @@ -5283,12 +6397,19 @@ static void InitBeltMovement() for (j = 0; j < NUM_BELT_PARTS; j++) { int element = belt_base_active_element[belt_nr] + j; - int graphic = el2img(element); + int graphic_1 = el2img(element); + int graphic_2 = el2panelimg(element); if (game.belt_dir[i] == MV_LEFT) - graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; + { + graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; + graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; + } else - graphic_info[graphic].anim_mode |= ANIM_REVERSE; + { + graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; + graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; + } } } @@ -5364,12 +6485,19 @@ static void ToggleBeltSwitch(int x, int y) for (i = 0; i < NUM_BELT_PARTS; i++) { int element = belt_base_active_element[belt_nr] + i; - int graphic = el2img(element); + int graphic_1 = el2img(element); + int graphic_2 = el2panelimg(element); if (belt_dir == MV_LEFT) - graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; + { + graphic_info[graphic_1].anim_mode &= ~ANIM_REVERSE; + graphic_info[graphic_2].anim_mode &= ~ANIM_REVERSE; + } else - graphic_info[graphic].anim_mode |= ANIM_REVERSE; + { + graphic_info[graphic_1].anim_mode |= ANIM_REVERSE; + graphic_info[graphic_2].anim_mode |= ANIM_REVERSE; + } } SCAN_PLAYFIELD(xx, yy) @@ -5383,7 +6511,7 @@ static void ToggleBeltSwitch(int x, int y) if (e_belt_nr == belt_nr) { Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } } else if (IS_BELT(element) && belt_dir != MV_NONE) @@ -5395,7 +6523,7 @@ static void ToggleBeltSwitch(int x, int y) int belt_part = Feld[xx][yy] - belt_base_element[belt_nr]; Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } } else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE) @@ -5407,7 +6535,7 @@ static void ToggleBeltSwitch(int x, int y) int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr]; Feld[xx][yy] = belt_base_element[belt_nr] + belt_part; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } } } @@ -5428,34 +6556,34 @@ static void ToggleSwitchgateSwitch(int x, int y) element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; - DrawLevelField(xx, yy); + 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; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } #else if (element == EL_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } else if (element == EL_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_UP) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_DOWN; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } else if (element == EL_DC_SWITCHGATE_SWITCH_DOWN) { Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } #endif else if (element == EL_SWITCHGATE_OPEN || @@ -5503,25 +6631,25 @@ static void RedrawAllLightSwitchesAndInvisibleElements() game.light_time_left > 0) { Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_LIGHT_SWITCH_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_LIGHT_SWITCH; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER && game.light_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.light_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || @@ -5530,11 +6658,11 @@ static void RedrawAllLightSwitchesAndInvisibleElements() if (game.light_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || @@ -5543,11 +6671,11 @@ static void RedrawAllLightSwitchesAndInvisibleElements() if (game.light_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } @@ -5564,13 +6692,13 @@ static void RedrawAllInvisibleElementsForLenses() game.lenses_time_left > 0) { Feld[x][y] = EL_EMC_DRIPPER_ACTIVE; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_EMC_DRIPPER_ACTIVE && game.lenses_time_left == 0) { Feld[x][y] = EL_EMC_DRIPPER; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_INVISIBLE_STEELWALL || element == EL_INVISIBLE_WALL || @@ -5579,11 +6707,11 @@ static void RedrawAllInvisibleElementsForLenses() if (game.lenses_time_left > 0) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); /* uncrumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_INVISIBLE_STEELWALL_ACTIVE || element == EL_INVISIBLE_WALL_ACTIVE || @@ -5592,11 +6720,11 @@ static void RedrawAllInvisibleElementsForLenses() if (game.lenses_time_left == 0) Feld[x][y] = getInvisibleFromInvisibleActiveElement(element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); /* re-crumble neighbour fields, if needed */ if (element == EL_INVISIBLE_SAND) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } @@ -5613,13 +6741,13 @@ static void RedrawAllInvisibleElementsForMagnifier() game.magnify_time_left > 0) { Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_EMC_FAKE_GRASS_ACTIVE && game.magnify_time_left == 0) { Feld[x][y] = EL_EMC_FAKE_GRASS; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY(element) && game.magnify_time_left > 0) @@ -5630,8 +6758,10 @@ static void RedrawAllInvisibleElementsForMagnifier() element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE : IS_EMC_GATE_GRAY(element) ? element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE : + IS_DC_GATE_GRAY(element) ? + EL_DC_GATE_WHITE_GRAY_ACTIVE : element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (IS_GATE_GRAY_ACTIVE(element) && game.magnify_time_left == 0) @@ -5642,8 +6772,10 @@ static void RedrawAllInvisibleElementsForMagnifier() element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY : IS_EMC_GATE_GRAY_ACTIVE(element) ? element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY : + IS_DC_GATE_GRAY_ACTIVE(element) ? + EL_DC_GATE_WHITE_GRAY : element); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } } } @@ -5680,7 +6812,7 @@ static void ActivateTimegateSwitch(int x, int y) else if (element == EL_TIMEGATE_SWITCH_ACTIVE) { Feld[xx][yy] = EL_TIMEGATE_SWITCH; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } */ @@ -5722,7 +6854,7 @@ void Impact(int x, int y) RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_EMPTY; Feld[x][y + 2] = EL_ROCK; - DrawLevelField(x, y + 2); + TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } @@ -5732,7 +6864,7 @@ void Impact(int x, int y) RemoveMovingField(x, y + 1); Feld[x][y + 1] = EL_QUICKSAND_FAST_EMPTY; Feld[x][y + 2] = EL_ROCK; - DrawLevelField(x, y + 2); + TEST_DrawLevelField(x, y + 2); object_hit = TRUE; } @@ -5756,7 +6888,7 @@ void Impact(int x, int y) el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element)) { ResetGfxAnimation(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } if (impact && CAN_EXPLODE_IMPACT(element)) @@ -6230,7 +7362,7 @@ inline static void TurnRoundExt(int x, int y) { Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE; ResetGfxAnimation(move_x, move_y); - DrawLevelField(move_x, move_y); + TEST_DrawLevelField(move_x, move_y); MovDir[x][y] = back_dir; } @@ -6847,10 +7979,18 @@ void StartMoving(int x, int y) else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) { if (!MovDelay[x][y]) + { MovDelay[x][y] = TILEY + 1; + ResetGfxAnimation(x, y); + ResetGfxAnimation(x, y + 1); + } + if (MovDelay[x][y]) { + DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); + DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); + MovDelay[x][y]--; if (MovDelay[x][y]) return; @@ -6861,6 +8001,33 @@ void StartMoving(int x, int y) Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; + PlayLevelSoundAction(x, y, ACTION_FILLING); + } + else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) + { + if (!MovDelay[x][y]) + { + MovDelay[x][y] = TILEY + 1; + + ResetGfxAnimation(x, y); + ResetGfxAnimation(x, y + 1); + } + + if (MovDelay[x][y]) + { + DrawLevelElement(x, y, EL_QUICKSAND_EMPTYING); + DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); + + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + } + + Feld[x][y] = EL_QUICKSAND_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); } } @@ -6884,10 +8051,18 @@ void StartMoving(int x, int y) else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY) { if (!MovDelay[x][y]) + { MovDelay[x][y] = TILEY + 1; + ResetGfxAnimation(x, y); + ResetGfxAnimation(x, y + 1); + } + if (MovDelay[x][y]) { + DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); + DrawLevelElement(x, y + 1, EL_QUICKSAND_FAST_FILLING); + MovDelay[x][y]--; if (MovDelay[x][y]) return; @@ -6898,6 +8073,33 @@ void StartMoving(int x, int y) Store[x][y + 1] = Store[x][y]; Store[x][y] = 0; + PlayLevelSoundAction(x, y, ACTION_FILLING); + } + else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY) + { + if (!MovDelay[x][y]) + { + MovDelay[x][y] = TILEY + 1; + + ResetGfxAnimation(x, y); + ResetGfxAnimation(x, y + 1); + } + + if (MovDelay[x][y]) + { + DrawLevelElement(x, y, EL_QUICKSAND_FAST_EMPTYING); + DrawLevelElement(x, y + 1, EL_QUICKSAND_FILLING); + + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + } + + Feld[x][y] = EL_QUICKSAND_FAST_EMPTY; + Feld[x][y + 1] = EL_QUICKSAND_FULL; + Store[x][y + 1] = Store[x][y]; + Store[x][y] = 0; + PlayLevelSoundAction(x, y, ACTION_FILLING); } } @@ -6936,7 +8138,7 @@ void StartMoving(int x, int y) else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) - MovDelay[x][y] = TILEY/4 + 1; + MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { @@ -6964,7 +8166,7 @@ void StartMoving(int x, int y) else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) - MovDelay[x][y] = TILEY/4 + 1; + MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { @@ -6992,7 +8194,7 @@ void StartMoving(int x, int y) else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE) { if (!MovDelay[x][y]) - MovDelay[x][y] = TILEY/4 + 1; + MovDelay[x][y] = TILEY / 4 + 1; if (MovDelay[x][y]) { @@ -7265,7 +8467,7 @@ void StartMoving(int x, int y) element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON || element == EL_MOLE)) - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } } @@ -7299,7 +8501,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); PlayLevelSoundActionIfLoop(x, y, ACTION_ATTACKING); @@ -7339,7 +8541,7 @@ void StartMoving(int x, int y) if (IN_SCR_FIELD(sx, sy)) { - DrawLevelFieldCrumbledSand(xx, yy); + TEST_DrawLevelFieldCrumbled(xx, yy); DrawGraphic(sx, sy, flame_graphic, frame); } } @@ -7347,7 +8549,7 @@ void StartMoving(int x, int y) { if (Feld[xx][yy] == EL_FLAMES) Feld[xx][yy] = EL_EMPTY; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } } } @@ -7390,7 +8592,7 @@ void StartMoving(int x, int y) Feld[newx][newy] == EL_EM_STEEL_EXIT_OPEN) { RemoveField(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); PlayLevelSound(newx, newy, SND_PENGUIN_PASSING); if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) @@ -7406,7 +8608,7 @@ void StartMoving(int x, int y) else if (IS_FOOD_PENGUIN(Feld[newx][newy])) { if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING) - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); else GfxDir[x][y] = MovDir[x][y] = MV_NONE; } @@ -7417,7 +8619,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); return; } @@ -7431,7 +8633,7 @@ void StartMoving(int x, int y) else { Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_PIG_DIGGING); @@ -7441,7 +8643,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); return; } @@ -7520,7 +8722,7 @@ void StartMoving(int x, int y) else { Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); PlayLevelSoundAction(x, y, ACTION_DIGGING); } @@ -7531,7 +8733,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); #endif return; @@ -7540,6 +8742,10 @@ void StartMoving(int x, int y) 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)) @@ -7568,7 +8774,7 @@ void StartMoving(int x, int y) else { RemoveField(newx, newy); - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); } /* if digged element was about to explode, prevent the explosion */ @@ -7578,6 +8784,7 @@ void StartMoving(int x, int y) } 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))) @@ -7591,6 +8798,8 @@ void StartMoving(int x, int y) Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? new_element : move_leave_element); } +#endif + #endif if (move_pattern & MV_MAZE_RUNNER_STYLE) @@ -7606,7 +8815,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); return; } @@ -7633,7 +8842,7 @@ void StartMoving(int x, int y) if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); PlayLevelSound(x, y, SND_DRAGON_ATTACKING); @@ -7671,7 +8880,7 @@ void StartMoving(int x, int y) else { Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_YAMYAM_DIGGING); @@ -7702,7 +8911,7 @@ void StartMoving(int x, int y) else { Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); } PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING); @@ -7725,7 +8934,7 @@ void StartMoving(int x, int y) ResetGfxAnimation(x, y); GfxAction[x][y] = ACTION_DIGGING; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ @@ -7734,7 +8943,7 @@ void StartMoving(int x, int y) else /* element == EL_PACMAN */ { Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + TEST_DrawLevelField(newx, newy); PlayLevelSound(x, y, SND_PACMAN_DIGGING); } } @@ -7816,7 +9025,7 @@ void ContinueMoving(int x, int y) GfxAction[x][y], GfxDir[x][y], GfxFrame[x][y]); #endif - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); return; /* element is still moving */ } @@ -7835,7 +9044,7 @@ void ContinueMoving(int x, int y) { Feld[x][y] = EL_SAND; - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } else if (element == EL_QUICKSAND_FILLING) { @@ -7944,7 +9153,7 @@ void ContinueMoving(int x, int y) } #if USE_NEW_CUSTOM_VALUE - CustomValue[newx][newy] = CustomValue[x][y]; + CustomValue[newx][newy] = CustomValue[x][y]; #endif ChangeDelay[x][y] = 0; @@ -8002,7 +9211,7 @@ void ContinueMoving(int x, int y) InitField(x, y, FALSE); if (GFX_CRUMBLED(Feld[x][y])) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); if (ELEM_IS_PLAYER(move_leave_element)) RelocatePlayer(x, y, move_leave_element); @@ -8018,8 +9227,8 @@ void ContinueMoving(int x, int y) element_info[element].move_pattern == MV_WHEN_DROPPED))) GfxDir[x][y] = MovDir[newx][newy] = 0; - DrawLevelField(x, y); - DrawLevelField(newx, newy); + TEST_DrawLevelField(x, y); + TEST_DrawLevelField(newx, newy); Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ @@ -8064,6 +9273,11 @@ void ContinueMoving(int x, int y) else if (element == EL_PENGUIN) TestIfFriendTouchesBadThing(newx, newy); + if (DONT_GET_HIT_BY(element)) + { + TestIfGoodThingGetsHitByBadThing(newx, newy, direction); + } + /* give the player one last chance (one more frame) to move away */ if (CAN_FALL(element) && direction == MV_DOWN && (last_line || (!IS_FREE(x, newy + 1) && @@ -8281,7 +9495,7 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) AmoebaNr[x][y] = 0; Feld[x][y] = new_element; InitField(x, y, FALSE); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); done = TRUE; } } @@ -8323,7 +9537,7 @@ void AmoebeWaechst(int x, int y) { Feld[x][y] = Store[x][y]; Store[x][y] = 0; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } } } @@ -8355,7 +9569,7 @@ void AmoebaDisappearing(int x, int y) if (!MovDelay[x][y]) { Feld[x][y] = EL_EMPTY; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); /* don't let mole enter this field in this cycle; (give priority to objects falling to this field from above) */ @@ -8382,7 +9596,7 @@ void AmoebeAbleger(int ax, int ay) if (!level.amoeba_speed && element != EL_EMC_DRIPPER) { Feld[ax][ay] = EL_AMOEBA_DEAD; - DrawLevelField(ax, ay); + TEST_DrawLevelField(ax, ay); return; } @@ -8452,7 +9666,7 @@ void AmoebeAbleger(int ax, int ay) if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA)) { Feld[ax][ay] = EL_AMOEBA_DEAD; - DrawLevelField(ax, ay); + TEST_DrawLevelField(ax, ay); AmoebaCnt[AmoebaNr[ax][ay]]--; if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */ @@ -8516,7 +9730,7 @@ void AmoebeAbleger(int ax, int ay) return; } - DrawLevelField(newax, neway); + TEST_DrawLevelField(newax, neway); } void Life(int ax, int ay) @@ -8574,7 +9788,7 @@ void Life(int ax, int ay) { Feld[xx][yy] = EL_EMPTY; if (!Stop[xx][yy]) - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } @@ -8587,7 +9801,7 @@ void Life(int ax, int ay) Feld[xx][yy] = element; MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); if (!Stop[xx][yy]) - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } @@ -8612,7 +9826,11 @@ static void RunRobotWheel(int x, int y) static void StopRobotWheel(int x, int y) { if (ZX == x && ZY == y) + { ZX = ZY = -1; + + game.robot_wheel_active = FALSE; + } } static void InitTimegateWheel(int x, int y) @@ -8811,9 +10029,6 @@ void DrawTwinkleOnField(int x, int y) { MovDelay[x][y]--; - if (setup.direct_draw && MovDelay[x][y]) - SetDrawtoField(DRAW_BUFFERED); - DrawLevelElementAnimation(x, y, Feld[x][y]); if (MovDelay[x][y] != 0) @@ -8822,18 +10037,6 @@ void DrawTwinkleOnField(int x, int y) 10 - MovDelay[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame); - - if (setup.direct_draw) - { - int dest_x, dest_y; - - dest_x = FX + SCREENX(x) * TILEX; - dest_y = FY + SCREENY(y) * TILEY; - - BlitBitmap(drawto_field, window, - dest_x, dest_y, TILEX, TILEY, dest_x, dest_y); - SetDrawtoField(DRAW_DIRECT); - } } } } @@ -8862,28 +10065,28 @@ void MauerWaechst(int x, int y) if (MovDir[x][y] == MV_LEFT) { if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y])) - DrawLevelField(x - 1, y); + TEST_DrawLevelField(x - 1, y); } else if (MovDir[x][y] == MV_RIGHT) { if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y])) - DrawLevelField(x + 1, y); + TEST_DrawLevelField(x + 1, y); } else if (MovDir[x][y] == MV_UP) { if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1])) - DrawLevelField(x, y - 1); + TEST_DrawLevelField(x, y - 1); } else { if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1])) - DrawLevelField(x, y + 1); + TEST_DrawLevelField(x, y + 1); } Feld[x][y] = Store[x][y]; Store[x][y] = 0; GfxDir[x][y] = MovDir[x][y] = MV_NONE; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } } } @@ -8974,7 +10177,7 @@ void MauerAbleger(int ax, int ay) } if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei)) - DrawLevelField(ax, ay); + TEST_DrawLevelField(ax, ay); if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1])) oben_massiv = TRUE; @@ -9092,7 +10295,7 @@ void MauerAblegerStahl(int ax, int ay) element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) && ((links_massiv && rechts_massiv) || element == EL_EXPANDABLE_STEELWALL_VERTICAL)) - Feld[ax][ay] = EL_WALL; + Feld[ax][ay] = EL_STEELWALL; if (new_wall) PlayLevelSoundAction(ax, ay, ACTION_GROWING); @@ -9138,7 +10341,7 @@ void CheckForDragon(int x, int y) if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES) { Feld[xx][yy] = EL_EMPTY; - DrawLevelField(xx, yy); + TEST_DrawLevelField(xx, yy); } else break; @@ -9202,7 +10405,7 @@ static void ChangeActiveTrap(int x, int y) /* if new animation frame was drawn, correct crumbled sand border */ if (IS_NEW_FRAME(GfxFrame[x][y], graphic)) - DrawLevelFieldCrumbledSand(x, y); + TEST_DrawLevelFieldCrumbled(x, y); } static int getSpecialActionElement(int element, int number, int base_element) @@ -9236,6 +10439,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) int action_type = change->action_type; int action_mode = change->action_mode; int action_arg = change->action_arg; + int action_element = change->action_element; int i; if (!change->has_action) @@ -9247,11 +10451,21 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (level.time > 0 ? TimeLeft : TimePlayed); - int action_arg_element = + int action_arg_element_raw = (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player : action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : + action_arg == CA_ARG_ELEMENT_ACTION ? change->action_element : + action_arg == CA_ARG_INVENTORY_RM_TRIGGER ? change->actual_trigger_element: + action_arg == CA_ARG_INVENTORY_RM_TARGET ? change->target_element : + action_arg == CA_ARG_INVENTORY_RM_ACTION ? change->action_element : 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 && @@ -9308,10 +10522,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element): action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value: + action_arg == CA_ARG_ELEMENT_CV_ACTION ? GET_NEW_CE_VALUE(action_element): action_arg == CA_ARG_ELEMENT_CS_TARGET ? GET_CE_SCORE(target_element) : action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score: + action_arg == CA_ARG_ELEMENT_CS_ACTION ? GET_CE_SCORE(action_element) : action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : + action_arg == CA_ARG_ELEMENT_NR_ACTION ? change->action_element : -1); int action_arg_number_old = @@ -9327,16 +10544,23 @@ 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 && action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER : action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits : + action_arg == CA_ARG_PLAYER_ACTION ? 1 << GET_PLAYER_NR(action_element) : PLAYER_BITS_ANY); /* ---------- execute action -------------------------------------------- */ @@ -9375,7 +10599,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) TimeLeft = action_arg_number_new; #if 1 - game_control_value[GAME_CONTROL_TIME] = TimeLeft; + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else @@ -9395,7 +10619,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) local_player->score = action_arg_number_new; #if 1 - game_control_value[GAME_CONTROL_SCORE] = local_player->score; + game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); #else @@ -9410,7 +10634,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) local_player->gems_still_needed = action_arg_number_new; #if 1 - game_control_value[GAME_CONTROL_GEMS] = local_player->gems_still_needed; + game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); #else @@ -9438,6 +10662,33 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + 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; + } + /* ---------- player actions ------------------------------------------ */ case CA_MOVE_PLAYER: @@ -9492,6 +10743,10 @@ 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)) @@ -9609,6 +10864,104 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + case CA_SET_PLAYER_INVENTORY: + { + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + int j, k; + + if (trigger_player_bits & (1 << i)) + { + int inventory_element = action_arg_element; + + if (action_arg == CA_ARG_ELEMENT_TARGET || + action_arg == CA_ARG_ELEMENT_TRIGGER || + action_arg == CA_ARG_ELEMENT_ACTION) + { + int element = inventory_element; + int collect_count = element_info[element].collect_count_initial; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = + element; + } + else if (action_arg == CA_ARG_INVENTORY_RM_TARGET || + action_arg == CA_ARG_INVENTORY_RM_TRIGGER || + action_arg == CA_ARG_INVENTORY_RM_ACTION) + { + if (player->inventory_infinite_element != EL_UNDEFINED && + IS_EQUAL_OR_IN_GROUP(player->inventory_infinite_element, + action_arg_element_raw)) + player->inventory_infinite_element = EL_UNDEFINED; + + for (k = 0, j = 0; j < player->inventory_size; j++) + { + if (!IS_EQUAL_OR_IN_GROUP(player->inventory_element[j], + action_arg_element_raw)) + player->inventory_element[k++] = player->inventory_element[j]; + } + + player->inventory_size = k; + } + else if (action_arg == CA_ARG_INVENTORY_RM_FIRST) + { + if (player->inventory_size > 0) + { + for (j = 0; j < player->inventory_size - 1; j++) + player->inventory_element[j] = player->inventory_element[j + 1]; + + player->inventory_size--; + } + } + else if (action_arg == CA_ARG_INVENTORY_RM_LAST) + { + if (player->inventory_size > 0) + player->inventory_size--; + } + else if (action_arg == CA_ARG_INVENTORY_RM_ALL) + { + player->inventory_infinite_element = EL_UNDEFINED; + player->inventory_size = 0; + } + else if (action_arg == CA_ARG_INVENTORY_RESET) + { + player->inventory_infinite_element = EL_UNDEFINED; + player->inventory_size = 0; + + if (level.use_initial_inventory[i]) + { + for (j = 0; j < level.initial_inventory_size[i]; j++) + { + int element = level.initial_inventory_content[i][j]; + int collect_count = element_info[element].collect_count_initial; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = + element; + } + } + } + } + } + + break; + } + /* ---------- CE actions ---------------------------------------------- */ case CA_SET_CE_VALUE: @@ -9677,6 +11030,38 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + case CA_SET_CE_ARTWORK: + { + int artwork_element = action_arg_element; + boolean reset_frame = FALSE; + int xx, yy; + + if (action_arg == CA_ARG_ELEMENT_RESET) + artwork_element = (ei->use_gfx_element ? ei->gfx_element_initial : + element); + + if (ei->gfx_element != artwork_element) + reset_frame = TRUE; + + ei->gfx_element = artwork_element; + + SCAN_PLAYFIELD(xx, yy) + { + if (Feld[xx][yy] == element) + { + if (reset_frame) + { + ResetGfxAnimation(xx, yy); + ResetRandomAnimationValue(xx, yy); + } + + TEST_DrawLevelField(xx, yy); + } + } + + break; + } + /* ---------- engine actions ------------------------------------------ */ case CA_SET_ENGINE_SCAN_MODE: @@ -9753,10 +11138,10 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) ResetRandomAnimationValue(x, y); #endif - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); if (GFX_CRUMBLED(new_element)) - DrawLevelFieldCrumbledSandNeighbours(x, y); + TEST_DrawLevelFieldCrumbledNeighbours(x, y); } #if 1 @@ -9836,7 +11221,8 @@ static boolean ChangeElement(int x, int y, int element, int page) { /* reset actual trigger element, trigger player and action element */ change->actual_trigger_element = EL_EMPTY; - change->actual_trigger_player = EL_PLAYER_1; + change->actual_trigger_player = EL_EMPTY; + change->actual_trigger_player_bits = CH_PLAYER_NONE; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; @@ -9996,6 +11382,7 @@ 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]; + boolean handle_action_before_change = FALSE; #ifdef DEBUG if (!CAN_CHANGE_OR_HAS_ACTION(element) && @@ -10078,6 +11465,15 @@ 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) { if (ChangeElement(x, y, element, page)) @@ -10087,7 +11483,7 @@ static void HandleElementChange(int x, int y, int page) } } - if (change->has_action) + if (change->has_action && !handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); } } @@ -10217,11 +11613,17 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)) { change->actual_trigger_element = trigger_element; - change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); + change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); + change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; 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; @@ -10232,6 +11634,21 @@ 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 */ + + 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; @@ -10240,6 +11657,22 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, #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 */ + + 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); } @@ -10257,6 +11690,12 @@ 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 + } } } @@ -10311,6 +11750,10 @@ static boolean CheckElementChangeExt(int x, int y, 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]; @@ -10336,7 +11779,8 @@ static boolean CheckElementChangeExt(int x, int y, IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))) { change->actual_trigger_element = trigger_element; - change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); + change->actual_trigger_player = GET_PLAYER_FROM_BITS(trigger_player); + change->actual_trigger_player_bits = trigger_player; change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); @@ -10577,6 +12021,20 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) } } +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) + { + TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); + SnapField(player, 0, 0); /* stop snapping */ + } + } +} + static byte PlayerActions(struct PlayerInfo *player, byte player_action) { boolean moved = FALSE, snapped = FALSE, dropped = FALSE; @@ -10604,14 +12062,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) moved = MovePlayer(player, dx, dy); } - if (tape.single_step && tape.recording && !tape.pausing) - { - if (button1 || (dropped && !moved)) - { - TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); - SnapField(player, 0, 0); /* stop snapping */ - } - } + CheckSingleStepMode(player); SetPlayerWaiting(player, FALSE); @@ -10635,6 +12086,8 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; + CheckSingleStepMode(player); + return 0; } } @@ -10643,6 +12096,7 @@ static void CheckLevelTime() { int i; + /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ @@ -10660,6 +12114,21 @@ static void CheckLevelTime() level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + { + if (game_sp.LevelSolved && + !game_sp.GameOver) /* game won */ + { + PlayerWins(local_player); + + game_sp.GameOver = TRUE; + + AllPlayersGone = TRUE; + } + + if (game_sp.GameOver) /* game lost */ + AllPlayersGone = TRUE; + } if (TimeFrames >= FRAMES_PER_SECOND) { @@ -10691,7 +12160,7 @@ static void CheckLevelTime() PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); #if 1 - game_control_value[GAME_CONTROL_TIME] = TimeLeft; + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else @@ -10710,7 +12179,7 @@ static void CheckLevelTime() #if 1 else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ { - game_control_value[GAME_CONTROL_TIME] = TimePlayed; + game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } @@ -10727,7 +12196,12 @@ static void CheckLevelTime() DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); } +#if 1 + UpdateAndDisplayGameControlValues(); +#else + UpdateGameDoorValues(); DrawGameDoorValues(); +#endif } void AdvanceFrameAndPlayerCounters(int player_nr) @@ -10830,8 +12304,9 @@ void GameActions() } if (game.restart_level) - StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE); + StartGameActions(options.network, setup.autorecord, level.random_seed); + /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ @@ -10849,6 +12324,21 @@ void GameActions() level.native_em_level->ply[3]->alive == 0) /* all dead */ AllPlayersGone = TRUE; } + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + { + if (game_sp.LevelSolved && + !game_sp.GameOver) /* game won */ + { + PlayerWins(local_player); + + game_sp.GameOver = TRUE; + + AllPlayersGone = TRUE; + } + + if (game_sp.GameOver) /* game lost */ + AllPlayersGone = TRUE; + } if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); @@ -10950,17 +12440,49 @@ void GameActions() if (tape.recording) TapeRecordAction(tape_action); +#if USE_NEW_PLAYER_ASSIGNMENTS + { + byte mapped_action[MAX_PLAYERS]; + + for (i = 0; i < MAX_PLAYERS; i++) + mapped_action[i] = stored_player[map_player_action[i]].effective_action; + + for (i = 0; i < MAX_PLAYERS; i++) + stored_player[i].effective_action = mapped_action[i]; + } +#endif + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { GameActions_EM_Main(); } + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + { + GameActions_SP_Main(); + } else { GameActions_RND(); } } -void GameActions_EM_Main() +void GameActions_EM_Main() +{ + byte effective_action[MAX_PLAYERS]; + boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); + int i; + + for (i = 0; i < MAX_PLAYERS; i++) + effective_action[i] = stored_player[i].effective_action; + + GameActions_EM(effective_action, warp_mode); + + CheckLevelTime(); + + AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ +} + +void GameActions_SP_Main() { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); @@ -10969,7 +12491,7 @@ void GameActions_EM_Main() for (i = 0; i < MAX_PLAYERS; i++) effective_action[i] = stored_player[i].effective_action; - GameActions_EM(effective_action, warp_mode); + GameActions_SP(effective_action, warp_mode); CheckLevelTime(); @@ -11116,7 +12638,7 @@ void GameActions_RND() if (MovDelay[x][y] <= 0) { RemoveField(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); TestIfElementTouchesCustomElement(x, y); /* for empty space */ } @@ -11150,7 +12672,7 @@ void GameActions_RND() if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y)) { ResetGfxAnimation(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } #if DEBUG @@ -11285,7 +12807,7 @@ void GameActions_RND() DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) - DrawTwinkleOnField(x, y); + TEST_DrawTwinkleOnField(x, y); } else if (IS_MOVING(x, y)) ContinueMoving(x, y); @@ -11420,7 +12942,7 @@ void GameActions_RND() DrawLevelGraphicAnimationIfNeeded(x, y, graphic); if (IS_GEM(element) || element == EL_SP_INFOTRON) - DrawTwinkleOnField(x, y); + TEST_DrawTwinkleOnField(x, y); } else if ((element == EL_ACID || element == EL_EXIT_OPEN || @@ -11594,6 +13116,7 @@ void GameActions_RND() if (game.magic_wall_time_left > 0) { game.magic_wall_time_left--; + if (!game.magic_wall_time_left) { SCAN_PLAYFIELD(x, y) @@ -11604,19 +13127,19 @@ void GameActions_RND() element == EL_MAGIC_WALL_FULL) { Feld[x][y] = EL_MAGIC_WALL_DEAD; - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_BD_MAGIC_WALL_ACTIVE || element == EL_BD_MAGIC_WALL_FULL) { Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; - DrawLevelField(x, y); + TEST_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); + TEST_DrawLevelField(x, y); } } @@ -11670,6 +13193,36 @@ 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 !!! */ + + if (GfxRedraw[x][y] & GFX_REDRAW_TILE) + DrawLevelField(x, y); + + if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED) + DrawLevelFieldCrumbled(x, y); + + if (GfxRedraw[x][y] & GFX_REDRAW_TILE_CRUMBLED_NEIGHBOURS) + DrawLevelFieldCrumbledNeighbours(x, y); + + if (GfxRedraw[x][y] & GFX_REDRAW_TILE_TWINKLED) + DrawTwinkleOnField(x, y); + } + + GfxRedraw[x][y] = GFX_REDRAW_NONE; + } +#endif + CheckLevelTime(); DrawAllPlayers(); @@ -11754,12 +13307,13 @@ static boolean AllPlayersInVisibleScreen() void ScrollLevel(int dx, int dy) { -#if 1 +#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 i, x, y; + int x, y; #endif #if 0 @@ -11769,7 +13323,8 @@ void ScrollLevel(int dx, int dy) return; #endif -#if 1 +#if 0 + /* (directly solved in BlitBitmap() now) */ if (bitmap_db_field2 == NULL) bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); @@ -11792,7 +13347,7 @@ void ScrollLevel(int dx, int dy) #else -#if 1 +#if 0 /* !!! DOES NOT WORK FOR DIAGONAL PLAYER RELOCATION !!! */ int xsize = (BX2 - BX1 + 1); int ysize = (BY2 - BY1 + 1); @@ -11813,8 +13368,29 @@ void ScrollLevel(int dx, int dy) #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, @@ -11823,6 +13399,8 @@ void ScrollLevel(int dx, int dy) FX + TILEX * (dx == 1) - softscroll_offset, FY + TILEY * (dy == 1) - softscroll_offset); #endif + +#endif #endif if (dx != 0) @@ -12143,7 +13721,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) #endif { int old_scroll_x = scroll_x, old_scroll_y = scroll_y; - int offset = (setup.scroll_delay ? 3 : 0); + int offset = game.scroll_delay_value; if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) { @@ -12227,7 +13805,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) else if (old_jx == jx && old_jy != jy) player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP); - DrawLevelField(jx, jy); /* for "crumbled sand" */ + TEST_DrawLevelField(jx, jy); /* for "crumbled sand" */ player->last_move_dir = player->MovDir; player->is_moving = TRUE; @@ -12372,8 +13950,14 @@ 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 */ { @@ -12412,8 +13996,13 @@ 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)) @@ -12444,7 +14033,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); #if 1 - game_control_value[GAME_CONTROL_TIME] = TimeLeft; + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else @@ -12458,7 +14047,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) #if 1 else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ { - game_control_value[GAME_CONTROL_TIME] = TimePlayed; + game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } @@ -12540,7 +14129,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y) if (!IN_LEV_FIELD(xx, yy)) continue; - if (IS_PLAYER(x, y)) + if (IS_PLAYER(x, y)) /* player found at center element */ { struct PlayerInfo *player = PLAYERINFO(x, y); @@ -12558,8 +14147,21 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckTriggeredElementChangeByPlayer(xx, yy, border_element, 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 + (example: a level that contains EL_PLAYER_3 as the only player would + incorrectly give EL_PLAYER_1 for "player->element_nr") */ + int player_element = PLAYERINFO(x, y)->initial_element; + + CheckElementChangeBySide(xx, yy, border_element, player_element, + CE_TOUCHING_X, border_side); + } +#endif } - else if (IS_PLAYER(xx, yy)) + else if (IS_PLAYER(xx, yy)) /* player found at border element */ { struct PlayerInfo *player = PLAYERINFO(xx, yy); @@ -12574,6 +14176,20 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CheckTriggeredElementChangeByPlayer(x, y, center_element, 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 + (example: a level that contains EL_PLAYER_3 as the only player would + incorrectly give EL_PLAYER_1 for "player->element_nr") */ + int player_element = PLAYERINFO(xx, yy)->initial_element; + + CheckElementChangeBySide(x, y, center_element, player_element, + CE_TOUCHING_X, center_side); + } +#endif + break; } } @@ -12646,10 +14262,14 @@ void TestIfElementTouchesCustomElement(int x, int y) /* check for change of border element */ CheckElementChangeBySide(xx, yy, border_element, center_element, CE_TOUCHING_X, center_side); + + /* (center element cannot be player, so we dont have to check this here) */ } for (i = 0; i < NUM_DIRECTIONS; i++) { + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; int border_side = trigger_sides[i][1]; int border_element = border_element_old[i]; @@ -12661,6 +14281,20 @@ void TestIfElementTouchesCustomElement(int x, int y) change_center_element = 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, + not the player element that corresponds to the runtime player number + (example: a level that contains EL_PLAYER_3 as the only player would + incorrectly give EL_PLAYER_1 for "player->element_nr") */ + int player_element = PLAYERINFO(xx, yy)->initial_element; + + CheckElementChangeBySide(x, y, center_element, player_element, + CE_TOUCHING_X, border_side); + } +#endif } } @@ -12758,11 +14392,25 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_X, touched_side); - CheckElementChangeBySide(hitx, hity, touched_element, - hitting_element, CE_HIT_BY_X, hitting_side); + CheckElementChangeBySide(hitx, hity, touched_element, hitting_element, + CE_HIT_BY_X, hitting_side); 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, + not the player element that corresponds to the runtime player number + (example: a level that contains EL_PLAYER_3 as the only player would + incorrectly give EL_PLAYER_1 for "player->element_nr") */ + int player_element = PLAYERINFO(hitx, hity)->initial_element; + + CheckElementChangeBySide(x, y, hitting_element, player_element, + CE_HITTING_X, touched_side); + } +#endif } } @@ -12935,6 +14583,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) test_x = bad_x + test_xy[i][0]; test_y = bad_y + test_xy[i][1]; + if (!IN_LEV_FIELD(test_x, test_y)) continue; @@ -12965,12 +14614,14 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) kill_x = test_x; kill_y = test_y; + break; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; + break; } } @@ -12993,6 +14644,63 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) } } +void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir) +{ + int bad_element = Feld[bad_x][bad_y]; + int dx = (bad_move_dir == MV_LEFT ? -1 : bad_move_dir == MV_RIGHT ? +1 : 0); + int dy = (bad_move_dir == MV_UP ? -1 : bad_move_dir == MV_DOWN ? +1 : 0); + int test_x = bad_x + dx, test_y = bad_y + dy; + int test_move_dir, test_element; + int kill_x = -1, kill_y = -1; + + if (!IN_LEV_FIELD(test_x, test_y)) + return; + + test_move_dir = + (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE); + + test_element = Feld[test_x][test_y]; + + if (test_move_dir != bad_move_dir) + { + /* good thing can be player or penguin that does not move away */ + if (IS_PLAYER(test_x, test_y)) + { + struct PlayerInfo *player = PLAYERINFO(test_x, test_y); + + /* (note: in comparison to DONT_RUN_TO and DONT_TOUCH, also handle the + player as being hit when he is moving towards the bad thing, because + the "get hit by" condition would be lost after the player stops) */ + if (player->MovPos != 0 && player->MovDir == bad_move_dir) + return; /* player moves away from bad thing */ + + kill_x = test_x; + kill_y = test_y; + } + else if (test_element == EL_PENGUIN) + { + kill_x = test_x; + kill_y = test_y; + } + } + + if (kill_x != -1 || kill_y != -1) + { + if (IS_PLAYER(kill_x, kill_y)) + { + struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y); + + if (player->shield_deadly_time_left > 0 && + !IS_INDESTRUCTIBLE(bad_element)) + Bang(bad_x, bad_y); + else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y)) + KillPlayer(player); + } + else + Bang(kill_x, kill_y); + } +} + void TestIfPlayerTouchesBadThing(int x, int y) { TestIfGoodThingHitsBadThing(x, y, MV_NONE); @@ -13064,6 +14772,11 @@ void KillPlayer(struct PlayerInfo *player) if (!player->active) return; +#if 0 + printf("::: 0: killed == %d, active == %d, reanimated == %d\n", + player->killed, player->active, player->reanimated); +#endif + /* the following code was introduced to prevent an infinite loop when calling -> Bang() -> CheckTriggeredElementChangeExt() @@ -13088,8 +14801,31 @@ void KillPlayer(struct PlayerInfo *player) player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; +#if 0 + printf("::: 1: killed == %d, active == %d, reanimated == %d\n", + player->killed, player->active, player->reanimated); +#endif + Bang(jx, jy); + +#if 0 + printf("::: 2: killed == %d, active == %d, reanimated == %d\n", + 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) @@ -13130,7 +14866,7 @@ void RemovePlayer(struct PlayerInfo *player) StorePlayer[jx][jy] = 0; if (player->is_moving) - DrawLevelField(player->last_jx, player->last_jy); + TEST_DrawLevelField(player->last_jx, player->last_jy); for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) @@ -13201,9 +14937,9 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, ============================================================================= */ -int DigField(struct PlayerInfo *player, - int oldx, int oldy, int x, int y, - int real_dx, int real_dy, int mode) +static int DigField(struct PlayerInfo *player, + int oldx, int oldy, int x, int y, + int real_dx, int real_dy, int mode) { boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG); boolean player_was_pushing = player->is_pushing; @@ -13358,8 +15094,14 @@ 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) { @@ -13516,7 +15258,7 @@ int DigField(struct PlayerInfo *player, TimeLeft += level.extra_time; #if 1 - game_control_value[GAME_CONTROL_TIME] = TimeLeft; + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else @@ -13601,7 +15343,7 @@ int DigField(struct PlayerInfo *player, local_player->gems_still_needed = 0; #if 1 - game_control_value[GAME_CONTROL_GEMS] = local_player->gems_still_needed; + game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; DisplayGameControlValues(); #else @@ -13682,8 +15424,10 @@ int DigField(struct PlayerInfo *player, if (!(IN_LEV_FIELD(nextx, nexty) && (IS_FREE(nextx, nexty) || - (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY && - IS_SB_ELEMENT(element))))) + (IS_SB_ELEMENT(element) && + Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) || + (IS_CUSTOM_ELEMENT(element) && + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty))))) return MP_NO_ACTION; if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) @@ -13703,6 +15447,13 @@ int DigField(struct PlayerInfo *player, return MP_NO_ACTION; } + if (IS_CUSTOM_ELEMENT(element) && + CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty)) + { + if (!DigFieldByCE(nextx, nexty, element)) + return MP_NO_ACTION; + } + if (IS_SB_ELEMENT(element)) { if (element == EL_SOKOBAN_FIELD_FULL) @@ -13728,8 +15479,13 @@ 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); @@ -13786,7 +15542,9 @@ int DigField(struct PlayerInfo *player, ZX = x; ZY = y; - DrawLevelField(x, y); + game.robot_wheel_active = TRUE; + + TEST_DrawLevelField(x, y); } else if (element == EL_SP_TERMINAL) { @@ -13841,7 +15599,7 @@ int DigField(struct PlayerInfo *player, local_player->lights_still_needed--; ResetGfxAnimation(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_TIME_ORB_FULL) { @@ -13852,7 +15610,7 @@ int DigField(struct PlayerInfo *player, TimeLeft += level.time_orb_time; #if 1 - game_control_value[GAME_CONTROL_TIME] = TimeLeft; + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; DisplayGameControlValues(); #else @@ -13861,7 +15619,7 @@ int DigField(struct PlayerInfo *player, } ResetGfxAnimation(x, y); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); } else if (element == EL_EMC_MAGIC_BALL_SWITCH || element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) @@ -13943,7 +15701,66 @@ int DigField(struct PlayerInfo *player, return MP_MOVING; } -boolean SnapField(struct PlayerInfo *player, int dx, int dy) +static boolean DigFieldByCE(int x, int y, int digging_element) +{ + int element = Feld[x][y]; + + if (!IS_FREE(x, y)) + { + int action = (IS_DIGGABLE(element) ? ACTION_DIGGING : + IS_COLLECTIBLE(element) ? ACTION_COLLECTING : + ACTION_BREAKING); + + /* no element can dig solid indestructible elements */ + if (IS_INDESTRUCTIBLE(element) && + !IS_DIGGABLE(element) && + !IS_COLLECTIBLE(element)) + return FALSE; + + if (AmoebaNr[x][y] && + (element == EL_AMOEBA_FULL || + element == EL_BD_AMOEBA || + element == EL_AMOEBA_GROWING)) + { + AmoebaCnt[AmoebaNr[x][y]]--; + AmoebaCnt2[AmoebaNr[x][y]]--; + } + + if (IS_MOVING(x, y)) + RemoveMovingField(x, y); + else + { + RemoveField(x, y); + TEST_DrawLevelField(x, y); + } + + /* if digged element was about to explode, prevent the explosion */ + ExplodeField[x][y] = EX_TYPE_NONE; + + PlayLevelSoundAction(x, y, action); + } + + 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; +} + +static boolean SnapField(struct PlayerInfo *player, int dx, int dy) { int jx = player->jx, jy = player->jy; int x = jx + dx, y = jy + dy; @@ -14016,19 +15833,22 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) } if (player->MovPos != 0) /* prevent graphic bugs in versions < 2.2.0 */ - DrawLevelField(player->last_jx, player->last_jy); + TEST_DrawLevelField(player->last_jx, player->last_jy); - DrawLevelField(x, y); + TEST_DrawLevelField(x, y); return TRUE; } -boolean DropElement(struct PlayerInfo *player) +static boolean DropElement(struct PlayerInfo *player) { int old_element, new_element; 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 ? @@ -14036,6 +15856,7 @@ boolean DropElement(struct PlayerInfo *player) player->dynabombs_left > 0 ? EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr : EL_UNDEFINED); +#endif player->is_dropping_pressed = TRUE; @@ -14450,6 +16271,21 @@ void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) } } +void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) +{ + int element = map_element_SP_to_RND(element_sp); + int action = map_action_SP_to_RND(action_sp); + int offset = (setup.sp_show_border_elements ? 0 : 1); + int x = xx - offset; + int y = yy - offset; + +#if 0 + printf("::: %d -> %d\n", element_sp, action_sp); +#endif + + PlayLevelSoundElementAction(x, y, element, action); +} + #if 0 void ChangeTime(int value) { @@ -14480,7 +16316,7 @@ void RaiseScore(int value) local_player->score += value; #if 1 - game_control_value[GAME_CONTROL_SCORE] = local_player->score; + game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; DisplayGameControlValues(); #else @@ -14673,8 +16509,6 @@ unsigned int RND(int max) /* game engine snapshot handling functions */ /* ------------------------------------------------------------------------- */ -#define ARGS_ADDRESS_AND_SIZEOF(x) (&(x)), (sizeof(x)) - struct EngineSnapshotInfo { /* runtime values for custom element collect score */ @@ -14684,32 +16518,14 @@ struct EngineSnapshotInfo int choice_pos[NUM_GROUP_ELEMENTS]; /* runtime values for belt position animations */ - int belt_graphic[4 * NUM_BELT_PARTS]; - int belt_anim_mode[4 * NUM_BELT_PARTS]; -}; - -struct EngineSnapshotNodeInfo -{ - void *buffer_orig; - void *buffer_copy; - int size; + int belt_graphic[4][NUM_BELT_PARTS]; + int belt_anim_mode[4][NUM_BELT_PARTS]; }; static struct EngineSnapshotInfo engine_snapshot_rnd; -static ListNode *engine_snapshot_list = NULL; static char *snapshot_level_identifier = NULL; static int snapshot_level_nr = -1; -void FreeEngineSnapshot() -{ - while (engine_snapshot_list != NULL) - deleteNodeFromList(&engine_snapshot_list, engine_snapshot_list->key, - checked_free); - - setString(&snapshot_level_identifier, NULL); - snapshot_level_nr = -1; -} - static void SaveEngineSnapshotValues_RND() { static int belt_base_active_element[4] = @@ -14743,8 +16559,8 @@ static void SaveEngineSnapshotValues_RND() int graphic = el2img(element); int anim_mode = graphic_info[graphic].anim_mode; - engine_snapshot_rnd.belt_graphic[i * 4 + j] = graphic; - engine_snapshot_rnd.belt_anim_mode[i * 4 + j] = anim_mode; + engine_snapshot_rnd.belt_graphic[i][j] = graphic; + engine_snapshot_rnd.belt_anim_mode[i][j] = anim_mode; } } } @@ -14772,8 +16588,8 @@ static void LoadEngineSnapshotValues_RND() { for (j = 0; j < NUM_BELT_PARTS; j++) { - int graphic = engine_snapshot_rnd.belt_graphic[i * 4 + j]; - int anim_mode = engine_snapshot_rnd.belt_anim_mode[i * 4 + j]; + int graphic = engine_snapshot_rnd.belt_graphic[i][j]; + int anim_mode = engine_snapshot_rnd.belt_anim_mode[i][j]; graphic_info[graphic].anim_mode = anim_mode; } @@ -14795,36 +16611,26 @@ static void LoadEngineSnapshotValues_RND() } } -static void SaveEngineSnapshotBuffer(void *buffer, int size) -{ - struct EngineSnapshotNodeInfo *bi = - checked_calloc(sizeof(struct EngineSnapshotNodeInfo)); - - bi->buffer_orig = buffer; - bi->buffer_copy = checked_malloc(size); - bi->size = size; - - memcpy(bi->buffer_copy, buffer, size); - - addNodeToList(&engine_snapshot_list, NULL, bi); -} - void SaveEngineSnapshot() { - FreeEngineSnapshot(); /* free previous snapshot, if needed */ - - if (level_editor_test_game) /* do not save snapshots from editor */ + /* do not save snapshots from editor */ + if (level_editor_test_game) return; + /* free previous snapshot buffers, if needed */ + FreeEngineSnapshotBuffers(); + /* 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)); /* save further RND engine values */ @@ -14898,7 +16704,7 @@ void SaveEngineSnapshot() snapshot_level_nr = level_nr; #if 0 - ListNode *node = engine_snapshot_list; + ListNode *node = engine_snapshot_list_rnd; int num_bytes = 0; while (node != NULL) @@ -14912,29 +16718,17 @@ void SaveEngineSnapshot() #endif } -static void LoadEngineSnapshotBuffer(struct EngineSnapshotNodeInfo *bi) -{ - memcpy(bi->buffer_orig, bi->buffer_copy, bi->size); -} - void LoadEngineSnapshot() { - ListNode *node = engine_snapshot_list; - - if (engine_snapshot_list == NULL) - return; + /* restore generically stored snapshot buffers */ - while (node != NULL) - { - LoadEngineSnapshotBuffer((struct EngineSnapshotNodeInfo *)node->content); - - node = node->next; - } + LoadEngineSnapshotBuffers(); /* restore special values from snapshot structure */ LoadEngineSnapshotValues_RND(); LoadEngineSnapshotValues_EM(); + LoadEngineSnapshotValues_SP(); } boolean CheckEngineSnapshot() @@ -14946,98 +16740,38 @@ boolean CheckEngineSnapshot() /* ---------- new game button stuff ---------------------------------------- */ -/* graphic position values for game buttons */ -#define GAME_BUTTON_XSIZE 30 -#define GAME_BUTTON_YSIZE 30 -#define GAME_BUTTON_XPOS 5 -#define GAME_BUTTON_YPOS 215 -#define SOUND_BUTTON_XPOS 5 -#define SOUND_BUTTON_YPOS (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE) - -#define GAME_BUTTON_STOP_XPOS (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) -#define GAME_BUTTON_PAUSE_XPOS (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) -#define GAME_BUTTON_PLAY_XPOS (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) -#define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) -#define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) -#define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) - static struct { - int *x, *y; - int gd_x, gd_y; + int graphic; + struct Rect *pos; 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, - "stop game" + IMG_GAME_BUTTON_GFX_STOP, &game.button.stop, + GAME_CTRL_ID_STOP, "stop game" }, { - GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS, - GAME_CTRL_ID_PAUSE, - "pause game" + IMG_GAME_BUTTON_GFX_PAUSE, &game.button.pause, + GAME_CTRL_ID_PAUSE, "pause game" }, { - GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS, - GAME_CTRL_ID_PLAY, - "play game" + IMG_GAME_BUTTON_GFX_PLAY, &game.button.play, + GAME_CTRL_ID_PLAY, "play game" }, { - SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS, - SOUND_CTRL_ID_MUSIC, - "background music on/off" + IMG_GAME_BUTTON_GFX_SOUND_MUSIC, &game.button.sound_music, + SOUND_CTRL_ID_MUSIC, "background music on/off" }, { - SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS, - SOUND_CTRL_ID_LOOPS, - "sound loops on/off" + IMG_GAME_BUTTON_GFX_SOUND_LOOPS, &game.button.sound_loops, + SOUND_CTRL_ID_LOOPS, "sound loops on/off" }, { - SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS, - SOUND_CTRL_ID_SIMPLE, - "normal sounds on/off" + IMG_GAME_BUTTON_GFX_SOUND_SIMPLE, &game.button.sound_simple, + SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" } -#endif }; void CreateGameButtons() @@ -15046,23 +16780,22 @@ void CreateGameButtons() for (i = 0; i < NUM_GAME_BUTTONS; i++) { - Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; + struct GraphicInfo *gfx = &graphic_info[gamebutton_info[i].graphic]; + struct Rect *pos = gamebutton_info[i].pos; struct GadgetInfo *gi; 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 gd_x = gfx->src_x; + int gd_y = gfx->src_y; + int gd_xp = gfx->src_x + gfx->pressed_xoffset; + int gd_yp = gfx->src_y + gfx->pressed_yoffset; + int gd_xa = gfx->src_x + gfx->active_xoffset; + int gd_ya = gfx->src_y + gfx->active_yoffset; + int gd_xap = gfx->src_x + gfx->active_xoffset + gfx->pressed_xoffset; + int gd_yap = gfx->src_y + gfx->active_yoffset + gfx->pressed_yoffset; int id = i; - 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; - if (id == GAME_CTRL_ID_STOP || id == GAME_CTRL_ID_PAUSE || id == GAME_CTRL_ID_PLAY) @@ -15070,8 +16803,6 @@ void CreateGameButtons() button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; event_mask = GD_EVENT_RELEASED; - gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; - gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; } else { @@ -15081,28 +16812,22 @@ void CreateGameButtons() (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) || (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE); event_mask = GD_EVENT_PRESSED; - gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset; - gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE; } 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_X, DX + pos->x, + GDI_Y, DY + pos->y, + GDI_WIDTH, gfx->width, + GDI_HEIGHT, gfx->height, GDI_TYPE, button_type, GDI_STATE, GD_BUTTON_UNPRESSED, GDI_CHECKED, checked, - GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1, - GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1, - GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2, - GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2, + GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y, + GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp, + GDI_ALT_DESIGN_UNPRESSED, gfx->bitmap, gd_xa, gd_ya, + GDI_ALT_DESIGN_PRESSED, gfx->bitmap, gd_xap, gd_yap, + GDI_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleGameButtons, GDI_END); @@ -15138,10 +16863,16 @@ void UnmapGameButtons() UnmapGadget(game_gadget[i]); } -static void HandleGameButtons(struct GadgetInfo *gi) +void RedrawGameButtons() { - int id = gi->custom_id; + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + RedrawGadget(game_gadget[i]); +} +static void HandleGameButtonsExt(int id) +{ if (game_status != GAME_MODE_PLAYING) return; @@ -15187,6 +16918,7 @@ static void HandleGameButtons(struct GadgetInfo *gi) if (setup.sound_music) { setup.sound_music = FALSE; + FadeMusic(); } else if (audio.music_available) @@ -15205,6 +16937,7 @@ static void HandleGameButtons(struct GadgetInfo *gi) else if (audio.loops_available) { setup.sound = setup.sound_loops = TRUE; + SetAudioMode(setup.sound); } break; @@ -15215,6 +16948,7 @@ static void HandleGameButtons(struct GadgetInfo *gi) else if (audio.sound_available) { setup.sound = setup.sound_simple = TRUE; + SetAudioMode(setup.sound); } break; @@ -15223,3 +16957,27 @@ static void HandleGameButtons(struct GadgetInfo *gi) break; } } + +static void HandleGameButtons(struct GadgetInfo *gi) +{ + HandleGameButtonsExt(gi->custom_id); +} + +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 +}