rnd-20140228-1-src
[rocksndiamonds.git] / src / tools.c
index c590f455e92ab1ffd95208000e47548b0fc94c3c..0348f112c4f07abe7a21c31f2eb9b2178bb20afe 100644 (file)
@@ -11,6 +11,8 @@
 * tools.c                                                  *
 ***********************************************************/
 
+#include <math.h>
+
 #include "libgame/libgame.h"
 
 #include "tools.h"
 
 /* constants for number of doors and door parts */
 #define NUM_DOORS              2
-#define MAX_NUM_DOOR_PARTS     8
+#define NUM_PANELS             NUM_DOORS
+// #define NUM_PANELS          0
+#define MAX_PARTS_PER_DOOR     8
+#define MAX_DOOR_PARTS         (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
+#define DOOR_PART_IS_PANEL(i)  ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
 
 
 struct DoorPartOrderInfo
@@ -48,7 +54,7 @@ struct DoorPartOrderInfo
   int sort_priority;
 };
 
-static struct DoorPartOrderInfo door_part_order[NUM_DOORS * MAX_NUM_DOOR_PARTS];
+static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
 
 struct DoorPartControlInfo
 {
@@ -99,6 +105,7 @@ static struct DoorPartControlInfo door_part_controls[] =
     IMG_DOOR_1_GFX_PART_8,
     &door_1.part_8
   },
+
   {
     DOOR_2,
     IMG_DOOR_2_GFX_PART_1,
@@ -140,6 +147,17 @@ static struct DoorPartControlInfo door_part_controls[] =
     &door_2.part_8
   },
 
+  {
+    DOOR_1,
+    IMG_BACKGROUND_PANEL,
+    &door_1.panel
+  },
+  {
+    DOOR_2,
+    IMG_BACKGROUND_TAPE,
+    &door_2.panel
+  },
+
   {
     -1,
     -1,
@@ -5330,7 +5348,7 @@ void InitDoors()
   }
 
   /* sort door part controls according to sort_priority and graphic number */
-  qsort(door_part_order, NUM_DOORS * MAX_NUM_DOOR_PARTS,
+  qsort(door_part_order, MAX_DOOR_PARTS,
         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
 }
 
@@ -5407,13 +5425,8 @@ unsigned int MoveDoor(unsigned int door_state)
   };
   static int door1 = DOOR_OPEN_1;
   static int door2 = DOOR_CLOSE_2;
-#if 1
   unsigned int door_delay = 0;
   unsigned int door_delay_value;
-#endif
-#if 0
-  int stepsize = 1;
-#endif
   int i;
 
 #if 1
