rnd-20070401-2-src
[rocksndiamonds.git] / src / game.c
index 4b4a44cfee1868d6113e12a2b17c9f947db8499d..22008ecc5ee8c436284ef192ea0656a12245f1b2 100644 (file)
 #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_EMC_MAGIC_BALL_TIME       37
-#define GAME_CONTROL_LIGHT_SWITCH              38
-#define GAME_CONTROL_LIGHT_SWITCH_TIME         39
-#define GAME_CONTROL_TIMEGATE_SWITCH           40
-#define GAME_CONTROL_TIMEGATE_SWITCH_TIME      41
-#define GAME_CONTROL_SWITCHGATE_SWITCH         42
-#define GAME_CONTROL_EMC_LENSES                        43
-#define GAME_CONTROL_EMC_LENSES_TIME           44
-#define GAME_CONTROL_EMC_MAGNIFIER             45
-#define GAME_CONTROL_EMC_MAGNIFIER_TIME                46
-#define GAME_CONTROL_BALLOON_SWITCH            47
-#define GAME_CONTROL_DYNABOMB_NUMBER           48
-#define GAME_CONTROL_DYNABOMB_SIZE             49
-#define GAME_CONTROL_DYNABOMB_POWER            50
-#define GAME_CONTROL_PENGUINS                  51
-#define GAME_CONTROL_SOKOBAN_OBJECTS           52
-#define GAME_CONTROL_SOKOBAN_FIELDS            53
-#define GAME_CONTROL_ROBOT_WHEEL               54
-#define GAME_CONTROL_CONVEYOR_BELT_1           55
-#define GAME_CONTROL_CONVEYOR_BELT_1_SWITCH    56
-#define GAME_CONTROL_CONVEYOR_BELT_2           57
-#define GAME_CONTROL_CONVEYOR_BELT_2_SWITCH    58
-#define GAME_CONTROL_CONVEYOR_BELT_3           59
-#define GAME_CONTROL_CONVEYOR_BELT_3_SWITCH    60
-#define GAME_CONTROL_CONVEYOR_BELT_4           61
-#define GAME_CONTROL_CONVEYOR_BELT_4_SWITCH    62
-#define GAME_CONTROL_MAGIC_WALL                        63
-#define GAME_CONTROL_MAGIC_WALL_TIME           64
-#define GAME_CONTROL_BD_MAGIC_WALL             65
-#define GAME_CONTROL_DC_MAGIC_WALL             66
-#define GAME_CONTROL_PLAYER_NAME               67
-#define GAME_CONTROL_LEVEL_NAME                        68
-#define GAME_CONTROL_LEVEL_AUTHOR              69
-
-#define NUM_GAME_CONTROLS                      70
+#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];
@@ -402,11 +401,6 @@ static struct GameControlInfo game_controls[] =
     &game.panel.emc_magic_ball_switch,
     TYPE_ELEMENT,
   },
-  {
-    GAME_CONTROL_EMC_MAGIC_BALL_TIME,
-    &game.panel.emc_magic_ball_time,
-    TYPE_INTEGER,
-  },
   {
     GAME_CONTROL_LIGHT_SWITCH,
     &game.panel.light_switch,
@@ -1728,53 +1722,63 @@ 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;
+}
+
 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++)
   {
     int nr = game_controls[i].nr;
     int type = game_controls[i].type;
     struct TextPosInfo *pos = game_controls[i].pos;
 
+    /* force update of game controls after initialization */
     game_control_value[nr] = last_game_control_value[nr] = -1;
 
     /* determine panel value width for later calculation of alignment */
     if (type == TYPE_INTEGER || type == TYPE_STRING)
       pos->width = pos->chars * getFontWidth(pos->font);
+    else if (type == TYPE_ELEMENT)
+      pos->width = MINI_TILESIZE;
   }
 }
 
 void UpdateGameControlValues()
 {
-  int i, j;
+  int i, k;
 
   game_control_value[GAME_CONTROL_LEVEL_NUMBER] = level_nr;
   game_control_value[GAME_CONTROL_GEMS] = local_player->gems_still_needed;
 
   game_control_value[GAME_CONTROL_INVENTORY] = 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_1 + i] = EL_EMPTY;
+  game_control_value[GAME_CONTROL_KEY_WHITE] = EL_EMPTY;
   game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] = 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;
