fixed drawing of inner corners for growing/shrinking crumbled elements
[rocksndiamonds.git] / src / tools.c
index b563b9318c16a897fd2700442b0e1c5bfa034285..7888dca70b1addb1f994aae8d73035ee69c35e75 100644 (file)
@@ -1219,52 +1219,64 @@ int getGraphicAnimationFrame(int graphic, int sync_frame)
                           sync_frame);
 }
 
-void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
-                             Bitmap **bitmap, int *x, int *y,
-                             boolean get_backside)
+void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
-  Bitmap *src_bitmap = g->bitmap;
-  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);
 
-  // if no in-game graphics defined, always use standard graphic size
-  if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
-    tilesize = TILESIZE;
-
   if (tilesize == gfx.standard_tile_size)
-    src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
+    *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
   else if (tilesize == game.tile_size)
-    src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
+    *bitmap = g->bitmaps[IMG_BITMAP_GAME];
   else
-    src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+    *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+}
+
+void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
+                       boolean get_backside)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
+  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
 
   if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
     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 % g->height + pos / max_width * g->height;
+    *x = pos % max_width;
+    *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 * g->height;
     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
 
-    src_x = src_x % g->width + pos / max_height * g->width;
-    src_y = pos % max_height;
+    *x = src_x % g->width + pos / max_height * g->width;
+    *y = pos % max_height;
   }
   else                         /* frames are ordered diagonally */
   {
-    src_x = src_x + frame * g->offset_x;
-    src_y = src_y + frame * g->offset_y;
+    *x = src_x + frame * g->offset_x;
+    *y = src_y + frame * g->offset_y;
   }
+}
+
+void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
+                             Bitmap **bitmap, int *x, int *y,
+                             boolean get_backside)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+
+  // if no in-game graphics defined, always use standard graphic size
+  if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
+    tilesize = TILESIZE;
+
+  getGraphicSourceBitmap(graphic, tilesize, bitmap);
+  getGraphicSourceXY(graphic, frame, x, y, get_backside);
 
-  *bitmap = src_bitmap;
-  *x = src_x * tilesize / g->tile_size;
-  *y = src_y * tilesize / g->tile_size;
+  *x = *x * tilesize / g->tile_size;
+  *y = *y * tilesize / g->tile_size;
 }
 
 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
@@ -1294,40 +1306,8 @@ void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
                                       int *x, int *y, boolean get_backside)
 {
-  struct GraphicInfo *g = &graphic_info[graphic];
-  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
-  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
-
-  if (TILESIZE_VAR != TILESIZE)
-    return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
-                                   get_backside);
-
-  *bitmap = g->bitmap;
-
-  if (g->offset_y == 0)                /* frames are ordered horizontally */
-  {
-    int max_width = g->anim_frames_per_line * g->width;
-    int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
-
-    *x = pos % max_width;
-    *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 * g->height;
-    int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
-
-    *x = src_x % g->width + pos / max_height * g->width;
-    *y = pos % max_height;
-  }
-  else                         /* frames are ordered diagonally */
-  {
-    *x = src_x + frame * g->offset_x;
-    *y = src_y + frame * g->offset_y;
-  }
-
-  *x = *x * TILESIZE_VAR / g->tile_size;
-  *y = *y * TILESIZE_VAR / g->tile_size;
+  getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
+                          get_backside);
 }
 
 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
@@ -1780,6 +1760,9 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
   int width, height, cx, cy;
   int sx = SCREENX(x), sy = SCREENY(y);
   int crumbled_border_size = graphic_info[graphic].border_size;
+  int crumbled_tile_size = graphic_info[graphic].tile_size;
+  int crumbled_border_size_var =
+    crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
   int i;
 
   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
@@ -1807,8 +1790,8 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
 
   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
 
-  width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
-  height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
+  width  = crumbled_border_size_var;
+  height = crumbled_border_size_var;
   cx = (dx > 0 ? TILESIZE_VAR - width  : 0);
   cy = (dy > 0 ? TILESIZE_VAR - height : 0);
 
@@ -1824,7 +1807,9 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
   int width, height, bx, by, cx, cy;
   int sx = SCREENX(x), sy = SCREENY(y);
   int crumbled_border_size = graphic_info[graphic].border_size;
-  int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
+  int crumbled_tile_size = graphic_info[graphic].tile_size;
+  int crumbled_border_size_var =
+    crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
   int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
   int i;
 
@@ -1843,7 +1828,7 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
 
   /* (remaining middle border part must be at least as big as corner part) */
   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
-      crumbled_border_size >= TILESIZE / 3)
+      crumbled_border_size_var >= TILESIZE_VAR / 3)
     return;
 
   /* correct corners of crumbled border, if needed */
@@ -1911,12 +1896,12 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
 
   element = TILE_GFX_ELEMENT(x, y);
 
-  /* crumble field itself */
-  if (IS_CRUMBLED_TILE(x, y, element))
+  if (IS_CRUMBLED_TILE(x, y, element))         /* crumble field itself */
   {
     if (!IN_SCR_FIELD(sx, sy))
       return;
 
+    /* crumble field borders towards direct neighbour fields */
     for (i = 0; i < 4; i++)
     {
       int xx = x + xy[i][0];
@@ -1934,6 +1919,7 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
     }
 
+    /* crumble inner field corners towards corner neighbour fields */
     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
        graphic_info[graphic].anim_frames == 2)
     {
@@ -1948,8 +1934,9 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
 
     MarkTileDirty(sx, sy);
   }
