rnd-20030507-1-src
[rocksndiamonds.git] / src / editor.c
index a726f9139671e95d179840c3a14ce2ae93ef4dfb..5884e40f8f5b00902a567072e92e3e10655dcac8 100644 (file)
@@ -82,6 +82,8 @@
 
 #define ED_COUNT_CHANGE_DELAY_XPOS     (ED_SETTINGS_XPOS2 + 9 * MINI_TILEX)
 
+#define ED_COUNT_CHANGE_DELAY_XPOS     (ED_SETTINGS_XPOS2 + 9 * MINI_TILEX)
+
 #define ED_COUNTER_YSTART              (ED_SETTINGS_YPOS + 2 * TILEY)
 #define ED_COUNTER_YDISTANCE           (3 * MINI_TILEY)
 #define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART + \
 #define ED_AREA_ELEM_CONTENT_YPOS      (22 * MINI_TILEY)
 
 #define ED_AREA_ELEM_CONTENT2_XPOS     (20 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT2_YPOS     ED_COUNTER_YPOS2(4)
+#define ED_AREA_ELEM_CONTENT2_YPOS     (ED_COUNTER_YPOS2(5) + \
+                                        ED_GADGET_DISTANCE)
 
 /* values for random placement background drawing area */
 #define ED_AREA_RANDOM_BACKGROUND_XPOS (29 * MINI_TILEX)
 #define ED_SELECTBOX_XSIZE             ED_WIN_COUNT_XSIZE
 #define ED_SELECTBOX_YSIZE             ED_WIN_COUNT_YSIZE
 
+#define ED_SELECTBOX_CHANGE_UNITS_XPOS (ED_SETTINGS_XPOS2 + \
+                                        ED_CHECKBUTTON_XSIZE + \
+                                        2 * ED_GADGET_DISTANCE)
+
 #define ED_TEXTBUTTON_XPOS             ED_WIN_COUNT_XPOS
 #define ED_TEXTBUTTON_YPOS             (ED_WIN_COUNT_YPOS + \
                                         2 * (2 + ED_WIN_COUNT_YSIZE))
 /* selectbox identifiers */
 #define GADGET_ID_SELECTBOX_FIRST      (GADGET_ID_TEXT_INPUT_FIRST + 2)
 
-#define GADGET_ID_CUSTOM_CHANGE_CAUSE  (GADGET_ID_SELECTBOX_FIRST + 0)
+#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 0)
+#define GADGET_ID_CHANGE_CAUSE         (GADGET_ID_SELECTBOX_FIRST + 1)
 
 /* textbutton identifiers */
-#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 1)
+#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 2)
 
 #define GADGET_ID_PROPERTIES_INFO      (GADGET_ID_TEXTBUTTON_FIRST + 0)
 #define GADGET_ID_PROPERTIES_CONFIG    (GADGET_ID_TEXTBUTTON_FIRST + 1)
 #define ED_TEXTINPUT_ID_LEVEL_LAST     ED_TEXTINPUT_ID_LEVEL_AUTHOR
 
 /* values for selectbox gadgets */
-#define ED_SELECTBOX_ID_CUSTOM_CHANGE_CAUSE    0
+#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      0
+#define ED_SELECTBOX_ID_CHANGE_CAUSE           1
 
-#define ED_NUM_SELECTBOX                       1
+#define ED_NUM_SELECTBOX                       2
+
+#define ED_SELECTBOX_ID_CHANGE_FIRST   ED_SELECTBOX_ID_CHANGE_TIME_UNITS
+#define ED_SELECTBOX_ID_CHANGE_LAST    ED_SELECTBOX_ID_CHANGE_CAUSE
 
 /* values for textbutton gadgets */
 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO       0
@@ -652,20 +664,20 @@ static struct
     "element content",                 NULL
   },
   {
-    ED_COUNT_CHANGE_DELAY_XPOS,                ED_COUNTER_YPOS2(5),
+    ED_COUNT_CHANGE_DELAY_XPOS,                ED_COUNTER_YPOS2(6),
     0,                                 999,
     GADGET_ID_CHANGE_DELAY_FIX_DOWN,   GADGET_ID_CHANGE_DELAY_FIX_UP,
     GADGET_ID_CHANGE_DELAY_FIX_TEXT,
     &custom_element_change.delay_fixed,
-    NULL,                              "seconds (fixed)"
+    NULL,                              "units (fixed)"
   },
   {
-    ED_COUNT_CHANGE_DELAY_XPOS,                ED_COUNTER_YPOS2(6),
+    ED_COUNT_CHANGE_DELAY_XPOS,                ED_COUNTER_YPOS2(7),
     0,                                 999,
     GADGET_ID_CHANGE_DELAY_RND_DOWN,   GADGET_ID_CHANGE_DELAY_RND_UP,
     GADGET_ID_CHANGE_DELAY_RND_TEXT,
     &custom_element_change.delay_random,
-    NULL,                              "seconds (random)"
+    NULL,                              "units (random)"
   }
 };
 
