added level editor support for Mirror Magic (and Deflektor) game elements
[rocksndiamonds.git] / src / editor.c
index 29bf2c7bff7b785a3927e7193adb4cf5808d1ce2..6338734733b0ea65a74856e13b654570a0eb090b 100644 (file)
 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1   4
 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2   5
 #define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE     6
-#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1    7
-#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2    8
+#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2    7
+#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1    8
 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE       9
 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE       10
 
 #define ED_NUM_TEXTBUTTONS                     11
 
-#define ED_TEXTBUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
-#define ED_TEXTBUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
+#define ED_TAB_BUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
+#define ED_TAB_BUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
 
-#define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
-#define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
+#define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
+#define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
 
 #define ED_TEXTBUTTON_ID_CHANGE_FIRST  ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
 #define ED_TEXTBUTTON_ID_CHANGE_LAST   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
@@ -2630,20 +2630,23 @@ static struct
     NULL, NULL, NULL,                  "Configure custom element change pages"
   },
 
-  /* ---------- element settings (buttons) --------------------------------- */
+  /* ---------- level and editor settings (buttons) ------------------------ */
 
   {
-    -1,                                        -1,
-    GADGET_ID_SAVE_AS_TEMPLATE_1,      GADGET_ID_CUSTOM_USE_TEMPLATE_1,
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(6),
+    GADGET_ID_SAVE_AS_TEMPLATE_2,      GADGET_ID_NONE,
     -1,                                        "Save",
-    NULL, " ",                         "As Template",
+    NULL, NULL,                                "this level as level template",
     "Save current settings as new template"
   },
+
+  /* ---------- element settings (buttons) --------------------------------- */
+
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(6),
-    GADGET_ID_SAVE_AS_TEMPLATE_2,      GADGET_ID_NONE,
+    -1,                                        -1,
+    GADGET_ID_SAVE_AS_TEMPLATE_1,      GADGET_ID_CUSTOM_USE_TEMPLATE_1,
     -1,                                        "Save",
-    NULL, NULL,                                "this level as level template",
+    NULL, " ",                         "As Template",
     "Save current settings as new template"
   },
   {
@@ -4212,6 +4215,116 @@ static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
 static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash);
 static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash);
 
+static int editor_hl_mirror_magic[] =
+{
+  EL_INTERNAL_CASCADE_MM_ACTIVE,
+  EL_CHAR('M'),
+  EL_CHAR('M'),
+  EL_EMPTY,
+};
+
+static int editor_el_mirror_magic[] =
+{
+  EL_MM_MCDUFFIN_RIGHT,
+  EL_MM_MCDUFFIN_UP,
+  EL_MM_MCDUFFIN_LEFT,
+  EL_MM_MCDUFFIN_DOWN,
+
+  EL_MM_MIRROR_START,
+  EL_MM_MIRROR_FIXED_START,
+  EL_MM_POLARISATOR_START,
+  EL_MM_POLARISATOR_CROSS_START,
+
+  EL_MM_BEAMER_RED_START,
+  EL_MM_BEAMER_YELLOW_START,
+  EL_MM_BEAMER_GREEN_START,
+  EL_MM_BEAMER_BLUE_START,
+
+  EL_MM_PRISM,
+  EL_MM_FUSE_ACTIVE,
+  EL_MM_PACMAN_RIGHT,
+  EL_MM_EXIT_CLOSED,
+
+  EL_MM_KETTLE,
+  EL_MM_BOMB,
+  EL_MM_KEY,
+  EL_MM_FUEL_FULL,
+
+  EL_MM_LIGHTBULB,
+  EL_MM_LIGHTBULB_ACTIVE,
+  EL_MM_GRAY_BALL,
+  EL_MM_LIGHTBALL,
+
+  EL_MM_STEEL_WALL,
+  EL_MM_WOODEN_WALL,
+  EL_MM_ICE_WALL,
+  EL_MM_AMOEBA_WALL,
+
+  EL_MM_STEEL_LOCK,
+  EL_MM_WOODEN_LOCK,
+  EL_MM_STEEL_BLOCK,
+  EL_MM_WOODEN_BLOCK,
+
+  EL_MM_STEEL_GRID_FIXED_1,
+  EL_MM_STEEL_GRID_FIXED_2,
+  EL_MM_STEEL_GRID_FIXED_3,
+  EL_MM_STEEL_GRID_FIXED_4,
+
+  EL_MM_WOODEN_GRID_FIXED_1,
+  EL_MM_WOODEN_GRID_FIXED_2,
+  EL_MM_WOODEN_GRID_FIXED_3,
+  EL_MM_WOODEN_GRID_FIXED_4
+};
+static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
+static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
+static int num_editor_hl_mirror_magic = SIZEOF_ARRAY_INT(editor_hl_mirror_magic);
+static int num_editor_el_mirror_magic = SIZEOF_ARRAY_INT(editor_el_mirror_magic);
+
+static int editor_hl_deflektor[] =
+{
+  EL_INTERNAL_CASCADE_DF_ACTIVE,
+  EL_CHAR('D'),
+  EL_CHAR('F'),
+  EL_EMPTY,
+};
+
+static int editor_el_deflektor[] =
+{
+  EL_DF_LASER_RIGHT,
+  EL_DF_LASER_UP,
+  EL_DF_LASER_LEFT,
+  EL_DF_LASER_DOWN,
+
+  EL_DF_RECEIVER_RIGHT,
+  EL_DF_RECEIVER_UP,
+  EL_DF_RECEIVER_LEFT,
+  EL_DF_RECEIVER_DOWN,
+
+  EL_DF_MIRROR_START,
+  EL_DF_MIRROR_ROTATING_START,
+  EL_DF_CELL,
+  EL_DF_MINE,
+
+  EL_DF_FIBRE_OPTIC_RED_1,
+  EL_DF_FIBRE_OPTIC_YELLOW_1,
+  EL_DF_FIBRE_OPTIC_GREEN_1,
+  EL_DF_FIBRE_OPTIC_BLUE_1,
+
+  EL_DF_STEEL_GRID_FIXED_START,
+  EL_DF_STEEL_GRID_ROTATING_START,
+  EL_DF_WOODEN_GRID_FIXED_START,
+  EL_DF_WOODEN_GRID_ROTATING_START,
+
+  EL_DF_STEEL_WALL,
+  EL_DF_WOODEN_WALL,
+  EL_DF_REFRACTOR,
+  EL_EMPTY
+};
+static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
+static int *editor_el_deflektor_ptr = editor_el_deflektor;
+static int num_editor_hl_deflektor = SIZEOF_ARRAY_INT(editor_hl_deflektor);
+static int num_editor_el_deflektor = SIZEOF_ARRAY_INT(editor_el_deflektor);
+
 static int editor_hl_chars[] =
 {
   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
@@ -4981,6 +5094,18 @@ editor_elements_info[] =
     &editor_hl_dx_boulderdash_ptr,     &num_editor_hl_dx_boulderdash,
     &editor_el_dx_boulderdash_ptr,     &num_editor_el_dx_boulderdash
   },
