X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=88bca397acab2ff7622569e1dbe4056d7d36052c;hb=ffe5b4f7f8db01217558b2de54edc2f54eb75f03;hp=593a8bac409ac4b4a1f45cf0fc957ffe0d49ec56;hpb=884012f34f9f3c22bf75d1468e4ed57d7795a24b;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 593a8bac..88bca397 100644 --- a/src/game.c +++ b/src/game.c @@ -128,451 +128,718 @@ #define DX_TIME (DX + XX_TIME) #define DY_TIME (DY + YY_TIME) -#if 0 +#if 1 /* game panel display and control definitions */ -#define GAME_CONTROL_LEVEL 0 -#define GAME_CONTROL_GEMS 1 -#define GAME_CONTROL_INVENTORY 2 -#define GAME_CONTROL_KEY_1 3 -#define GAME_CONTROL_KEY_2 4 -#define GAME_CONTROL_KEY_3 5 -#define GAME_CONTROL_KEY_4 6 -#define GAME_CONTROL_KEY_5 7 -#define GAME_CONTROL_KEY_6 8 -#define GAME_CONTROL_KEY_7 9 -#define GAME_CONTROL_KEY_8 10 -#define GAME_CONTROL_KEY_WHITE 11 -#define GAME_CONTROL_KEY_WHITE_COUNT 12 -#define GAME_CONTROL_SCORE 13 -#define GAME_CONTROL_TIME 14 -#define GAME_CONTROL_TIME_HH 15 -#define GAME_CONTROL_TIME_MM 16 -#define GAME_CONTROL_TIME_SS 17 -#define GAME_CONTROL_DROP_NEXT_1 18 -#define GAME_CONTROL_DROP_NEXT_2 19 -#define GAME_CONTROL_DROP_NEXT_3 20 -#define GAME_CONTROL_DROP_NEXT_4 21 -#define GAME_CONTROL_DROP_NEXT_5 22 -#define GAME_CONTROL_DROP_NEXT_6 23 -#define GAME_CONTROL_DROP_NEXT_7 24 -#define GAME_CONTROL_DROP_NEXT_8 25 -#define GAME_CONTROL_SHIELD_NORMAL 26 -#define GAME_CONTROL_SHIELD_NORMAL_TIME 27 -#define GAME_CONTROL_SHIELD_DEADLY 28 -#define GAME_CONTROL_SHIELD_DEADLY_TIME 29 -#define GAME_CONTROL_EXIT 30 -#define GAME_CONTROL_EM_EXIT 31 -#define GAME_CONTROL_SP_EXIT 32 -#define GAME_CONTROL_STEEL_EXIT 33 -#define GAME_CONTROL_EM_STEEL_EXIT 34 -#define GAME_CONTROL_EMC_MAGIC_BALL 35 -#define GAME_CONTROL_EMC_MAGIC_BALL_TIME 36 -#define GAME_CONTROL_LIGHT_SWITCH 37 -#define GAME_CONTROL_LIGHT_SWITCH_TIME 38 -#define GAME_CONTROL_TIMEGATE_SWITCH 39 -#define GAME_CONTROL_TIMEGATE_SWITCH_TIME 40 -#define GAME_CONTROL_SWITCHGATE_SWITCH 41 -#define GAME_CONTROL_EMC_LENSES 42 -#define GAME_CONTROL_EMC_LENSES_TIME 43 -#define GAME_CONTROL_EMC_MAGNIFIER 44 -#define GAME_CONTROL_EMC_MAGNIFIER_TIME 45 -#define GAME_CONTROL_BALLOON_SWITCH 46 -#define GAME_CONTROL_DYNABOMB_NUMBER 47 -#define GAME_CONTROL_DYNABOMB_SIZE 48 -#define GAME_CONTROL_DYNABOMB_POWER 49 -#define GAME_CONTROL_PENGUINS 50 -#define GAME_CONTROL_SOKOBAN_OBJECTS 51 -#define GAME_CONTROL_SOKOBAN_FIELDS 52 -#define GAME_CONTROL_ROBOT_WHEEL 53 -#define GAME_CONTROL_CONVEYOR_BELT_1 54 -#define GAME_CONTROL_CONVEYOR_BELT_1_SWITCH 55 -#define GAME_CONTROL_CONVEYOR_BELT_2 56 -#define GAME_CONTROL_CONVEYOR_BELT_2_SWITCH 57 -#define GAME_CONTROL_CONVEYOR_BELT_3 58 -#define GAME_CONTROL_CONVEYOR_BELT_3_SWITCH 59 -#define GAME_CONTROL_CONVEYOR_BELT_4 60 -#define GAME_CONTROL_CONVEYOR_BELT_4_SWITCH 61 -#define GAME_CONTROL_MAGIC_WALL 62 -#define GAME_CONTROL_MAGIC_WALL_TIME 63 -#define GAME_CONTROL_BD_MAGIC_WALL 64 -#define GAME_CONTROL_DC_MAGIC_WALL 65 -#define GAME_CONTROL_PLAYER_NAME 66 -#define GAME_CONTROL_LEVEL_NAME 67 -#define GAME_CONTROL_LEVEL_AUTHOR 68 - -struct GameControlInfo +#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_SHIELD_NORMAL 35 +#define GAME_PANEL_SHIELD_NORMAL_TIME 36 +#define GAME_PANEL_SHIELD_DEADLY 37 +#define GAME_PANEL_SHIELD_DEADLY_TIME 38 +#define GAME_PANEL_EXIT 39 +#define GAME_PANEL_EMC_MAGIC_BALL 40 +#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH 41 +#define GAME_PANEL_LIGHT_SWITCH 42 +#define GAME_PANEL_LIGHT_SWITCH_TIME 43 +#define GAME_PANEL_TIMEGATE_SWITCH 44 +#define GAME_PANEL_TIMEGATE_SWITCH_TIME 45 +#define GAME_PANEL_SWITCHGATE_SWITCH 46 +#define GAME_PANEL_EMC_LENSES 47 +#define GAME_PANEL_EMC_LENSES_TIME 48 +#define GAME_PANEL_EMC_MAGNIFIER 49 +#define GAME_PANEL_EMC_MAGNIFIER_TIME 50 +#define GAME_PANEL_BALLOON_SWITCH 51 +#define GAME_PANEL_DYNABOMB_NUMBER 52 +#define GAME_PANEL_DYNABOMB_SIZE 53 +#define GAME_PANEL_DYNABOMB_POWER 54 +#define GAME_PANEL_PENGUINS 55 +#define GAME_PANEL_SOKOBAN_OBJECTS 56 +#define GAME_PANEL_SOKOBAN_FIELDS 57 +#define GAME_PANEL_ROBOT_WHEEL 58 +#define GAME_PANEL_CONVEYOR_BELT_1 59 +#define GAME_PANEL_CONVEYOR_BELT_2 60 +#define GAME_PANEL_CONVEYOR_BELT_3 61 +#define GAME_PANEL_CONVEYOR_BELT_4 62 +#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH 63 +#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH 64 +#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH 65 +#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH 66 +#define GAME_PANEL_MAGIC_WALL 67 +#define GAME_PANEL_MAGIC_WALL_TIME 68 +#define GAME_PANEL_GRAVITY_STATE 69 +#define GAME_PANEL_GRAPHIC_1 70 +#define GAME_PANEL_GRAPHIC_2 71 +#define GAME_PANEL_GRAPHIC_3 72 +#define GAME_PANEL_GRAPHIC_4 73 +#define GAME_PANEL_GRAPHIC_5 74 +#define GAME_PANEL_GRAPHIC_6 75 +#define GAME_PANEL_GRAPHIC_7 76 +#define GAME_PANEL_GRAPHIC_8 77 +#define GAME_PANEL_ELEMENT_1 78 +#define GAME_PANEL_ELEMENT_2 79 +#define GAME_PANEL_ELEMENT_3 80 +#define GAME_PANEL_ELEMENT_4 81 +#define GAME_PANEL_ELEMENT_5 82 +#define GAME_PANEL_ELEMENT_6 83 +#define GAME_PANEL_ELEMENT_7 84 +#define GAME_PANEL_ELEMENT_8 85 +#define GAME_PANEL_ELEMENT_COUNT_1 86 +#define GAME_PANEL_ELEMENT_COUNT_2 87 +#define GAME_PANEL_ELEMENT_COUNT_3 88 +#define GAME_PANEL_ELEMENT_COUNT_4 89 +#define GAME_PANEL_ELEMENT_COUNT_5 90 +#define GAME_PANEL_ELEMENT_COUNT_6 91 +#define GAME_PANEL_ELEMENT_COUNT_7 92 +#define GAME_PANEL_ELEMENT_COUNT_8 93 +#define GAME_PANEL_CE_SCORE_1 94 +#define GAME_PANEL_CE_SCORE_2 95 +#define GAME_PANEL_CE_SCORE_3 96 +#define GAME_PANEL_CE_SCORE_4 97 +#define GAME_PANEL_CE_SCORE_5 98 +#define GAME_PANEL_CE_SCORE_6 99 +#define GAME_PANEL_CE_SCORE_7 100 +#define GAME_PANEL_CE_SCORE_8 101 +#define GAME_PANEL_CE_SCORE_1_ELEMENT 102 +#define GAME_PANEL_CE_SCORE_2_ELEMENT 103 +#define GAME_PANEL_CE_SCORE_3_ELEMENT 104 +#define GAME_PANEL_CE_SCORE_4_ELEMENT 105 +#define GAME_PANEL_CE_SCORE_5_ELEMENT 106 +#define GAME_PANEL_CE_SCORE_6_ELEMENT 107 +#define GAME_PANEL_CE_SCORE_7_ELEMENT 108 +#define GAME_PANEL_CE_SCORE_8_ELEMENT 109 +#define GAME_PANEL_PLAYER_NAME 110 +#define GAME_PANEL_LEVEL_NAME 111 +#define GAME_PANEL_LEVEL_AUTHOR 112 + +#define NUM_GAME_PANEL_CONTROLS 113 + +struct GamePanelOrderInfo +{ + int nr; + int sort_priority; +}; + +static struct GamePanelOrderInfo game_panel_order[NUM_GAME_PANEL_CONTROLS]; + +struct GamePanelControlInfo { int nr; - struct TextPosInfo *pos_text; + struct TextPosInfo *pos; int type; - void *ptr; + + 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, - &game.panel.level, + 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_KEYS, - &game.panel.keys, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_1, + &game.panel.inventory_first[0], + TYPE_ELEMENT, }, { - GAME_CONTROL_SCORE, - &game.panel.score, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_2, + &game.panel.inventory_first[1], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME, - &game.panel.time, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_3, + &game.panel.inventory_first[2], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_HH, - &game.panel.time_hh, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_4, + &game.panel.inventory_first[3], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_MM, - &game.panel.time_mm, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_5, + &game.panel.inventory_first[4], + TYPE_ELEMENT, }, { - GAME_CONTROL_TIME_SS, - &game.panel.time_ss, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_6, + &game.panel.inventory_first[5], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_1, - &game.panel.drop_next_1, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_7, + &game.panel.inventory_first[6], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_2, - &game.panel.drop_next_2, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_FIRST_8, + &game.panel.inventory_first[7], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_3, - &game.panel.drop_next_3, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_1, + &game.panel.inventory_last[0], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_4, - &game.panel.drop_next_4, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_2, + &game.panel.inventory_last[1], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_5, - &game.panel.drop_next_5, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_3, + &game.panel.inventory_last[2], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_6, - &game.panel.drop_next_6, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_4, + &game.panel.inventory_last[3], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_7, - &game.panel.drop_next_7, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_5, + &game.panel.inventory_last[4], + TYPE_ELEMENT, }, { - GAME_CONTROL_DROP_NEXT_8, - &game.panel.drop_next_8, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_6, + &game.panel.inventory_last[5], + TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_KEYS, - &game.panel.emc_keys, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_7, + &game.panel.inventory_last[6], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_1, - &game.panel.key_1, - TYPE_INTEGER, + GAME_PANEL_INVENTORY_LAST_8, + &game.panel.inventory_last[7], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_2, - &game.panel.key_2, - TYPE_INTEGER, + GAME_PANEL_KEY_1, + &game.panel.key[0], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_3, - &game.panel.key_3, - TYPE_INTEGER, + GAME_PANEL_KEY_2, + &game.panel.key[1], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_4, - &game.panel.key_4, - TYPE_INTEGER, + GAME_PANEL_KEY_3, + &game.panel.key[2], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_5, - &game.panel.key_5, - TYPE_INTEGER, + GAME_PANEL_KEY_4, + &game.panel.key[3], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_6, - &game.panel.key_6, - TYPE_INTEGER, + GAME_PANEL_KEY_5, + &game.panel.key[4], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_7, - &game.panel.key_7, - TYPE_INTEGER, + GAME_PANEL_KEY_6, + &game.panel.key[5], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_8, - &game.panel.key_8, - TYPE_INTEGER, + GAME_PANEL_KEY_7, + &game.panel.key[6], + TYPE_ELEMENT, + }, + { + GAME_PANEL_KEY_8, + &game.panel.key[7], + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_WHITE, + GAME_PANEL_KEY_WHITE, &game.panel.key_white, - TYPE_INTEGER, + TYPE_ELEMENT, }, { - GAME_CONTROL_KEY_WHITE_COUNT, + GAME_PANEL_KEY_WHITE_COUNT, &game.panel.key_white_count, TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_NORMAL, - &game.panel.shield_normal, + GAME_PANEL_SCORE, + &game.panel.score, TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_NORMAL_TIME, - &game.panel.shield_normal_time, + GAME_PANEL_HIGHSCORE, + &game.panel.highscore, TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_DEADLY, - &game.panel.shield_deadly, + GAME_PANEL_TIME, + &game.panel.time, TYPE_INTEGER, }, { - GAME_CONTROL_SHIELD_DEADLY_TIME, - &game.panel.shield_deadly_time, + GAME_PANEL_TIME_HH, + &game.panel.time_hh, TYPE_INTEGER, }, { - GAME_CONTROL_EXIT, - &game.panel.exit, + GAME_PANEL_TIME_MM, + &game.panel.time_mm, TYPE_INTEGER, }, { - GAME_CONTROL_EM_EXIT, - &game.panel.em_exit, + GAME_PANEL_TIME_SS, + &game.panel.time_ss, TYPE_INTEGER, }, { - GAME_CONTROL_SP_EXIT, - &game.panel.sp_exit, - 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_CONTROL_EM_STEEL_EXIT, - &game.panel.em_steel_exit, + GAME_PANEL_SHIELD_DEADLY, + &game.panel.shield_deadly, + TYPE_ELEMENT, + }, + { + GAME_PANEL_SHIELD_DEADLY_TIME, + &game.panel.shield_deadly_time, TYPE_INTEGER, }, { - GAME_CONTROL_EMC_MAGIC_BALL, + GAME_PANEL_EXIT, + &game.panel.exit, + TYPE_ELEMENT, + }, + { + GAME_PANEL_EMC_MAGIC_BALL, &game.panel.emc_magic_ball, - TYPE_INTEGER, + TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_MAGIC_BALL_TIME, - &game.panel.emc_magic_ball_time, - TYPE_INTEGER, + 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_INTEGER, + 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_INTEGER, + 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_INTEGER, + TYPE_ELEMENT, }, { - GAME_CONTROL_EMC_LENSES, + GAME_PANEL_EMC_LENSES, &game.panel.emc_lenses, - TYPE_INTEGER, + 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_INTEGER, + 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_INTEGER, + 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_INTEGER, + 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_PANEL_CONVEYOR_BELT_1, + &game.panel.conveyor_belt[0], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_2, + &game.panel.conveyor_belt[1], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_3, + &game.panel.conveyor_belt[2], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_4, + &game.panel.conveyor_belt[3], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_1_SWITCH, + &game.panel.conveyor_belt_switch[0], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_2_SWITCH, + &game.panel.conveyor_belt_switch[1], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_3_SWITCH, + &game.panel.conveyor_belt_switch[2], + TYPE_ELEMENT, + }, + { + GAME_PANEL_CONVEYOR_BELT_4_SWITCH, + &game.panel.conveyor_belt_switch[3], + TYPE_ELEMENT, + }, + { + GAME_PANEL_MAGIC_WALL, + &game.panel.magic_wall, + TYPE_ELEMENT, + }, + { + GAME_PANEL_MAGIC_WALL_TIME, + &game.panel.magic_wall_time, TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_1, - &game.panel.conveyor_belt_1, + 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_CONTROL_CONVEYOR_BELT_1_SWITCH, - &game.panel.conveyor_belt_1_switch, + GAME_PANEL_ELEMENT_COUNT_2, + &game.panel.element_count[1], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_2, - &game.panel.conveyor_belt_2, + GAME_PANEL_ELEMENT_COUNT_3, + &game.panel.element_count[2], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_2_SWITCH, - &game.panel.conveyor_belt_2_switch, + GAME_PANEL_ELEMENT_COUNT_4, + &game.panel.element_count[3], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_3, - &game.panel.conveyor_belt_3, + GAME_PANEL_ELEMENT_COUNT_5, + &game.panel.element_count[4], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_3_SWITCH, - &game.panel.conveyor_belt_3_switch, + GAME_PANEL_ELEMENT_COUNT_6, + &game.panel.element_count[5], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_4, - &game.panel.conveyor_belt_4, + GAME_PANEL_ELEMENT_COUNT_7, + &game.panel.element_count[6], TYPE_INTEGER, }, { - GAME_CONTROL_CONVEYOR_BELT_4_SWITCH, - &game.panel.conveyor_belt_4_switch, + GAME_PANEL_ELEMENT_COUNT_8, + &game.panel.element_count[7], TYPE_INTEGER, }, { - GAME_CONTROL_MAGIC_WALL, - &game.panel.magic_wall, + GAME_PANEL_CE_SCORE_1, + &game.panel.ce_score[0], TYPE_INTEGER, }, { - GAME_CONTROL_MAGIC_WALL_TIME, - &game.panel.magic_wall_time, + GAME_PANEL_CE_SCORE_2, + &game.panel.ce_score[1], TYPE_INTEGER, }, { - GAME_CONTROL_BD_MAGIC_WALL, - &game.panel.bd_magic_wall, + GAME_PANEL_CE_SCORE_3, + &game.panel.ce_score[2], TYPE_INTEGER, }, { - GAME_CONTROL_DC_MAGIC_WALL, - &game.panel.dc_magic_wall, + GAME_PANEL_CE_SCORE_4, + &game.panel.ce_score[3], TYPE_INTEGER, }, { - GAME_CONTROL_PLAYER_NAME, - &game.panel.player_name, + GAME_PANEL_CE_SCORE_5, + &game.panel.ce_score[4], TYPE_INTEGER, }, { - GAME_CONTROL_LEVEL_NAME, - &game.panel.level_name, + GAME_PANEL_CE_SCORE_6, + &game.panel.ce_score[5], TYPE_INTEGER, }, { - GAME_CONTROL_LEVEL_AUTHOR, - &game.panel.level_author, + 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_PANEL_CE_SCORE_8_ELEMENT, + &game.panel.ce_score_element[7], + TYPE_ELEMENT, + }, + { + GAME_PANEL_PLAYER_NAME, + &game.panel.player_name, + TYPE_STRING, + }, + { + GAME_PANEL_LEVEL_NAME, + &game.panel.level_name, + TYPE_STRING, + }, + { + GAME_PANEL_LEVEL_AUTHOR, + &game.panel.level_author, + TYPE_STRING, + }, { -1, NULL, -1, - NULL } }; #endif @@ -635,6 +902,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 : \ @@ -753,6 +1023,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); @@ -1661,73 +1933,750 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = getInvisibleActiveFromInvisibleElement(element); break; - case EL_EMC_MAGIC_BALL: - if (game.ball_state) - Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; - break; + case EL_EMC_MAGIC_BALL: + if (game.ball_state) + Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; + break; + + case EL_EMC_MAGIC_BALL_SWITCH: + if (game.ball_state) + Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; + break; + + default: + if (IS_CUSTOM_ELEMENT(element)) + { + if (CAN_MOVE(element)) + InitMovDir(x, y); + +#if USE_NEW_CUSTOM_VALUE + if (!element_info[element].use_last_ce_value || init_game) + CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); +#endif + } + else if (IS_GROUP_ELEMENT(element)) + { + Feld[x][y] = GetElementFromGroupElement(element); + + InitField(x, y, init_game); + } + + break; + } + + if (!init_game) + CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); +} + +static inline void InitField_WithBug1(int x, int y, boolean init_game) +{ + InitField(x, y, init_game); + + /* not needed to call InitMovDir() -- already done by InitField()! */ + if (game.engine_version < VERSION_IDENT(3,1,0,0) && + CAN_MOVE(Feld[x][y])) + InitMovDir(x, y); +} + +static inline void InitField_WithBug2(int x, int y, boolean init_game) +{ + int old_element = Feld[x][y]; + + InitField(x, y, init_game); + + /* not needed to call InitMovDir() -- already done by InitField()! */ + if (game.engine_version < VERSION_IDENT(3,1,0,0) && + CAN_MOVE(old_element) && + (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) + InitMovDir(x, y); + + /* this case is in fact a combination of not less than three bugs: + first, it calls InitMovDir() for elements that can move, although this is + already done by InitField(); then, it checks the element that was at this + field _before_ the call to InitField() (which can change it); lastly, it + was not called for "mole with direction" elements, which were treated as + "cannot move" due to (fixed) wrong element initialization in "src/init.c" + */ +} + +#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; game_panel_controls[i].nr != -1; i++) + { + 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; + + 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->size * getFontWidth(pos->font); + pos->height = getFontHeight(pos->font); + } + else if (type == TYPE_ELEMENT) + { + 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 UpdatePlayfieldElementCount() +{ + 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++; + } + + 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; +} + +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.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 : + local_player->score); + int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->required : + local_player->gems_still_needed); + int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->required > 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_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 (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 + game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += + stored_player[i].inventory_size; + + if (stored_player[i].num_white_keys > 0) + game_panel_controls[GAME_PANEL_KEY_WHITE].value = + EL_DC_KEY_WHITE; + + game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += + stored_player[i].num_white_keys; + } + } + else + { + int player_nr = game.centered_player_nr; + + 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); + } + + 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 + game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value += + stored_player[player_nr].inventory_size; + + if (stored_player[player_nr].num_white_keys > 0) + game_panel_controls[GAME_PANEL_KEY_WHITE].value = EL_DC_KEY_WHITE; + + game_panel_controls[GAME_PANEL_KEY_WHITE_COUNT].value += + stored_player[player_nr].num_white_keys; + } + + 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_panel_controls[GAME_PANEL_TIME].value = time; + + 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; + + game_panel_controls[GAME_PANEL_SHIELD_NORMAL].value = + (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE : + EL_EMPTY); + game_panel_controls[GAME_PANEL_SHIELD_NORMAL_TIME].value = + local_player->shield_normal_time_left; + game_panel_controls[GAME_PANEL_SHIELD_DEADLY].value = + (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE : + EL_EMPTY); + game_panel_controls[GAME_PANEL_SHIELD_DEADLY_TIME].value = + local_player->shield_deadly_time_left; + + game_panel_controls[GAME_PANEL_EXIT].value = + (exit_closed ? EL_EXIT_CLOSED : EL_EXIT_OPEN); + + 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_panel_controls[GAME_PANEL_LIGHT_SWITCH].value = + (game.light_time_left > 0 ? EL_LIGHT_SWITCH_ACTIVE : EL_LIGHT_SWITCH); + game_panel_controls[GAME_PANEL_LIGHT_SWITCH_TIME].value = + game.light_time_left; + + game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH].value = + (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED); + game_panel_controls[GAME_PANEL_TIMEGATE_SWITCH_TIME].value = + game.timegate_time_left; + + game_panel_controls[GAME_PANEL_SWITCHGATE_SWITCH].value = + EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; + + game_panel_controls[GAME_PANEL_EMC_LENSES].value = + (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY); + game_panel_controls[GAME_PANEL_EMC_LENSES_TIME].value = + game.lenses_time_left; + + game_panel_controls[GAME_PANEL_EMC_MAGNIFIER].value = + (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY); + game_panel_controls[GAME_PANEL_EMC_MAGNIFIER_TIME].value = + game.magnify_time_left; + + 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_panel_controls[GAME_PANEL_DYNABOMB_NUMBER].value = + local_player->dynabomb_count; + game_panel_controls[GAME_PANEL_DYNABOMB_SIZE].value = + local_player->dynabomb_size; + game_panel_controls[GAME_PANEL_DYNABOMB_POWER].value = + (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY); + + game_panel_controls[GAME_PANEL_PENGUINS].value = + local_player->friends_still_needed; + + game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = + local_player->sokobanfields_still_needed; + game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = + local_player->sokobanfields_still_needed; + + game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = + (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); + + 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_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; + +#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) + { + 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_panel_controls[i].nr != -1; i++) + { + struct GamePanelControlInfo *gpc = &game_panel_controls[i]; + + if (PANEL_DEACTIVATED(gpc->pos)) + continue; + + 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 */ + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); + + /* 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 + 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_PANEL_LEVEL_NUMBER || + nr == GAME_PANEL_TIME) + { + boolean use_dynamic_size = (size == -1 ? TRUE : FALSE); + + if (use_dynamic_size) /* use dynamic number of digits */ + { + 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; + + size = (value < value_change ? size1 : size2); + font = (value < value_change ? font1 : font2); + +#if 0 + /* clear background if value just changed its size (dynamic digits) */ + if ((last_value < value_change) != (value < value_change)) + { + int width1 = size1 * getFontWidth(font1); + int width2 = size2 * getFontWidth(font2); + int max_width = MAX(width1, width2); + int max_height = MAX(getFontHeight(font1), getFontHeight(font2)); + + pos->width = max_width; + + ClearRectangleOnBackground(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), + max_width, max_height); + } +#endif + } + } + +#if 1 + /* correct text size if "digits" is zero or less */ + if (size <= 0) + size = strlen(int2str(value, size)); + + /* dynamically correct text alignment */ + pos->width = size * getFontWidth(font); +#endif + + DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), + int2str(value, size), font, mask_mode); + } + else if (type == TYPE_ELEMENT) + { + 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) + { + 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); + + 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(src_bitmap, drawto, src_x, src_y, width, height, + dst_x, dst_y); + } + } +#else + if (value == EL_UNDEFINED || value == EL_EMPTY) + { + element = (last_value == EL_UNDEFINED ? EL_EMPTY : last_value); + graphic = el2panelimg(element); + + src_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; + src_x = DOOR_GFX_PAGEX5 + ALIGNED_TEXT_XPOS(pos); + src_y = DOOR_GFX_PAGEY1 + ALIGNED_TEXT_YPOS(pos); + } + else + { + element = value; + graphic = el2panelimg(value); + + getSizedGraphicSource(graphic, frame, size, &src_bitmap, &src_x,&src_y); + } - case EL_EMC_MAGIC_BALL_SWITCH: - if (game.ball_state) - Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; - break; + width = graphic_info[graphic].width * size / TILESIZE; + height = graphic_info[graphic].height * size / TILESIZE; - default: - if (IS_CUSTOM_ELEMENT(element)) + BlitBitmap(src_bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y); +#endif + } + else if (type == TYPE_STRING) + { + 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) { - if (CAN_MOVE(element)) - InitMovDir(x, y); + 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)); -#if USE_NEW_CUSTOM_VALUE - if (!element_info[element].use_last_ce_value || init_game) - CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]); + 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 - } - else if (IS_GROUP_ELEMENT(element)) - { - Feld[x][y] = GetElementFromGroupElement(element); - InitField(x, y, init_game); + font = (active ? font2 : font1); } - break; - } + if (s != NULL) + { + char *s_cut; - if (!init_game) - CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); -} +#if 1 + if (size <= 0) + { + /* don't truncate output if "chars" is zero or less */ + size = strlen(s); -static inline void InitField_WithBug1(int x, int y, boolean init_game) -{ - InitField(x, y, init_game); + /* dynamically correct text alignment */ + pos->width = size * getFontWidth(font); + } +#endif - /* not needed to call InitMovDir() -- already done by InitField()! */ - if (game.engine_version < VERSION_IDENT(3,1,0,0) && - CAN_MOVE(Feld[x][y])) - InitMovDir(x, y); -} + s_cut = getStringCopyN(s, size); -static inline void InitField_WithBug2(int x, int y, boolean init_game) -{ - int old_element = Feld[x][y]; + DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), + s_cut, font, mask_mode); - InitField(x, y, init_game); + free(s_cut); + } + } - /* not needed to call InitMovDir() -- already done by InitField()! */ - if (game.engine_version < VERSION_IDENT(3,1,0,0) && - CAN_MOVE(old_element) && - (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) - InitMovDir(x, y); + redraw_mask |= REDRAW_DOOR_1; + } - /* this case is in fact a combination of not less than three bugs: - first, it calls InitMovDir() for elements that can move, although this is - already done by InitField(); then, it checks the element that was at this - field _before_ the call to InitField() (which can change it); lastly, it - was not called for "mole with direction" elements, which were treated as - "cannot move" due to (fixed) wrong element initialization in "src/init.c" - */ + game_status = GAME_MODE_PLAYING; } -#if 1 +void UpdateAndDisplayGameControlValues() +{ + if (tape.warp_forward) + return; + + UpdateGameControlValues(); + DisplayGameControlValues(); +} void DrawGameValue_Emeralds(int value) { @@ -1738,7 +2687,11 @@ 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 !!! */ +#endif if (PANEL_DEACTIVATED(pos)) return; @@ -1750,14 +2703,18 @@ 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 !!! */ +#endif if (PANEL_DEACTIVATED(pos)) return; @@ -1776,7 +2733,11 @@ 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 !!! */ +#endif if (PANEL_DEACTIVATED(pos)) return; @@ -1792,7 +2753,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; @@ -1803,6 +2764,10 @@ void DrawGameValue_Time(int value) int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); +#if 1 + return; /* !!! USE NEW STUFF !!! */ +#endif + if (PANEL_DEACTIVATED(pos)) return; @@ -1838,7 +2803,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; @@ -1849,6 +2814,10 @@ void DrawGameValue_Level(int value) int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); +#if 1 + return; /* !!! USE NEW STUFF !!! */ +#endif + if (PANEL_DEACTIVATED(pos)) return; @@ -1873,6 +2842,10 @@ void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) #endif int i; +#if 1 + return; /* !!! USE NEW STUFF !!! */ +#endif + #if 0 if (PANEL_DEACTIVATED(pos)) return; @@ -1897,7 +2870,7 @@ void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) #if 1 struct TextPosInfo *pos = &game.panel.key[i]; #endif - int src_x = DOOR_GFX_PAGEX5 + 18; + int src_x = DOOR_GFX_PAGEX5 + 18 + (i % 4) * MINI_TILEX; int src_y = DOOR_GFX_PAGEY1 + 123; #if 1 int dst_x = PANEL_XPOS(pos); @@ -1978,7 +2951,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); @@ -2088,7 +3061,17 @@ void DrawAllGameValues(int emeralds, int dynamite, int score, int time, DrawGameValue_Keys(key); } +void UpdateGameDoorValues() +{ + UpdateGameControlValues(); +} + void DrawGameDoorValues() +{ + DisplayGameControlValues(); +} + +void DrawGameDoorValues_OLD() { int time_value = (level.time == 0 ? TimePlayed : TimeLeft); int dynamite_value = 0; @@ -2378,6 +3361,7 @@ static void InitGameEngine() { 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_bits = CH_PLAYER_1; 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; @@ -2557,6 +3541,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) @@ -2596,12 +3587,15 @@ void InitGame() boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ +#if 0 boolean do_fading = (game_status == GAME_MODE_MAIN); +#endif int i, j, x, y; game_status = GAME_MODE_PLAYING; InitGameEngine(); + InitGameControlValues(); /* don't play tapes over network */ network_playing = (options.network && !tape.playing); @@ -2732,6 +3726,8 @@ void InitGame() player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; + player->LevelSolved_CountingTime = 0; + player->LevelSolved_CountingScore = 0; } network_player_action_received = FALSE; @@ -2760,6 +3756,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; @@ -2846,6 +3843,8 @@ void InitGame() emulate_sp = FALSE; InitField(x, y, TRUE); + + ResetGfxAnimation(x, y); } InitBeltMovement(); @@ -3082,7 +4081,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; @@ -3099,7 +4099,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; @@ -3119,7 +4120,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; @@ -3150,26 +4152,39 @@ 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) CloseDoor(DOOR_CLOSE_1); +#if 1 + if (level_editor_test_game) + FadeSkipNextFadeIn(); + else + FadeSetEnterScreen(); +#else if (level_editor_test_game) fading = fading_none; else fading = menu.destination; +#endif #if 1 - if (fading.anim_mode == ANIM_CROSSFADE) - FadeCrossSaveBackbuffer(); - else - FadeOut(REDRAW_FIELD); + FadeOut(REDRAW_FIELD); #else if (do_fading) FadeOut(REDRAW_FIELD); #endif +#if 0 + game_status = GAME_MODE_PLAYING; +#endif + /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -3196,10 +4211,7 @@ void InitGame() /* !!! FIX THIS (END) !!! */ #if 1 - if (fading.anim_mode == ANIM_CROSSFADE) - FadeCross(redraw_mask); - else - FadeIn(redraw_mask); + FadeIn(REDRAW_FIELD); #else if (do_fading) FadeIn(REDRAW_FIELD); @@ -3217,7 +4229,12 @@ void InitGame() SetPanelBackground(); SetDrawBackgroundMask(REDRAW_DOOR_1); +#if 1 + UpdateAndDisplayGameControlValues(); +#else + UpdateGameDoorValues(); DrawGameDoorValues(); +#endif if (!game.restart_level) { @@ -3474,6 +4491,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() @@ -3528,8 +4548,18 @@ void GameWon() time = time_final; score = score_final; +#if 1 + 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 DrawGameValue_Time(time); DrawGameValue_Score(score); +#endif } if (level.game_engine_type == GAME_ENGINE_TYPE_RND) @@ -3603,8 +4633,18 @@ void GameWon() time += time_count_steps * time_count_dir; score += time_count_steps * level.score[SC_TIME_BONUS]; +#if 1 + local_player->LevelSolved_CountingTime = time; + local_player->LevelSolved_CountingScore = score; + + game_panel_controls[GAME_PANEL_TIME].value = time; + game_panel_controls[GAME_PANEL_SCORE].value = score; + + DisplayGameControlValues(); +#else DrawGameValue_Time(time); DrawGameValue_Score(score); +#endif if (time == time_final) StopSound(SND_GAME_LEVELTIME_BONUS); @@ -3668,11 +4708,6 @@ void GameEnd() if (!local_player->LevelSolved_SaveScore) { #if 1 - if (fading.anim_mode == ANIM_CROSSFADE) - FadeCrossSaveBackbuffer(); - else - FadeOut(REDRAW_FIELD); -#else FadeOut(REDRAW_FIELD); #endif @@ -3707,11 +4742,6 @@ void GameEnd() else { #if 1 - if (fading.anim_mode == ANIM_CROSSFADE) - FadeCrossSaveBackbuffer(); - else - FadeOut(REDRAW_FIELD); -#else FadeOut(REDRAW_FIELD); #endif @@ -4194,12 +5224,14 @@ 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); + int offset = game.scroll_delay_value; if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen) { - if (center_screen) + if (!level.shifted_relocation || center_screen) { + /* quick relocation (without scrolling), with centering of screen */ + scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); @@ -4234,6 +5266,8 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, } else { + /* quick relocation (without scrolling), inside visible screen area */ + 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); @@ -4255,6 +5289,49 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, } else { +#if 1 + int scroll_xx, scroll_yy; + + if (!level.shifted_relocation || center_screen) + { + /* visible relocation (with scrolling), with centering of screen */ + + scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : + x > SBX_Right + MIDPOSX ? SBX_Right : + x - MIDPOSX); + + scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : + y > SBY_Lower + MIDPOSY ? SBY_Lower : + y - MIDPOSY); + } + else + { + /* visible relocation (with scrolling), but do not center screen */ + + int center_scroll_x = (old_x < SBX_Left + MIDPOSX ? SBX_Left : + old_x > SBX_Right + MIDPOSX ? SBX_Right : + old_x - MIDPOSX); + + int center_scroll_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_xx = (offset_x < SBX_Left + MIDPOSX ? SBX_Left : + offset_x > SBX_Right + MIDPOSX ? SBX_Right : + offset_x - MIDPOSX); + + scroll_yy = (offset_y < SBY_Upper + MIDPOSY ? SBY_Upper : + offset_y > SBY_Lower + MIDPOSY ? SBY_Lower : + offset_y - MIDPOSY); + } + +#else + + /* visible relocation (with scrolling), with centering of screen */ + int scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left : x > SBX_Right + MIDPOSX ? SBX_Right : x - MIDPOSX); @@ -4262,6 +5339,7 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, int scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper : y > SBY_Lower + MIDPOSY ? SBY_Lower : y - MIDPOSY); +#endif ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ @@ -4909,12 +5987,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; + } } } @@ -4990,12 +6075,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) @@ -7570,7 +8662,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; @@ -8238,7 +9330,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) @@ -8437,9 +9533,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) @@ -8448,18 +9541,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); - } } } } @@ -8953,11 +10034,15 @@ 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; +#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 && @@ -9000,7 +10085,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { TimeLeft = action_arg_number_new; +#if 1 + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; + + DisplayGameControlValues(); +#else DrawGameValue_Time(TimeLeft); +#endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) @@ -9014,7 +10105,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { local_player->score = action_arg_number_new; +#if 1 + game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; + + DisplayGameControlValues(); +#else DrawGameValue_Score(local_player->score); +#endif break; } @@ -9023,7 +10120,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { local_player->gems_still_needed = action_arg_number_new; +#if 1 + game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; + + DisplayGameControlValues(); +#else DrawGameValue_Emeralds(local_player->gems_still_needed); +#endif break; } @@ -9445,6 +10548,7 @@ 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_bits = CH_PLAYER_1; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; @@ -9825,7 +10929,8 @@ 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); @@ -9944,7 +11049,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); @@ -10298,7 +11404,13 @@ static void CheckLevelTime() if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); +#if 1 + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; + + DisplayGameControlValues(); +#else DrawGameValue_Time(TimeLeft); +#endif if (!TimeLeft && setup.time_limit) { @@ -10309,8 +11421,17 @@ static void CheckLevelTime() KillPlayer(&stored_player[i]); } } +#if 1 + else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + { + game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; + + DisplayGameControlValues(); + } +#else else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); +#endif level.native_em_level->lev->time = (level.time == 0 ? TimePlayed : TimeLeft); @@ -10319,6 +11440,13 @@ static void CheckLevelTime() if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime); } + +#if 1 + UpdateAndDisplayGameControlValues(); +#else + UpdateGameDoorValues(); + DrawGameDoorValues(); +#endif } void AdvanceFrameAndPlayerCounters(int player_nr) @@ -11185,6 +12313,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) @@ -11383,7 +12512,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); @@ -11734,7 +12863,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))) { @@ -12034,14 +13163,29 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (TimeLeft <= 10 && setup.time_limit) PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); +#if 1 + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; + + DisplayGameControlValues(); +#else DrawGameValue_Time(TimeLeft); +#endif if (!TimeLeft && setup.time_limit) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } +#if 1 + else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + { + game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; + + DisplayGameControlValues(); + } +#else else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); +#endif } if (tape.single_step && tape.recording && !tape.pausing && @@ -13090,7 +14234,14 @@ int DigField(struct PlayerInfo *player, else if (element == EL_EXTRA_TIME && level.time > 0) { TimeLeft += level.extra_time; + +#if 1 + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; + + DisplayGameControlValues(); +#else DrawGameValue_Time(TimeLeft); +#endif } else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) { @@ -13169,7 +14320,13 @@ int DigField(struct PlayerInfo *player, if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; +#if 1 + game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; + + DisplayGameControlValues(); +#else DrawGameValue_Emeralds(local_player->gems_still_needed); +#endif } RaiseScoreElement(element); @@ -13349,6 +14506,8 @@ int DigField(struct PlayerInfo *player, ZX = x; ZY = y; + game.robot_wheel_active = TRUE; + DrawLevelField(x, y); } else if (element == EL_SP_TERMINAL) @@ -13413,7 +14572,14 @@ int DigField(struct PlayerInfo *player, if (level.time > 0 || level.use_time_orb_bug) { TimeLeft += level.time_orb_time; + +#if 1 + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; + + DisplayGameControlValues(); +#else DrawGameValue_Time(TimeLeft); +#endif } ResetGfxAnimation(x, y); @@ -13585,6 +14751,9 @@ boolean DropElement(struct PlayerInfo *player) int dropx = player->jx, dropy = player->jy; int drop_direction = player->MovDir; int drop_side = drop_direction; +#if 1 + int drop_element = get_next_dropped_element(player); +#else int drop_element = (player->inventory_size > 0 ? player->inventory_element[player->inventory_size - 1] : player->inventory_infinite_element != EL_UNDEFINED ? @@ -13592,6 +14761,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; @@ -14035,7 +15205,13 @@ void RaiseScore(int value) { local_player->score += value; +#if 1 + game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; + + DisplayGameControlValues(); +#else DrawGameValue_Score(local_player->score); +#endif } void RaiseScoreElement(int element) @@ -14131,7 +15307,13 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) if (quick_quit) { #if 1 + +#if 1 + FadeSkipNextFadeIn(); +#else fading = fading_none; +#endif + #else OpenDoor(DOOR_CLOSE_1); #endif @@ -14147,14 +15329,7 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) else { #if 0 -#if 1 - if (fading.anim_mode == ANIM_CROSSFADE) - FadeCrossSaveBackbuffer(); - else - FadeOut(REDRAW_FIELD); -#else FadeOut(REDRAW_FIELD); -#endif #endif game_status = GAME_MODE_MAIN; @@ -14654,6 +15829,7 @@ void CreateGameButtons() 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_DIRECT_DRAW, FALSE, GDI_EVENT_MASK, event_mask, GDI_CALLBACK_ACTION, HandleGameButtons, GDI_END); @@ -14689,6 +15865,14 @@ void UnmapGameButtons() UnmapGadget(game_gadget[i]); } +void RedrawGameButtons() +{ + int i; + + for (i = 0; i < NUM_GAME_BUTTONS; i++) + RedrawGadget(game_gadget[i]); +} + static void HandleGameButtons(struct GadgetInfo *gi) { int id = gi->custom_id;