fixed showing special toolbox buttons for empty space elements in editor
[rocksndiamonds.git] / src / editor.c
index 7bc6dcd7bcaaa71674b799b08fc1fb64c0fb76ee..4f29f028a7bc245c1b3abb4222aae4095c0f6be2 100644 (file)
@@ -3800,7 +3800,7 @@ static struct
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
-    &custom_element.gfx_element_initial,1, 1,
+    &custom_element.gfx_element_initial, 1, 1,
     NULL, NULL, NULL, NULL,            "custom graphic element"
   },
 
@@ -3914,7 +3914,7 @@ static int level_xpos = -1, level_ypos = -1;
 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
 
-#define IN_ED_FIELD(x,y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
+#define IN_ED_FIELD(x, y)      IN_FIELD(x, y, ed_fieldx, ed_fieldy)
 
 // drawing elements on the three mouse buttons
 static int new_element1 = EL_WALL;
@@ -3973,6 +3973,7 @@ static boolean getDrawModeHiRes(void);
 static int getTabulatorBarWidth(void);
 static int getTabulatorBarHeight(void);
 static Pixel getTabulatorBarColor(void);
+static int numHiresTiles(int);
 
 static int num_editor_gadgets = 0;     // dynamically determined
 
@@ -5742,9 +5743,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   // find all elements used in current level
   for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
-      if (Tile[x][y] < NUM_FILE_ELEMENTS)      // should always be true
+    {
+      if (Tile[x][y] >= NUM_FILE_ELEMENTS)     // should never happen
+       continue;
+
+      if (IS_MM_WALL(Tile[x][y]))
+       element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
+      else
        element_found[Tile[x][y]] = TRUE;
+    }
+  }
 
   *num_elements = 0;
 
@@ -5764,14 +5774,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   *num_elements = 0;
 
-  // add all elements used in current level (non-custom/group elements)
+  // add all elements used in current level (non-custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
+                             IS_GROUP_ELEMENT(i) ||
+                             IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
-  // add all elements used in current level (custom/group elements)
+  // add all elements used in current level (custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
+                            IS_GROUP_ELEMENT(i) ||
+                            IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
   while (*num_elements % 4)    // pad with empty elements, if needed
@@ -7662,7 +7676,7 @@ static void MapCheckbuttonGadget(int id)
 
   // set position for gadgets with dynamically determined position
   if (checkbutton_info[id].x != -1)    // do not change dynamic positions
-    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END);
+    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
 
   x_left = gi->x - xoffset_left;
@@ -8167,6 +8181,12 @@ static boolean CopyCustomElement(int element_old, int element_new,
 
     return FALSE;
   }
+  else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
+  {
+    Request("Please choose empty element!", REQ_CONFIRM);
+
+    return FALSE;
+  }
   else
   {
     level.changed = TRUE;
@@ -9747,13 +9767,16 @@ static void DrawPropertiesInfo(void)
     { -1,                      NULL                                    }
   };
   char *filename = getElementDescriptionFilename(properties_element);
-  char *percentage_text = "In this level: ";
+  char *num_elements_text = "In this level: ";
+  char *num_similar_text = "Similar tiles: ";
   char *properties_text = "Standard properties: ";
   char *description_text = "Description:";
   char *no_description_text = "No description available.";
   char *none_text = "None";
   float percentage;
-  int num_elements_in_level;
+  int num_elements_in_level = 0;
+  int num_similar_in_level = 0;
+  int num_hires_tiles_in_level = 0;
   int num_standard_properties = 0;
   int font1_nr = FONT_TEXT_1;
   int font2_nr = FONT_TEXT_2;
@@ -9762,7 +9785,8 @@ static void DrawPropertiesInfo(void)
   int font2_height = getFontHeight(font2_nr);
   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
   int font2_yoffset = (font1_height - font2_height) / 2;
-  int percentage_text_len = strlen(percentage_text) * font1_width;
+  int num_elements_text_len = strlen(num_elements_text) * font1_width;
+  int num_similar_text_len = strlen(num_similar_text) * font1_width;
   int properties_text_len = strlen(properties_text) * font1_width;
   int xpos = ED_ELEMENT_SETTINGS_X(0);
   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
@@ -9781,22 +9805,66 @@ static void DrawPropertiesInfo(void)
 
   // ----- print number of elements / percentage of this element in level
 