@@ -694,6 +706,14 @@ static struct
   }
 };
 
+static struct ValueTextInfo options_change_time_units[] =
+{
+  { 50,        "seconds"               },
+  { 1, "frames"                },
+  { -1,        NULL                    }
+};
+static int index_change_time_units = 0;
+
 static struct ValueTextInfo options_change_cause[] =
 {
   { 1, "specified delay"       },
@@ -703,23 +723,32 @@ static struct ValueTextInfo options_change_cause[] =
   { 5, "pressed by player"     },
   { -1,        NULL                    }
 };
-static int index_change_cause = 0;
+static int index_change_cause = 0, value_change_cause = 0;
 
 static struct
 {
   int x, y;
   int gadget_id;
-  int size;
+  int size;    /* size of selectbox (chars) or '0' (dynamically determined) */
   struct ValueTextInfo *options;
-  int *index;
+  int *index, *value;
   char *text, *infotext;
 } selectbox_info[ED_NUM_SELECTBOX] =
 {
+  {
+    ED_SELECTBOX_CHANGE_UNITS_XPOS,    ED_COUNTER_YPOS2(8),
+    GADGET_ID_CHANGE_TIME_UNITS,
+    0,
+    options_change_time_units, &index_change_time_units,
+    &custom_element_change.delay_frames,
+    "delay units given in", "time units for change"
+  },
   {
     ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(8),
-    GADGET_ID_CUSTOM_CHANGE_CAUSE,
-    17,
+    GADGET_ID_CHANGE_CAUSE,
+    0,
     options_change_cause, &index_change_cause,
+    &value_change_cause,
     "test:", "test-selectbox entry"
   },
 };
@@ -888,10 +917,10 @@ static struct
     "restrict random placement to",    "set random placement restriction"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
+    ED_SETTINGS_XPOS,                  0,      /* set at runtime */
     GADGET_ID_STICK_ELEMENT,
     &stick_element_properties_window,
