added support for animated door parts (for menu request doors)
[rocksndiamonds.git] / src / tools.c
index 335d983a96e8700a5cbf801553cd6cc095d72ad2..082aa5ea08cb503b0fea7bd304ec9ce5ac66f032 100644 (file)
@@ -1045,94 +1045,48 @@ inline int getGraphicAnimationFrame(int graphic, int sync_frame)
                           sync_frame);
 }
 
-void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
+void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
                              Bitmap **bitmap, int *x, int *y,
                              boolean get_backside)
 {
-  struct
-  {
-    int width_mult, width_div;
-    int height_mult, height_div;
-  }
-  offset_calc[6] =
-  {
-    { 15, 16,  2, 3    },      /* 1 x 1 */
-    { 7, 8,    2, 3    },      /* 2 x 2 */
-    { 3, 4,    2, 3    },      /* 4 x 4 */
-    { 1, 2,    2, 3    },      /* 8 x 8 */
-    { 0, 1,    2, 3    },      /* 16 x 16 */
-    { 0, 1,    0, 1    },      /* 32 x 32 */
-  };
   struct GraphicInfo *g = &graphic_info[graphic];
   Bitmap *src_bitmap = g->bitmap;
-  int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
-  int offset_calc_pos = log_2(tilesize);
-  int bitmap_width  = src_bitmap->width;
-  int bitmap_height = src_bitmap->height;
-  int width_mult  = offset_calc[offset_calc_pos].width_mult;
-  int width_div   = offset_calc[offset_calc_pos].width_div;
-  int height_mult = offset_calc[offset_calc_pos].height_mult;
-  int height_div  = offset_calc[offset_calc_pos].height_div;
-  int startx = bitmap_width * width_mult / width_div;
-  int starty = bitmap_height * height_mult / height_div;
-  int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
-    tilesize_raw / TILESIZE;
-  int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
-    tilesize_raw / TILESIZE;
-  int width = g->width * tilesize_raw / TILESIZE;
-  int height = g->height * tilesize_raw / TILESIZE;
-  int offset_x = g->offset_x * tilesize_raw / TILESIZE;
-  int offset_y = g->offset_y * tilesize_raw / TILESIZE;
-
-  if (game.tile_size != TILESIZE)
-  {
-    int bitmap_width_std =
-      bitmap_width * TILESIZE / (TILESIZE + game.tile_size);
-    int bitmap_height_std =
-      bitmap_height * TILESIZE / game.tile_size * 3 / 2;
-
-    if (tilesize_raw == game.tile_size)
-    {
-      startx = bitmap_width_std;
-      starty = 0;
-    }
-    else
-    {
-      bitmap_width = bitmap_width_std;
-
-      if (game.tile_size > TILESIZE * 3 / 2)
-       bitmap_height = bitmap_height_std;
+  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
+  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
+  int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
 
-      startx = bitmap_width * width_mult / width_div;
-      starty = bitmap_height * height_mult / height_div;
-    }
-  }
+  if (tilesize == gfx.standard_tile_size)
+    src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
+  else if (tilesize == game.tile_size)
+    src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
+  else
+    src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
 
   if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
-    int max_width = g->anim_frames_per_line * width;
-    int pos = (src_y / height) * max_width + src_x + frame * offset_x;
+    int max_width = g->anim_frames_per_line * g->width;
+    int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
 
     src_x = pos % max_width;
-    src_y = src_y % height + pos / max_width * height;
+    src_y = src_y % g->height + pos / max_width * g->height;
   }
   else if (g->offset_x == 0)   /* frames are ordered vertically */
   {
-    int max_height = g->anim_frames_per_line * height;
-    int pos = (src_x / width) * max_height + src_y + frame * offset_y;
+    int max_height = g->anim_frames_per_line * g->height;
+    int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
 
-    src_x = src_x % width + pos / max_height * width;
+    src_x = src_x % g->width + pos / max_height * g->width;
     src_y = pos % max_height;
   }
   else                         /* frames are ordered diagonally */
   {
-    src_x = src_x + frame * offset_x;
-    src_y = src_y + frame * offset_y;
+    src_x = src_x + frame * g->offset_x;
+    src_y = src_y + frame * g->offset_y;
   }
 
   *bitmap = src_bitmap;
-  *x = startx + src_x;
-  *y = starty + src_y;
+  *x = src_x * tilesize / TILESIZE;
+  *y = src_y * tilesize / TILESIZE;
 }
 
 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
@@ -1142,10 +1096,10 @@ void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
                           get_backside);
 }
 