+      for (k = 0; k < MAX_NUM_KEYS; k++)
+       if (stored_player[i].key[k])
+         game_control_value[GAME_CONTROL_KEY_1 + k] =
+           get_key_element_from_nr(k);
 
       game_control_value[GAME_CONTROL_INVENTORY] +=
        stored_player[i].inventory_size;
 
       if (stored_player[i].num_white_keys > 0)
-       game_control_value[GAME_CONTROL_KEY_WHITE] = 1;
+       game_control_value[GAME_CONTROL_KEY_WHITE] = EL_DC_KEY_WHITE;
 
       game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] +=
        stored_player[i].num_white_keys;
@@ -1784,15 +1788,16 @@ 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 (stored_player[player_nr].key[k])
+       game_control_value[GAME_CONTROL_KEY_1 + k] =
+         get_key_element_from_nr(k);
 
     game_control_value[GAME_CONTROL_INVENTORY] +=
       stored_player[player_nr].inventory_size;
 
     if (stored_player[player_nr].num_white_keys > 0)
-      game_control_value[GAME_CONTROL_KEY_WHITE] = 1;
+      game_control_value[GAME_CONTROL_KEY_WHITE] = EL_DC_KEY_WHITE;
 
     game_control_value[GAME_CONTROL_KEY_WHITE_COUNT] +=
       stored_player[player_nr].num_white_keys;
@@ -1810,51 +1815,77 @@ void UpdateGameControlValues()
   game_control_value[GAME_CONTROL_TIME_MM] = (TapeTime / 60) % 60;
   game_control_value[GAME_CONTROL_TIME_SS] = TapeTime % 60;
 
+  /* !!! TODO !!! */
   for (i = 0; i < 8; i++)
-    game_control_value[GAME_CONTROL_DROP_NEXT_1 + i] = 0;
+    game_control_value[GAME_CONTROL_DROP_NEXT_1 + i] = EL_UNDEFINED;
 
   game_control_value[GAME_CONTROL_SHIELD_NORMAL] =
-    (local_player->shield_normal_time_left > 0 ? 1 : 0);
+    (local_player->shield_normal_time_left > 0 ? EL_SHIELD_NORMAL_ACTIVE :
+     EL_EMPTY);
   game_control_value[GAME_CONTROL_SHIELD_NORMAL_TIME] =
     local_player->shield_normal_time_left;
   game_control_value[GAME_CONTROL_SHIELD_DEADLY] =
-    (local_player->shield_deadly_time_left > 0 ? 1 : 0);
+    (local_player->shield_deadly_time_left > 0 ? EL_SHIELD_DEADLY_ACTIVE :
+     EL_EMPTY);
   game_control_value[GAME_CONTROL_SHIELD_DEADLY_TIME] =
     local_player->shield_deadly_time_left;
 
-  game_control_value[GAME_CONTROL_EXIT] = 0;
-  game_control_value[GAME_CONTROL_EM_EXIT] = 0;
-  game_control_value[GAME_CONTROL_SP_EXIT] = 0;
-  game_control_value[GAME_CONTROL_STEEL_EXIT] = 0;
-  game_control_value[GAME_CONTROL_EM_STEEL_EXIT] = 0;
+  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_control_value[GAME_CONTROL_EMC_MAGIC_BALL] = 0;
-  game_control_value[GAME_CONTROL_EMC_MAGIC_BALL_SWITCH] = 0;
-  game_control_value[GAME_CONTROL_EMC_MAGIC_BALL_TIME] = 0;
+  /* !!! TODO !!! */
+  game_control_value[GAME_CONTROL_EMC_MAGIC_BALL] = EL_UNDEFINED;
+  game_control_value[GAME_CONTROL_EMC_MAGIC_BALL_SWITCH] = EL_UNDEFINED;
 