@@ -5477,29 +5490,38 @@ unsigned int MoveDoor(unsigned int door_state)
   if (door_state & DOOR_ACTION)
   {
     boolean door_panel_drawn[NUM_DOORS];
-    boolean door_part_done[NUM_DOORS * MAX_NUM_DOOR_PARTS];
+    boolean door_part_done[MAX_DOOR_PARTS];
     boolean door_part_done_all;
-#if 0
-    int num_xsteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
-    int num_ysteps[NUM_DOORS * MAX_NUM_DOOR_PARTS];
-#endif
+    int num_steps[MAX_DOOR_PARTS];
     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 current_move_delay = 0;
     int k;
 
-    for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
+    for (i = 0; i < MAX_DOOR_PARTS; i++)
     {
-      int nr = door_part_order[i].nr;
-      struct DoorPartControlInfo *dpc = &door_part_controls[nr];
+      struct DoorPartControlInfo *dpc = &door_part_controls[i];
       struct GraphicInfo *g = &graphic_info[dpc->graphic];
       int door_token = dpc->door_nr;
 
-      door_part_done[nr] = (!(door_state & door_token) ||
-                           !g->bitmap);
+      door_part_done[i] = (!(door_state & door_token) ||
+                          !g->bitmap);
     }
 
-    for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
+#if 0
+    for (i = 0; i < MAX_DOOR_PARTS; i++)
+    {
+      struct DoorPartControlInfo *dpc = &door_part_controls[i];
+      struct DoorPartPosInfo *pos = dpc->pos;
+      int start_step = pos->start_step;
+
+      printf("::: ---> %d: start_step == %d [%d]\n",
+            i, start_step, door_part_done[i]);
+    }
+#endif
+
+    for (i = 0; i < MAX_DOOR_PARTS; i++)
     {
       struct DoorPartControlInfo *dpc = &door_part_controls[i];
       struct GraphicInfo *g = &graphic_info[dpc->graphic];
@@ -5507,34 +5529,33 @@ unsigned int MoveDoor(unsigned int door_state)
       int step_xoffset = ABS(pos->step_xoffset);
       int step_yoffset = ABS(pos->step_yoffset);
       int step_delay = pos->step_delay;
-      int move_xsize = (step_xoffset ? g->width  : 0);
-      int move_ysize = (step_yoffset ? g->height : 0);
-      /*
-      int move_size = (move_xsize && move_ysize ?
-                      MIN(move_xsize, move_ysize) :
-                      move_xsize ? move_xsize : move_ysize);
-      */
-      int move_xsteps = (step_xoffset ? CEIL(move_xsize, step_xoffset) : 0);
-      int move_ysteps = (step_yoffset ? CEIL(move_ysize, step_yoffset) : 0);
-      /*
-      int move_xdelay = move_xsteps * step_delay;
-      int move_ydelay = move_ysteps * step_delay;
-      int move_delay = (move_xdelay && move_ydelay ?
-                       MIN(move_xdelay, move_ydelay) :
-                       move_xdelay ? move_xdelay : move_ydelay);
-      */
+      int start_step = pos->start_step;
+      float move_xsize = (step_xoffset ? g->width  : 0);
+      float move_ysize = (step_yoffset ? g->height : 0);
+      int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
+      int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
       int move_steps = (move_xsteps && move_ysteps ?
                        MIN(move_xsteps, move_ysteps) :
-                       move_xsteps ? move_xsteps : move_ysteps);
+                       move_xsteps ? move_xsteps : move_ysteps) - start_step;
       int move_delay = move_steps * step_delay;
-      // int move_delay = MAX(move_xsize, move_ysize) * step_delay;
+
+      if (door_part_done[i])
+       continue;
 
       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[i] = move_steps;
+
+#if 0
 #if 0
-      num_xsteps[i] = move_xsteps;
-      num_ysteps[i] = move_ysteps;
+      printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
+            i, move_delay, start_step, door_part_order[i].nr);
+#else
+      if (DOOR_PART_IS_PANEL(i))
+       printf("::: %d: move_delay == %d, start_step == %d\n",
+              i, move_delay, start_step);
+#endif
 #endif
     }
 
@@ -5543,14 +5564,11 @@ unsigned int MoveDoor(unsigned int door_state)
     door_delay_value = max_step_delay;
 
 #if 0
-    printf("::: max_move_delay == %d, max_step_delay == %d, num_move_steps == %d\n",
-          max_move_delay, max_step_delay, num_move_steps);
+    door_delay_value *= 10;
 #endif
 
 #if 0
-    for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
-      printf("::: door_part_done[%d] == %d\n", i, door_part_done[i]);
-    printf("\n");
+    printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
 #endif
 
     for (k = 0; k < num_move_steps; k++)
@@ -5558,22 +5576,52 @@ unsigned int MoveDoor(unsigned int door_state)
       for (i = 0; i < NUM_DOORS; i++)
        door_panel_drawn[i] = FALSE;
 
-      for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
+      for (i = 0; i < MAX_DOOR_PARTS; i++)
       {
        int nr = door_part_order[i].nr;
        struct DoorPartControlInfo *dpc = &door_part_controls[nr];
        int door_token = dpc->door_nr;
        int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
+       boolean is_panel = DOOR_PART_IS_PANEL(nr);
        struct GraphicInfo *g = &graphic_info[dpc->graphic];
        struct DoorPartPosInfo *pos = dpc->pos;
        struct XY *panel_pos = &panel_pos_list[door_index];
        struct Rect *door_rect = &door_rect_list[door_index];
-       int src_xx, src_yy;
-       int dst_xx, dst_yy;
+       Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
+       int current_door_state = door_state & door_token;
+       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
+       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
+       boolean mode_opening = (is_panel ? door_closing : door_opening);
+       int start_step = pos->start_step;
+       int step_delay = pos->step_delay;
+       int step_factor = step_delay / max_step_delay;
+       int k1 = (step_factor ? k / step_factor + 1 : k);
+       int k2 = (mode_opening ? k1 + start_step : num_steps[nr] - k1);
+       int kk = (k2 < 0 ? 0 : k2);
+       int src_x, src_y, src_xx, src_yy;
+       int dst_x, dst_y, dst_xx, dst_yy;
        int width, height;
 
+#if 0
+       if (DOOR_PART_IS_PANEL(nr))
+       {
+         int start_step = pos->start_step;
+
+         k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
+         kk = (k2 < 0 ? 0 : k2);
+       }
+#endif
+
+#if 0
+       // !!! TEST !!! 
+       if (nr != 16 && nr != 0)
+         continue;
+#endif
+
+#if 0
        if (door_part_done[nr])
          continue;
+#endif
 
        if (!(door_state & door_token))
          continue;
@@ -5581,167 +5629,134 @@ unsigned int MoveDoor(unsigned int door_state)
        if (!g->bitmap)
          continue;
 
+#if 0
+       if (current_move_delay % step_delay)
+         continue;
+#endif
+
+       // draw door panel
+
        if (!door_panel_drawn[door_index])
        {
+#if 1
+         ClearRectangle(drawto, door_rect->x, door_rect->y,
+                        door_rect->width, door_rect->height);
+#else
          BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
                     door_rect->width, door_rect->height,
                     door_rect->x, door_rect->y);
+#endif
 
          door_panel_drawn[door_index] = TRUE;
        }
 