-void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
+void getSizedGraphicSource(int graphic, int frame, int tilesize,
                           Bitmap **bitmap, int *x, int *y)
 {
-  getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
+  getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
 }
 
 void getFixedGraphicSource(int graphic, int frame,
@@ -4159,6 +4113,8 @@ unsigned int MoveDoor(unsigned int door_state)
     int max_move_delay = 0;    // delay for complete animations of all doors
     int max_step_delay = 0;    // delay (ms) between two animation frames
     int num_move_steps = 0;    // number of animation steps for all doors
+    int max_move_delay_doors_only = 0; // delay for doors only (no panel)
+    int num_move_steps_doors_only = 0; // steps for doors only (no panel)
     int current_move_delay = 0;
     int start = 0;
     int k;
@@ -4207,16 +4163,21 @@ unsigned int MoveDoor(unsigned int door_state)
       if (door_part_skip[nr])
        continue;
 
-      if (!is_panel)
-       panel_has_doors[door_index] = TRUE;
-
       max_move_delay = MAX(max_move_delay, move_delay);
       max_step_delay = (max_step_delay == 0 ? step_delay :
                        euclid(max_step_delay, step_delay));
       num_steps[nr] = move_steps;
+
+      if (!is_panel)
+      {
+       max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
+
+       panel_has_doors[door_index] = TRUE;
+      }
     }
 
     num_move_steps = max_move_delay / max_step_delay;
+    num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
 
     door_delay_value = max_step_delay;
 
@@ -4249,6 +4210,7 @@ unsigned int MoveDoor(unsigned int door_state)
        int door_token = dpc->door_token;
        int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
        boolean is_panel = DOOR_PART_IS_PANEL(nr);
+       boolean is_panel_and_door_has_closed = FALSE;
        struct Rect *door_rect = &door_rect_list[door_index];
        Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
                                  bitmap_db_door_2);
@@ -4264,7 +4226,9 @@ unsigned int MoveDoor(unsigned int door_state)
        int step_factor = step_delay / max_step_delay;
        int k1 = (step_factor ? k / step_factor + 1 : k);
        int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
-       int kk = (k2 < 0 ? 0 : k2);
+       int kk = MAX(0, k2);
+       int g_src_x = 0;
+       int g_src_y = 0;
        int src_x, src_y, src_xx, src_yy;
        int dst_x, dst_y, dst_xx, dst_yy;
        int width, height;
@@ -4278,6 +4242,16 @@ unsigned int MoveDoor(unsigned int door_state)
        if (!g->bitmap)
          continue;
 
+       if (!is_panel)
+       {
+         int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
+         int kk_door = MAX(0, k2_door);
+         int sync_frame = kk_door * door_delay_value;
+         int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
+
+         getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
+       }
+
        // draw door panel
 
        if (!door_panel_drawn[door_index])
@@ -4338,22 +4312,21 @@ unsigned int MoveDoor(unsigned int door_state)
          height = g->height - src_yy;
        }
 
-       if (is_panel)
-       {
-         src_x = src_xx;
-         src_y = src_yy;
-       }
-       else
-       {
-         src_x = g->src_x + src_xx;
-         src_y = g->src_y + src_yy;
-       }
+       src_x = g_src_x + src_xx;
+       src_y = g_src_y + src_yy;
 
        dst_x = door_rect->x + dst_xx;
        dst_y = door_rect->y + dst_yy;
 
+       is_panel_and_door_has_closed =
+         (is_panel &&
+          door_closing &&
+          panel_has_doors[door_index] &&
+          k >= num_move_steps_doors_only - 1);
+
        if (width  >= 0 && width  <= g->width &&
-           height >= 0 && height <= g->height)
+           height >= 0 && height <= g->height &&
+           !is_panel_and_door_has_closed)
        {
          if (is_panel || !pos->draw_masked)
            BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
@@ -4370,8 +4343,7 @@ unsigned int MoveDoor(unsigned int door_state)
          door_part_done[nr] = TRUE;
 
        // continue door part animations, but not panel after door has closed
-       if (!door_part_done[nr] &&
-           !(is_panel && door_closing && panel_has_doors[door_index]))
+       if (!door_part_done[nr] && !is_panel_and_door_has_closed)
          door_part_done_all = FALSE;
       }
 
@@ -6220,7 +6192,7 @@ em_object_mapping_list[] =
   },
   {
     Xalpha_copyr,                      TRUE,   FALSE,
-    EL_CHAR('©'),                      -1, -1
+    EL_CHAR(CHAR_BYTE_COPYRIGHT),      -1, -1
   },
 
   {