+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);
+ }
+}
+
+void InitGameControlValues()
+{
+ int i;
+
+ for (i = 0; game_panel_controls[i].nr != -1; i++)
+ {
+ struct GamePanelControlInfo *gpc = &game_panel_controls[i];
+ int nr = gpc->nr;
+ int type = gpc->type;
+ struct TextPosInfo *pos = gpc->pos;
+
+ if (nr != i)
+ {
+ Error(ERR_INFO, "'game_panel_controls' structure corrupted");
+ 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;
+ }
+ }
+}
+
+void UpdateGameControlValues()
+{
+ int i, k;
+ int time = (level.time == 0 ? TimePlayed : TimeLeft);
+ int score = (local_player->LevelSolved ? local_player->score_final :
+ local_player->score);
+ int exit_closed = (local_player->gems_still_needed > 0 ||
+ local_player->sokobanfields_still_needed > 0 ||
+ local_player->lights_still_needed > 0);
+
+ game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr;
+ game_panel_controls[GAME_PANEL_GEMS].value =
+ local_player->gems_still_needed;
+
+ 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 (stored_player[i].key[k])
+ game_panel_controls[GAME_PANEL_KEY_1 + k].value =
+ get_key_element_from_nr(k);
+
+ 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 (stored_player[player_nr].key[k])
+ game_panel_controls[GAME_PANEL_KEY_1 + k].value =
+ get_key_element_from_nr(k);
+
+ 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 < 8; 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_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);
+
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1].value =
+ (game.belt_dir[0] != MV_NONE ? EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE :
+ EL_CONVEYOR_BELT_1_MIDDLE);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_1_SWITCH].value =
+ getBeltSwitchElementFromBeltNrAndBeltDir(0, game.belt_dir[0]);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_2].value =
+ (game.belt_dir[1] != MV_NONE ? EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE :
+ EL_CONVEYOR_BELT_2_MIDDLE);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_2_SWITCH].value =
+ getBeltSwitchElementFromBeltNrAndBeltDir(1, game.belt_dir[1]);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_3].value =
+ (game.belt_dir[2] != MV_NONE ? EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE :
+ EL_CONVEYOR_BELT_3_MIDDLE);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_3_SWITCH].value =
+ getBeltSwitchElementFromBeltNrAndBeltDir(2, game.belt_dir[2]);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_4].value =
+ (game.belt_dir[3] != MV_NONE ? EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE :
+ EL_CONVEYOR_BELT_4_MIDDLE);
+ game_panel_controls[GAME_PANEL_CONVEYOR_BELT_4_SWITCH].value =
+ getBeltSwitchElementFromBeltNrAndBeltDir(3, game.belt_dir[3]);
+
+ 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
+
+ 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;
+
+ 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 != gpc->last_value)
+ gpc->gfx_frame = 0;
+ else
+ gpc->gfx_frame++;
+
+ gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value),
+ gpc->gfx_frame);
+ }
+ }
+}
+
+void DisplayGameControlValues()
+{
+ int i;
+
+ game_status = GAME_MODE_PSEUDO_PANEL;
+
+ for (i = 0; game_panel_controls[i].nr != -1; i++)
+ {
+ struct GamePanelControlInfo *gpc = &game_panel_controls[i];
+ int nr = gpc->nr;
+ int type = gpc->type;
+ struct TextPosInfo *pos = gpc->pos;
+ int value = gpc->value;
+ int frame = gpc->frame;
+ int last_value = gpc->last_value;
+ int last_frame = gpc->last_frame;
+ int size = pos->size;
+ int font = pos->font;
+
+ if (value == last_value && frame == last_frame)
+ continue;
+
+ 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 (PANEL_DEACTIVATED(pos))
+ continue;
+
+ 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);
+
+ /* 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);
+ }
+ }
+
+ pos->width = size * getFontWidth(font);
+ }
+
+ DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, size), font);
+ }
+ else if (type == TYPE_ELEMENT)
+ {
+ int dst_x = PANEL_XPOS(pos);
+ int dst_y = PANEL_YPOS(pos);
+
+ if (value == EL_UNDEFINED || value == EL_EMPTY)
+ {
+ int src_x = DOOR_GFX_PAGEX5 + ALIGNED_TEXT_XPOS(pos);
+ int src_y = DOOR_GFX_PAGEY1 + ALIGNED_TEXT_YPOS(pos);
+
+ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y,
+ size, size, dst_x, dst_y);
+ }
+ else
+ {
+ int graphic = el2panelimg(value);
+
+ DrawSizedGraphicExt(drawto, dst_x, dst_y, graphic, frame, size);
+ }
+ }
+ 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)
+ {
+ int font1 = pos->font; /* (used for normal state) */
+ int font2 = pos->font_alt; /* (used for active state) */
+ 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);
+
+ font = (active ? font2 : font1);
+ }
+
+#if 1
+ /* as with numbers, don't truncate output if "chars" is zero or less */
+ size = (size > 0 ? size : strlen(s));
+#endif
+
+ if (s != NULL)
+ {
+ char *s_cut = getStringCopyN(s, size);
+
+#if 0
+ /* (not needed anymore with above correction of "size" value) */
+ size = strlen(s_cut); /* string size may be smaller than "chars" */
+#endif
+
+ pos->width = size * getFontWidth(font);
+
+ DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), s_cut, font);
+
+ free(s_cut);
+ }
+ }
+
+ redraw_mask |= REDRAW_DOOR_1;
+ }
+
+ game_status = GAME_MODE_PLAYING;
+}
+