-#if 1
-       if ((door_state & door_token) & DOOR_OPEN)
-       {
-#if 0
-         // !!! TEST !!!       
-         if (nr != 2)
-           continue;
-#endif
+       // draw opening or closing door parts
 
-#if 0
-         if (k == 0)
-           printf("::: step_xoffset == %d, step_yoffset == %d\n",
-                  pos->step_xoffset, pos->step_yoffset);
-#endif
-
-         if (pos->step_xoffset < 0)
-         {
-#if 1
-           src_xx = 0;
-           dst_xx = pos->x + ABS(k * pos->step_xoffset);
-           width = g->width;
-
-           if (dst_xx + width > door_rect->width)
-             width = door_rect->width - dst_xx;
-#else
-           src_xx = 0;
-           width = g->width + k * pos->step_xoffset;
+       if (pos->step_xoffset < 0)      // door part on right side
+       {
+         src_xx = 0;
+         dst_xx = pos->x + ABS(kk * pos->step_xoffset);
+         width = g->width;
 
-           if (width > door_rect->width)
-             width = door_rect->width;
+         if (dst_xx + width > door_rect->width)
+           width = door_rect->width - dst_xx;
+       }
+       else                            // door part on left side
+       {
+         src_xx = 0;
+         dst_xx = pos->x - kk * pos->step_xoffset;
 
-           dst_xx = door_rect->width - width;
-#endif
-         }
-         else
+         if (dst_xx < 0)
          {
-           src_xx = 0;
-           dst_xx = pos->x - k * pos->step_xoffset;
-
-           if (dst_xx < 0)
-           {
-             src_xx = ABS(dst_xx);
-             dst_xx = 0;
-           }
-
-           width = g->width - src_xx;
+           src_xx = ABS(dst_xx);
+           dst_xx = 0;
          }
 
-         if (pos->step_yoffset < 0)
-         {
-#if 1
-           src_yy = 0;
-           dst_yy = pos->y + ABS(k * pos->step_yoffset);
-           height = g->height;
-
-           if (dst_yy + height > door_rect->height)
-             height = door_rect->height - dst_yy;
-#else
-           src_yy = 0;
-           height = g->height + k * pos->step_yoffset;
-
-           if (height > door_rect->height)
-             height = door_rect->height;
-
-           dst_yy = door_rect->height - height;
-#endif
-         }
-         else
-         {
-           src_yy = 0;
-           dst_yy = pos->y - k * pos->step_yoffset;
+         width = g->width - src_xx;
 
-           if (dst_yy < 0)
-           {
-             src_yy = ABS(dst_yy);
-             dst_yy = 0;
-           }
+         // printf("::: k == %d [%d] \n", k, start_step);
+       }
 
-           height = g->height - src_yy;
-         }
+       if (pos->step_yoffset < 0)      // door part on bottom side
+       {
+         src_yy = 0;
+         dst_yy = pos->y + ABS(kk * pos->step_yoffset);
+         height = g->height;
 
-         if (width < 0 || height < 0)
-           door_part_done[nr] = TRUE;
+         if (dst_yy + height > door_rect->height)
+           height = door_rect->height - dst_yy;
        }
-       else    // DOOR_CLOSE
+       else                            // door part on top side
        {
-#if 1
-         // !!! TEST !!!
-
-         door_part_done[nr] = TRUE;
+         src_yy = 0;
+         dst_yy = pos->y - kk * pos->step_yoffset;
 
-         BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
-                          g->width, g->height,
-                          door_rect->x + pos->x, door_rect->y + pos->y);
+         if (dst_yy < 0)
+         {
+           src_yy = ABS(dst_yy);
+           dst_yy = 0;
+         }
 
-         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
-#else
-         src_xx = (num_xsteps[nr] - k) * pos->step_xoffset;
-         src_yy = (num_ysteps[nr] - k) * pos->step_yoffset;
-         dst_xx = pos->x;
-         dst_yy = pos->y;
-         width  = g->width  - src_xx;
          height = g->height - src_yy;
+       }
 