+  {
+    &setup.editor.el_classic,
+    &setup.editor_cascade.el_mm,
+    &editor_hl_mirror_magic_ptr,       &num_editor_hl_mirror_magic,
+    &editor_el_mirror_magic_ptr,       &num_editor_el_mirror_magic
+  },
+  {
+    &setup.editor.el_classic,
+    &setup.editor_cascade.el_df,
+    &editor_hl_deflektor_ptr,          &num_editor_hl_deflektor,
+    &editor_el_deflektor_ptr,          &num_editor_el_deflektor
+  },
   {
     &setup.editor.el_classic,
     &setup.editor_cascade.el_chars,
@@ -5233,7 +5358,7 @@ static void ReinitializeElementList()
        Error(ERR_WARN, "editor element %d is runtime element", element);
 
       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
-       Error(ERR_WARN, "no element description for element %d", element);
+       Error(ERR_WARN, "no element description text for element %d", element);
     }
   }
 
@@ -7799,7 +7924,8 @@ void CheckElementDescriptions()
 
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
-      Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
+      Error(ERR_WARN, "no element description file for element '%s'",
+           EL_NAME(i));
 }
 
 static int getMaxEdFieldX(boolean has_scrollbar)
@@ -8235,8 +8361,8 @@ static void DrawLevelInfoTabulatorGadgets()
   int gd_x = gd->x + gd_gi1->border.width / 2;
   int gd_y = gd->y + gd_gi1->height - 1;
   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
-  int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL;
-  int id_last  = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR;
+  int id_first = ED_TAB_BUTTON_ID_LEVELINFO_FIRST;
+  int id_last  = ED_TAB_BUTTON_ID_LEVELINFO_LAST;
   int i;
 
   for (i = id_first; i <= id_last; i++)
@@ -8595,41 +8721,22 @@ static void DrawEnvelopeTextArea(int envelope_nr)
   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
 }
 
-static boolean PrintInfoText(char *text, int font_nr, int start_line)
+static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
 {
-  int font_height = getFontHeight(font_nr);
-  int pad_x = ED_ELEMENT_SETTINGS_X(0);
-  int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
-  int sx = SX + pad_x;
-  int sy = SY + pad_y;
-  int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
-
-  if (start_line >= max_lines_per_screen)
-    return FALSE;
-
-  DrawText(sx, sy + start_line * font_height, text, font_nr);
-
-  return TRUE;
+  DrawText(SX + xpos, SY + ypos, text, font_nr);
 }
 