-  num_elements_in_level = 0;
-  for (y = 0; y < lev_fieldy; y++) 
+  for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
+    {
       if (Tile[x][y] == properties_element)
+      {
        num_elements_in_level++;
+      }
+      else if (IS_MM_WALL(Tile[x][y]) &&
+              map_mm_wall_element(Tile[x][y]) == properties_element)
+      {
+       num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
+      }
+    }
+  }
+
   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-  DrawTextS(xpos, ypos, font1_nr, percentage_text);
+  DrawTextS(xpos, ypos, font1_nr, num_elements_text);
 
-  if (num_elements_in_level > 0)
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+  if (num_hires_tiles_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
+             "%d wall tiles", num_hires_tiles_in_level);
+  else if (num_elements_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              "%d (%.2f %%)", num_elements_in_level, percentage);
   else
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              none_text);
 
+  // ----- print number of similar elements / percentage of them in level
+
+  for (y = 0; y < lev_fieldy; y++)
+  {
+    for (x = 0; x < lev_fieldx; x++)
+    {
+      if (strEqual(element_info[Tile[x][y]].class_name,
+                  element_info[properties_element].class_name))
+      {
+       num_similar_in_level++;
+      }
+    }
+  }
+
+  if (num_similar_in_level != num_elements_in_level)
+  {
+    ypos += 1 * MAX(font1_height, font2_height);
+
+    percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
+
+    DrawTextS(xpos, ypos, font1_nr, num_similar_text);
+
+    if (num_similar_in_level > 0)
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               "%d (%.2f %%)", num_similar_in_level, percentage);
+    else
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               none_text);
+  }
+
   ypos += 2 * MAX(font1_height, font2_height);
 
   // ----- print standard properties of this element
@@ -9910,9 +9978,9 @@ static struct
   { EL_NUT,            &level.score[SC_NUT],           TEXT_CRACKING   },
   { EL_DYNAMITE,       &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
   { EL_EM_DYNAMITE,    &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE],TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE], TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE], TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE], TEXT_COLLECTING },
   { EL_SHIELD_NORMAL,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
   { EL_SHIELD_DEADLY,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
   { EL_EXTRA_TIME,     &level.extra_time_score,        TEXT_COLLECTING },
@@ -10615,7 +10683,8 @@ static void DrawPropertiesWindow(void)
   UnmapLevelEditorToolboxCustomGadgets();
 
   if (IS_CUSTOM_ELEMENT(properties_element) ||
-      IS_GROUP_ELEMENT(properties_element))
+      IS_GROUP_ELEMENT(properties_element) ||
+      IS_EMPTY_ELEMENT(properties_element))
     MapLevelEditorToolboxCustomGadgets();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
@@ -11940,6 +12009,23 @@ static boolean isHiresDrawElement(int element)
   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
 }
 
+static int numHiresTiles(int element)
+{
+  if (!IS_MM_WALL(element))
+    return 1;
+
+  int bits = MM_WALL_BITS(element);
+  int num_bits = 0;
+
+  while (bits)
+  {
+    bits &= bits - 1;
+    num_bits++;
+  }
+
+  return num_bits;
+}
+
 static void SetDrawModeHiRes(int element)
 {
   draw_mode_hires =
@@ -12170,7 +12256,7 @@ static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
-  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
+  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
 }
 #endif
 
@@ -13148,7 +13234,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          SetDrawModeHiRes(new_element);
 
-         if (IS_PLAYER_ELEMENT(new_element))
+         if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
          {
            // remove player at old position
            for (y = 0; y < lev_fieldy; y++)
@@ -13157,7 +13243,8 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
              {
                int old_element = Tile[x][y];
 
-               if (IS_PLAYER_ELEMENT(old_element))
+               if (IS_PLAYER_ELEMENT(old_element) &&
+                   IS_PLAYER_ELEMENT(new_element))
                {
                  int replaced_with_element =
                    (old_element == EL_SOKOBAN_FIELD_PLAYER &&
@@ -13177,6 +13264,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
                  SetElement(x, y, replaced_with_element);
                }
+               else if (IS_MM_MCDUFFIN(old_element) &&
+                        IS_MM_MCDUFFIN(new_element))
+               {
+                 // remove McDuffin at old position
+                 SetElement(x, y, EL_EMPTY);
+               }
              }
            }
          }
@@ -14730,7 +14823,7 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
       sy = ly - level_ypos;
     }
 
-    if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
+    if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
     {
       if (button_status)       // if (gi->state == GD_BUTTON_PRESSED)
       {