-  else         /* center field not crumbled -- crumble neighbour fields */
+  else         /* center field is not crumbled -- crumble neighbour fields */
   {
+    /* crumble field borders of direct neighbour fields */
     for (i = 0; i < 4; i++)
     {
       int xx = x + xy[i][0];
@@ -1975,6 +1962,37 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
 
       MarkTileDirty(sxx, syy);
     }
+
+    /* crumble inner field corners of corner neighbour fields */
+    for (i = 0; i < 4; i++)
+    {
+      int dx = (i & 1 ? +1 : -1);
+      int dy = (i & 2 ? +1 : -1);
+      int xx = x + dx;
+      int yy = y + dy;
+      int sxx = sx + dx;
+      int syy = sy + dy;
+
+      if (!IN_LEV_FIELD(xx, yy) ||
+         !IN_SCR_FIELD(sxx, syy))
+       continue;
+
+      if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
+       continue;
+
+      element = TILE_GFX_ELEMENT(xx, yy);
+
+      if (!IS_CRUMBLED_TILE(xx, yy, element))
+       continue;
+
+      graphic = el_act2crm(element, ACTION_DEFAULT);
+
+      if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
+         graphic_info[graphic].anim_frames == 2)
+       DrawLevelFieldCrumbledInnerCorners(xx, yy, -dx, -dy, graphic);
+
+      MarkTileDirty(sxx, syy);
+    }
   }
 }
 
@@ -2024,6 +2042,7 @@ void DrawLevelFieldCrumbledNeighbours(int x, int y)
   };
   int i;
 
+  /* crumble direct neighbour fields (required for field borders) */
   for (i = 0; i < 4; i++)
   {
     int xx = x + xy[i][0];
@@ -2039,6 +2058,30 @@ void DrawLevelFieldCrumbledNeighbours(int x, int y)
 
     DrawLevelField(xx, yy);
   }
+
+  /* crumble corner neighbour fields (required for inner field corners) */
+  for (i = 0; i < 4; i++)
+  {
+    int dx = (i & 1 ? +1 : -1);
+    int dy = (i & 2 ? +1 : -1);
+    int xx = x + dx;
+    int yy = y + dy;
+    int sxx = sx + dx;
+    int syy = sy + dy;
+
+    if (!IN_LEV_FIELD(xx, yy) ||
+       !IN_SCR_FIELD(sxx, syy) ||
+       !GFX_CRUMBLED(Feld[xx][yy]) ||
+       IS_MOVING(xx, yy))
+      continue;
+
+    int element = TILE_GFX_ELEMENT(xx, yy);
+    int graphic = el_act2crm(element, ACTION_DEFAULT);
+
+    if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
+       graphic_info[graphic].anim_frames == 2)
+      DrawLevelField(xx, yy);
+  }
 }
 
 static int getBorderElement(int x, int y)
@@ -3685,7 +3728,10 @@ static int RequestHandleEvents(unsigned int req_state)
          }
 
          case EVENT_KEYPRESS:
-           switch (GetEventKey((KeyEvent *)&event, TRUE))
+         {
+           Key key = GetEventKey((KeyEvent *)&event, TRUE);
+
+           switch (key)
            {
              case KSYM_space:
                if (req_state & REQ_CONFIRM)
@@ -3707,12 +3753,15 @@ static int RequestHandleEvents(unsigned int req_state)
                break;
 
              default:
+               HandleKeysDebug(key);
                break;
            }
 
            if (req_state & REQ_PLAYER)
              result = 0;
+
            break;
+         }
 
          case EVENT_KEYRELEASE:
            ClearPlayerAction();
@@ -4474,7 +4523,8 @@ unsigned int MoveDoor(unsigned int door_state)
          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);
+         getFixedGraphicSource(dpc->graphic, frame, &bitmap,
+                               &g_src_x, &g_src_y);
        }
 
        // draw door panel
@@ -7278,6 +7328,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
                     &g_em->crumbled_src_x, &g_em->crumbled_src_y);
 
     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
+    g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
 
     g_em->has_crumbled_graphics = TRUE;
   }
@@ -7287,6 +7338,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
     g_em->crumbled_src_x = 0;
     g_em->crumbled_src_y = 0;
     g_em->crumbled_border_size = 0;
+    g_em->crumbled_tile_size = 0;
 
     g_em->has_crumbled_graphics = FALSE;
   }
@@ -8046,42 +8098,38 @@ void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
                                boolean any_player_snapping,
                                boolean any_player_dropping)
 {
-  static boolean player_was_waiting = TRUE;
-
   if (frame == 0 && !any_player_dropping)
   {
-    if (!player_was_waiting)
+    if (!local_player->was_waiting)
     {
-      if (!SaveEngineSnapshotToList())
+      if (!CheckSaveEngineSnapshotToList())
        return;
 
-      player_was_waiting = TRUE;
+      local_player->was_waiting = TRUE;
     }
   }
   else if (any_player_moving || any_player_snapping || any_player_dropping)
   {
-    player_was_waiting = FALSE;
+    local_player->was_waiting = FALSE;
   }
 }
 
 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
                                boolean murphy_is_dropping)
 {
-  static boolean player_was_waiting = TRUE;
-
   if (murphy_is_waiting)
   {
-    if (!player_was_waiting)
+    if (!local_player->was_waiting)
     {
-      if (!SaveEngineSnapshotToList())
+      if (!CheckSaveEngineSnapshotToList())
        return;
 
-      player_was_waiting = TRUE;
+      local_player->was_waiting = TRUE;
     }
   }
   else
   {
-    player_was_waiting = FALSE;
+    local_player->was_waiting = FALSE;
   }
 }