-  game_control_value[GAME_CONTROL_LIGHT_SWITCH] = 0;
+  game_control_value[GAME_CONTROL_LIGHT_SWITCH] =
+    (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_control_value[GAME_CONTROL_TIMEGATE_SWITCH] = 0;
+  game_control_value[GAME_CONTROL_TIMEGATE_SWITCH] =
+    (game.timegate_time_left > 0 ? EL_TIMEGATE_OPEN : EL_TIMEGATE_CLOSED);
   game_control_value[GAME_CONTROL_TIMEGATE_SWITCH_TIME] =
     game.timegate_time_left;
 
-  game_control_value[GAME_CONTROL_SWITCHGATE_SWITCH] = 0;
+  /* !!! TODO !!! */
+  game_control_value[GAME_CONTROL_SWITCHGATE_SWITCH] = EL_UNDEFINED;
 
-  game_control_value[GAME_CONTROL_EMC_LENSES] = 0;
+  game_control_value[GAME_CONTROL_EMC_LENSES] =
+    (game.lenses_time_left > 0 ? EL_EMC_LENSES : EL_EMPTY);
   game_control_value[GAME_CONTROL_EMC_LENSES_TIME] = game.lenses_time_left;
 
-  game_control_value[GAME_CONTROL_EMC_MAGNIFIER] = 0;
+  game_control_value[GAME_CONTROL_EMC_MAGNIFIER] =
+    (game.magnify_time_left > 0 ? EL_EMC_MAGNIFIER : EL_EMPTY);
   game_control_value[GAME_CONTROL_EMC_MAGNIFIER_TIME] = game.magnify_time_left;
 
-  game_control_value[GAME_CONTROL_BALLOON_SWITCH] = 0;
+  game_control_value[GAME_CONTROL_BALLOON_SWITCH] =
+    (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] =
     local_player->dynabomb_count;
   game_control_value[GAME_CONTROL_DYNABOMB_SIZE] =
     local_player->dynabomb_size;
   game_control_value[GAME_CONTROL_DYNABOMB_POWER] =
-    local_player->dynabomb_xl;
+    (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY);
 
   game_control_value[GAME_CONTROL_PENGUINS] =
     local_player->friends_still_needed;
@@ -1864,22 +1895,25 @@ void UpdateGameControlValues()
   game_control_value[GAME_CONTROL_SOKOBAN_FIELDS] =
     local_player->sokobanfields_still_needed;
 
-  game_control_value[GAME_CONTROL_ROBOT_WHEEL] = 0;
-
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_1] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_1_SWITCH] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_2] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_2_SWITCH] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_3] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_3_SWITCH] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_4] = 0;
-  game_control_value[GAME_CONTROL_CONVEYOR_BELT_4_SWITCH] = 0;
-
-  game_control_value[GAME_CONTROL_MAGIC_WALL] = 0;
+  /* !!! TODO !!! */
+  game_control_value[GAME_CONTROL_ROBOT_WHEEL] = EL_UNDEFINED;
+
+  /* !!! TODO !!! */
+  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;
+
+  /* !!! TODO !!! */
+  game_control_value[GAME_CONTROL_MAGIC_WALL] = EL_UNDEFINED;
   game_control_value[GAME_CONTROL_MAGIC_WALL_TIME] =
     game.magic_wall_time_left;
-  game_control_value[GAME_CONTROL_BD_MAGIC_WALL] = 0;
-  game_control_value[GAME_CONTROL_DC_MAGIC_WALL] = 0;
+  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;
@@ -1951,23 +1985,22 @@ void DisplayGameControlValues()
     }
     else if (type == TYPE_ELEMENT)
     {
-      if (nr >= GAME_CONTROL_KEY_1 && nr <= GAME_CONTROL_KEY_8)
+      int dst_x = PANEL_XPOS(pos);
+      int dst_y = PANEL_YPOS(pos);
+
+      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);
+       int src_x = DOOR_GFX_PAGEX5 + ALIGNED_TEXT_XPOS(pos);
+       int src_y = DOOR_GFX_PAGEY1 + ALIGNED_TEXT_YPOS(pos);
 
-       if (value)
-         DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic);
-       else
-         BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y,
-                    MINI_TILEX, MINI_TILEY, dst_x, dst_y);
+       BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y,
+                  MINI_TILEX, MINI_TILEY, dst_x, dst_y);
+      }
+      else
+      {
+       int graphic = el2edimg(value);
+
+       DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic);
       }
     }
     else if (type == TYPE_STRING)
@@ -1985,6 +2018,8 @@ void DisplayGameControlValues()
        free(s_cut);
       }
     }
+
+    redraw_mask |= REDRAW_DOOR_1;
   }
 }
 
@@ -2846,6 +2881,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)
@@ -3374,7 +3416,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;
@@ -3391,7 +3434,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;
@@ -3411,7 +3455,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;
@@ -3451,7 +3496,7 @@ void InitGame()
   if (level_editor_test_game)
     FadeSkipNextFadeIn();
   else
-    FadeSetStartItem();
+    FadeSetEnterScreen();
 #else
   if (level_editor_test_game)
     fading = fading_none;
@@ -4491,7 +4536,7 @@ 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)
     {
@@ -12114,7 +12159,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)))
     {