-    "stick window to edit content",    "stick window to edit content"
+    "stick this screen to edit content","stick this screen to edit content"
   },
   {
     ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
@@ -900,85 +929,85 @@ static struct
     "slip down from certain flat walls","use EM style slipping behaviour"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(5),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(6),
     GADGET_ID_CUSTOM_INDESTRUCTIBLE,
     &custom_element_properties[EP_INDESTRUCTIBLE],
     "indestructible",                  "element cannot be destroyed"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(6),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(7),
     GADGET_ID_CUSTOM_DIGGABLE,
     &custom_element_properties[EP_DIGGABLE],
     "diggable",                                "element can be digged away"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(7),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(8),
     GADGET_ID_CUSTOM_COLLECTIBLE,
     &custom_element_properties[EP_COLLECTIBLE],
     "collectible",                     "element can be collected"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(8),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(9),
     GADGET_ID_CUSTOM_PUSHABLE,
     &custom_element_properties[EP_PUSHABLE],
     "pushable",                                "element can be pushed"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(9),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(10),
     GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_FALL],
     "can fall",                                "element can fall down"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(10),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(11),
     GADGET_ID_CUSTOM_CAN_SMASH,
     &custom_element_properties[EP_CAN_SMASH],
     "can smash",                       "element can smash other elements"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(11),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(12),
     GADGET_ID_CUSTOM_CAN_MOVE,
     &custom_element_properties[EP_CAN_MOVE],
     "can move",                                "element can move in some direction"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(12),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(13),
     GADGET_ID_CUSTOM_SLIPPERY,
     &custom_element_properties[EP_SLIPPERY],
     "slippery",                                "other elements can fall down from it"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(13),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(14),
     GADGET_ID_CUSTOM_WALKABLE_OVER,
     &custom_element_properties[EP_WALKABLE_OVER],
     "player can walk over",            "player can walk over this element"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(14),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(15),
     GADGET_ID_CUSTOM_WALKABLE_INSIDE,
     &custom_element_properties[EP_WALKABLE_INSIDE],
     "player can walk inside",          "player can walk inside this element"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(15),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(16),
     GADGET_ID_CUSTOM_WALKABLE_UNDER,
     &custom_element_properties[EP_WALKABLE_UNDER],
     "player can walk under",           "player can walk under this element"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(4),
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS2(5),
     GADGET_ID_CUSTOM_CHANGEABLE,
     &custom_element_properties[EP_CHANGEABLE],
     "element changes to    after:",    "element can change to other element"
   },
   {
-    ED_SETTINGS_XPOS2,                 ED_COUNTER_YPOS2(5),
+    ED_SETTINGS_XPOS2,                 ED_COUNTER_YPOS2(6),
     GADGET_ID_CHANGE_DELAY_FIXED,
     &custom_element_change_events[CE_DELAY_FIXED],
     "delay of",                                "element changes after fixed delay"
   },
   {
-    ED_SETTINGS_XPOS2,                 ED_COUNTER_YPOS2(6),
+    ED_SETTINGS_XPOS2,                 ED_COUNTER_YPOS2(7),
     GADGET_ID_CHANGE_DELAY_RANDOM,
     &custom_element_change_events[CE_DELAY_RANDOM],
     "delay of",                                "element changes after random delay"
@@ -1013,6 +1042,7 @@ static int new_element3 = EL_SAND;
 /* forward declaration for internal use */
 static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
+static void ModifyEditorSelectbox(int, int);
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
@@ -2456,30 +2486,43 @@ static void CreateTextInputGadgets()
 static void CreateSelectboxGadgets()
 {
   int max_infotext_len = getMaxInfoTextLength();
-  int i;
+  int i, j;
 
   for (i=0; i<ED_NUM_SELECTBOX; i++)
   {
     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
+    int xoffset;
     struct GadgetInfo *gi;
     unsigned long event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = selectbox_info[i].gadget_id;
 
+    /* (we cannot use -1 for uninitialized values if we directly compare
+       with results from strlen(), because the '<' and '>' operation will
+       implicitely cast -1 to an unsigned integer value!) */
+
+    if (selectbox_info[i].size == 0)   /* dynamically determined */
+      for (j=0; selectbox_info[i].options[j].text != NULL; j++)
+       if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
+         selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
+
     event_mask = GD_EVENT_RELEASED |
       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
     gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
     gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
 
+    xoffset = (getFontWidth(FONT_TEXT_1) * strlen(selectbox_info[i].text) +
+              2 * ED_GADGET_DISTANCE);
+
     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, infotext,
-                     GDI_X, SX + selectbox_info[i].x,
+                     GDI_X, SX + selectbox_info[i].x + xoffset,
                      GDI_Y, SY + selectbox_info[i].y,
                      GDI_TYPE, GD_TYPE_SELECTBOX,
                      GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
@@ -2933,6 +2976,10 @@ static void CopyCustomElementPropertiesToGame(int element)
 
   for (i=0; i < NUM_CHANGE_EVENTS; i++)
     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
+
+  /* copy change events also to special level editor variable */
+  i = properties_element - EL_CUSTOM_START;
+  custom_element_change = level.custom_element[i].change;
 }
 
 void DrawLevelEd()
@@ -3128,6 +3175,23 @@ static void ModifyEditorCounterLimits(int counter_id, int min, int max)
   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
 }
 
+static void ModifyEditorSelectbox(int selectbox_id, int new_value)
+{
+  int gadget_id = selectbox_info[selectbox_id].gadget_id;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+  int new_index_value = 0;
+  int i;
+
+  for(i=0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
+    if (selectbox_info[selectbox_id].options[i].value == new_value)
+      new_index_value = i;
+
+  *selectbox_info[selectbox_id].value =
+    selectbox_info[selectbox_id].options[new_index_value].value;
+
+  ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
+}
+
 static void PickDrawingElement(int button, int element)
 {
   if (button < 1 || button > 3)
@@ -3320,6 +3384,7 @@ static void DrawAmoebaContentArea()
 
 static void DrawCustomChangedArea()
 {
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CHANGED];
 #if 0
   int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
   int yoffset_right2 = ED_BORDER_SIZE;
@@ -3336,7 +3401,6 @@ static void DrawCustomChangedArea()
   int area_y = ypos / MINI_TILEY;
   int area_sx = SX + xpos;
   int area_sy = SY + ypos;
-  int i = properties_element - EL_CUSTOM_START;
 
   if (!IS_CUSTOM_ELEMENT(properties_element))
   {
@@ -3346,10 +3410,17 @@ static void DrawCustomChangedArea()
     return;
   }
 
-  ElementContent[0][0][0] = level.custom_element[i].change.successor;
+  ElementContent[0][0][0] = custom_element_change.successor;
 
   DrawElementBorder(area_sx, area_sy, MINI_TILEX, MINI_TILEY);
+#if 1
+  DrawMiniGraphicExt(drawto,
+                    gi->x,
+                    gi->y,
+                    el2edimg(ElementContent[0][0][0]));
+#else
   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
+#endif
 
 #if 0
   DrawText(area_sx + TILEX, area_sy + 1, "Element after change", FONT_TEXT_1);
@@ -3550,12 +3621,14 @@ static void DrawPropertiesConfig()
   {
     /* draw stickybutton gadget */
     i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
+    checkbutton_info[i].y = ED_COUNTER_YPOS(4);
     x = checkbutton_info[i].x + xoffset_right2;
     y = checkbutton_info[i].y + yoffset_right2;
 
     DrawTextF(x, y, FONT_TEXT_1, checkbutton_info[i].text);
     ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
-                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+                GDI_CHECKED, *checkbutton_info[i].value,
+                GDI_Y, SY + checkbutton_info[i].y, GDI_END);
     MapCheckbuttonGadget(i);
 
     if (HAS_CONTENT(properties_element))
@@ -3925,12 +3998,14 @@ static void DrawPropertiesAdvanced()
 
   /* draw stickybutton gadget */
   i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
+  checkbutton_info[i].y = ED_COUNTER_YPOS2(4);
   x = checkbutton_info[i].x + xoffset_right2;
   y = checkbutton_info[i].y + yoffset_right2;
 
   DrawTextF(x, y, FONT_TEXT_1, checkbutton_info[i].text);
   ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
-              GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+              GDI_CHECKED, *checkbutton_info[i].value,
+              GDI_Y, SY + checkbutton_info[i].y, GDI_END);
   MapCheckbuttonGadget(i);
 
   /* draw counter gadgets */
@@ -3965,17 +4040,23 @@ static void DrawPropertiesAdvanced()
 
   DrawCustomChangedArea();
 
-  /* draw selectbox gadget */
-  i = ED_SELECTBOX_ID_CUSTOM_CHANGE_CAUSE;
-  x = selectbox_info[i].x + xoffset_right2;
-  y = selectbox_info[i].y + yoffset_right2;
+  /* draw selectbox gadgets */
+  for (i=ED_SELECTBOX_ID_CHANGE_FIRST; i<=ED_SELECTBOX_ID_CHANGE_LAST; i++)
+  {
+    int yoffset = ED_BORDER_SIZE;
 
-  selectbox_info[i].index = &index_change_cause;
+    x = selectbox_info[i].x;
+    y = selectbox_info[i].y + yoffset;
 
-  DrawTextF(x, y, FONT_TEXT_1, selectbox_info[i].text);
-  ModifyGadget(level_editor_gadget[selectbox_info[i].gadget_id],
-              GDI_SELECTBOX_INDEX, *selectbox_info[i].index, GDI_END);
-  MapSelectboxGadget(i);
+    DrawTextF(x, y, FONT_TEXT_1, selectbox_info[i].text);
+#if 1
+    ModifyEditorSelectbox(i, *selectbox_info[i].value);
+#else
+    ModifyGadget(level_editor_gadget[selectbox_info[i].gadget_id],
+                GDI_SELECTBOX_INDEX, *selectbox_info[i].index, GDI_END);
+#endif
+    MapSelectboxGadget(i);
+  }
 }
 
 static void DrawPropertiesWindow()
@@ -4756,7 +4837,8 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          int i = properties_element - EL_CUSTOM_START;
 
-         level.custom_element[i].change.successor = new_element;
+         custom_element_change.successor = new_element;
+         level.custom_element[i].change = custom_element_change;
        }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
@@ -4940,6 +5022,12 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
   int type_id = gi->custom_type_id;
 
   *selectbox_info[type_id].index = gi->selectbox.index;
+  *selectbox_info[type_id].value =
+    selectbox_info[type_id].options[gi->selectbox.index].value;
+
+  if (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
+      type_id <= ED_SELECTBOX_ID_CHANGE_LAST)
+    CopyCustomElementPropertiesToGame(properties_element);
 
 #if 0
   printf("Selected text value: '%s' [%d]\n",