-         // if (width < ABS(pos->step_xoffset)
-
-
-
-
-         src_xx = g->width  - k * pos->step_xoffset;
-         src_yy = g->height - k * pos->step_yoffset;
-         dst_xx = pos->x;
-         dst_yy = pos->y;
-
-         if (width < 0 || height < 0)
-           door_part_done[nr] = TRUE;
-#endif
+       if (is_panel)
+       {
+         src_x = panel_pos->x + src_xx;
+         src_y = panel_pos->y + src_yy;
+       }
+       else
+       {
+         src_x = g->src_x + src_xx;
+         src_y = g->src_y + src_yy;
        }
 
-       if (door_part_done[nr])
-         continue;
+       dst_x = door_rect->x + dst_xx;
+       dst_y = door_rect->y + dst_yy;
 
 #if 0
-       // !!! TEST !!! 
-       if (nr != 7)
-         continue;
+       if (DOOR_PART_IS_PANEL(nr))
+       {
+         printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
+                width, height, g->width, g->height, src_x, src_y);
+       }
 #endif
 
-       BlitBitmapMasked(g->bitmap, drawto,
-                        g->src_x + src_xx, g->src_y + src_yy, width, height,
-                        door_rect->x + dst_xx, door_rect->y + dst_yy);
-#else
-       // !!! TEST !!!
-       if (!((door_state & door_token) & DOOR_CLOSE))
-         continue;
+       if (width  >= 0 && width  <= g->width &&
+           height >= 0 && height <= g->height)
+       {
+         if (is_panel || !pos->draw_masked)
+           BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
+                      dst_x, dst_y);
+         else
+           BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
+                            dst_x, dst_y);
+       }
 
-       BlitBitmapMasked(g->bitmap, drawto, g->src_x, g->src_y,
-                        g->width, g->height,
-                        door_rect->x + pos->x, door_rect->y + pos->y);
+#if 0
+       if (DOOR_PART_IS_PANEL(nr))
+       {
+         bitmap = bitmap_db_door;
+         src_x = panel_pos->x + src_xx;
+         src_y = panel_pos->y + src_yy;
+
+         printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
+                width, height, g->width, g->height, src_x, src_y);
+
+         if (width  >= 0 && width  <= g->width &&
+             height >= 0 && height <= g->height)
+           BlitBitmap(bitmap, drawto, src_x, src_y,
+                            width, height,
+                            dst_x, dst_y);
+       }
 #endif
 
        redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
-      }
-
-      door_part_done_all = TRUE;
-
-      for (i = 0; i < NUM_DOORS * MAX_NUM_DOOR_PARTS; i++)
-       if (!door_part_done[i])
-         door_part_done_all = FALSE;
 
-      if (door_part_done_all)
-       break;
+       if ((door_opening && (width < 0         || height < 0)) ||
+           (door_closing && (width >= g->width && height >= g->height)))
+         door_part_done[nr] = TRUE;
+      }
 
       if (!(door_state & DOOR_NO_DELAY))
       {
@@ -5751,12 +5766,23 @@ unsigned int MoveDoor(unsigned int door_state)
          DoAnimation();
 
        WaitUntilDelayReached(&door_delay, door_delay_value);
+
+       current_move_delay += max_step_delay;
       }
+
+      door_part_done_all = TRUE;
+
+      for (i = 0; i < MAX_DOOR_PARTS; i++)
+       if (!door_part_done[i])
+         door_part_done_all = FALSE;
+
+#if 0
+      if (door_part_done_all)
+       break;
+#endif
     }
   }
 
-  redraw_mask |= REDRAW_ALL;
-
   if (door_state & DOOR_ACTION_1)
     door1 = door_state & DOOR_ACTION_1;
   if (door_state & DOOR_ACTION_2)