-static int PrintElementDescriptionFromFile(char *filename, int start_line)
+static int PrintElementDescriptionFromFile(char *filename, int font_nr,
+                                          int xpos, int ypos)
 {
-  int font_nr = FONT_TEXT_2;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
-  int pad_x = ED_ELEMENT_SETTINGS_X(0);
-  int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
-  int sx = SX + pad_x;
-  int sy = SY + pad_y + start_line * font_height;
-  int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
-  int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
-  int max_lines_drawable = max_lines_per_screen - start_line;
-
-  if (start_line >= max_lines_per_screen)
-    return FALSE;
+  int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
+  int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
 
-  return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1,
-                     max_lines_drawable, 0, -1, TRUE, FALSE, FALSE);
+  return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
+                     max_chars_per_line, -1, max_lines_drawable, 0, -1,
+                     TRUE, FALSE, FALSE);
 }
 
 static void DrawPropertiesInfo()
@@ -8695,23 +8802,34 @@ static void DrawPropertiesInfo()
   char *filename = getElementDescriptionFilename(properties_element);
   char *percentage_text = "In this level: ";
   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_standard_properties = 0;
   int font1_nr = FONT_TEXT_1;
   int font2_nr = FONT_TEXT_2;
   int font1_width = getFontWidth(font1_nr);
+  int font1_height = getFontHeight(font1_nr);
   int font2_height = getFontHeight(font2_nr);
-  int pad_x = ED_ELEMENT_SETTINGS_X(0);
-  int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
-  int screen_line = 0;
+  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 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;
   int i, x, y;
 
   if (setup.editor.show_element_token)
   {
-    DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
+    int font3_nr = FONT_TEXT_3;
+    int font3_height = getFontHeight(font3_nr);
+
+    DrawTextF(xpos, ypos, font3_nr,
              "[%s]", element_info[properties_element].token_name);
-    screen_line++;
+
+    ypos += 2 * font3_height;
   }
 
   /* ----- print number of elements / percentage of this element in level */
@@ -8723,40 +8841,53 @@ static void DrawPropertiesInfo()
        num_elements_in_level++;
   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-  DrawTextS(pad_x, pad_y + screen_line * font2_height, font1_nr,
-           percentage_text);
-  DrawTextF(pad_x + strlen(percentage_text) * font1_width,
-           pad_y + screen_line++ * font2_height, font2_nr,
-           "%d (%.2f%%)", num_elements_in_level, percentage);
+  DrawTextS(xpos, ypos, font1_nr, percentage_text);
 
-  screen_line++;
+  if (num_elements_in_level > 0)
+    DrawTextF(xpos + percentage_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,
+             none_text);
+
+  ypos += 2 * MAX(font1_height, font2_height);
 
   /* ----- print standard properties of this element */
 
-  DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
-           properties_text);
+  DrawTextS(xpos, ypos, font1_nr, properties_text);
+
+  ypos += line1_height;
 
   for (i = 0; properties[i].value != -1; i++)
   {
     if (!HAS_PROPERTY(properties_element, properties[i].value))
       continue;
 
-    DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
-             properties[i].text);
+    DrawTextS(xpos, ypos, font2_nr, properties[i].text);
+
+    ypos += font2_height;
+
     num_standard_properties++;
   }
 
   if (num_standard_properties == 0)
-    DrawTextS(pad_x + strlen(properties_text) * font1_width,
-             pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
+  {
+    DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
+             font2_nr, none_text);
+
+    ypos -= (line1_height - font1_height);
+  }
 
-  screen_line++;
+  ypos += MAX(font1_height, font2_height);
 
   /* ----- print special description of this element */
 
-  PrintInfoText("Description:", FONT_TEXT_1, screen_line);
-  if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
-    PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
+  PrintInfoText(description_text, font1_nr, xpos, ypos);
+
+  ypos += line1_height;
+
+  if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
+    PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
 }
 
 #define TEXT_COLLECTING                "Score for collecting"
@@ -8919,7 +9050,11 @@ static void DrawPropertiesConfig()
 
   if (!checkPropertiesConfig(properties_element))
   {
-    PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
+    int xpos = ED_ELEMENT_SETTINGS_X(0);
+    int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
+
+    PrintInfoText("No configuration options available.",
+                 FONT_TEXT_1, xpos, ypos);
 
     return;
   }
@@ -11354,6 +11489,8 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       LoadLevel(level_nr);
       LoadScore(level_nr);
 
+      SaveLevelSetup_SeriesInfo();
+
       TapeErase();
 
       ResetUndoBuffer();
@@ -11485,15 +11622,15 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
   int type_id = gi->custom_type_id;
   int i;
 
-  if (type_id >= ED_TEXTBUTTON_ID_LEVELINFO_FIRST &&
-      type_id <= ED_TEXTBUTTON_ID_LEVELINFO_LAST)
+  if (type_id >= ED_TAB_BUTTON_ID_LEVELINFO_FIRST &&
+      type_id <= ED_TAB_BUTTON_ID_LEVELINFO_LAST)
   {
     edit_mode_levelinfo = gi->custom_type_id;
 
     DrawLevelInfoWindow();
   }
-  else if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST &&
-          type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST)
+  else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
+          type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
   {
     edit_mode_properties = gi->custom_type_id;