added support for rocket launcher in BD engine
[rocksndiamonds.git] / src / editor.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // editor.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "game.h"
21 #include "init.h"
22 #include "tape.h"
23
24
25 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
26
27
28 // ----------------------------------------------------------------------------
29 // screen and artwork graphic pixel position definitions
30 // ----------------------------------------------------------------------------
31
32 // values for the control window
33 #define ED_CTRL1_BUTTONS_HORIZ          4       // toolbox
34 #define ED_CTRL1_BUTTONS_VERT           4
35 #define ED_CTRL2_BUTTONS_HORIZ          3       // level
36 #define ED_CTRL2_BUTTONS_VERT           2
37 #define ED_CTRL3_BUTTONS_HORIZ          3       // CE and GE
38 #define ED_CTRL3_BUTTONS_VERT           1
39 #define ED_CTRL4_BUTTONS_HORIZ          2       // CE and GE
40 #define ED_CTRL4_BUTTONS_VERT           1
41 #define ED_CTRL5_BUTTONS_HORIZ          1       // properties
42 #define ED_CTRL5_BUTTONS_VERT           1
43 #define ED_CTRL6_BUTTONS_HORIZ          3       // properties
44 #define ED_CTRL6_BUTTONS_VERT           1
45 #define ED_CTRL7_BUTTONS_HORIZ          1       // palette
46 #define ED_CTRL7_BUTTONS_VERT           1
47
48 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
49 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
50 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
51 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
52 #define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
53 #define ED_NUM_CTRL6_BUTTONS   (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT)
54 #define ED_NUM_CTRL7_BUTTONS   (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT)
55 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
56 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
57 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
58 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
59 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
60 #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS)
61 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_7_BUTTONS
62
63 // values for the element list
64 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
65 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
66 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
67 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
68 #define ED_ELEMENTLIST_COLS             MAX(1, editor.palette.cols)
69 #define ED_ELEMENTLIST_ROWS             MAX(1, editor.palette.rows)
70 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (ED_ELEMENTLIST_COLS)
71 #define ED_ELEMENTLIST_BUTTONS_VERT     (ED_ELEMENTLIST_ROWS)
72 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
73                                          ED_ELEMENTLIST_BUTTONS_VERT)
74
75 // standard distances
76 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
77 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
78 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
79 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
80 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
81 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
82 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
83                                          ED_DRAWINGAREA_BORDER_SIZE)
84 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
85
86 // values for drawingarea gadgets
87 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
88 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
89 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
90 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
91 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
92
93 // values for checkbutton gadgets
94 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
95 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
96
97 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
98 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
99
100 #define ED_SETTINGS_LEVEL_TABS_X        (editor.settings.tabs.x)
101 #define ED_SETTINGS_LEVEL_TABS_Y        (editor.settings.tabs.y)
102 #define ED_SETTINGS_ELEMENT_TABS_X      (editor.settings.tabs.x)
103 #define ED_SETTINGS_ELEMENT_TABS_Y      (editor.settings.tabs.y +       \
104                                          editor.settings.tabs.yoffset2)
105
106 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
107 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
108
109 #define ED_LEVEL_TABS_XSTART            (ED_SETTINGS_LEVEL_TABS_X)
110 #define ED_LEVEL_TABS_YSTART            (ED_SETTINGS_LEVEL_TABS_Y)
111 #define ED_LEVEL_SETTINGS_XSTART        (ED_SETTINGS_LEVEL_TABS_X +     \
112                                          ED_SETTINGS_TABS_XOFFSET)
113 #define ED_LEVEL_SETTINGS_YSTART        (ED_SETTINGS_LEVEL_TABS_Y +     \
114                                          ED_TABBUTTON_YSIZE +           \
115                                          ED_GADGET_TINY_DISTANCE +      \
116                                          ED_TAB_BAR_HEIGHT +            \
117                                          ED_SETTINGS_TABS_YOFFSET +     \
118                                          getFontHeight(FONT_TEXT_1) +   \
119                                          ED_GADGET_TEXT_DISTANCE)
120 #define ED_ELEMENT_TABS_XSTART          (ED_SETTINGS_ELEMENT_TABS_X)
121 #define ED_ELEMENT_TABS_YSTART          (ED_SETTINGS_ELEMENT_TABS_Y)
122 #define ED_ELEMENT_SETTINGS_XSTART      (ED_SETTINGS_ELEMENT_TABS_X +   \
123                                          ED_SETTINGS_TABS_XOFFSET)
124 #define ED_ELEMENT_SETTINGS_YSTART      (ED_SETTINGS_ELEMENT_TABS_Y +   \
125                                          ED_TABBUTTON_YSIZE +           \
126                                          ED_GADGET_TINY_DISTANCE +      \
127                                          ED_TAB_BAR_HEIGHT +            \
128                                          ED_SETTINGS_TABS_YOFFSET)
129
130 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
131                                          ED_GADGET_TEXT_DISTANCE)
132 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
133                                          ED_GADGET_LINE_DISTANCE)
134
135 #define ED_POS_RANGE                    (10000)
136 #define ED_POS_LEVEL_TABS_FIRST         (1 * ED_POS_RANGE)
137 #define ED_POS_LEVEL_TABS_LAST          (2 * ED_POS_RANGE - 1)
138 #define ED_POS_LEVEL_SETTINGS_FIRST     (2 * ED_POS_RANGE)
139 #define ED_POS_LEVEL_SETTINGS_LAST      (3 * ED_POS_RANGE - 1)
140 #define ED_POS_ELEMENT_TABS_FIRST       (3 * ED_POS_RANGE)
141 #define ED_POS_ELEMENT_TABS_LAST        (4 * ED_POS_RANGE - 1)
142 #define ED_POS_ELEMENT_SETTINGS_FIRST   (4 * ED_POS_RANGE)
143 #define ED_POS_ELEMENT_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
144
145 #define ED_LEVEL_TABS_XPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
146 #define ED_LEVEL_TABS_YPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
147
148 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
149 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
150
151 #define ED_ELEMENT_TABS_XPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
152 #define ED_ELEMENT_TABS_YPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
153
154 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
155 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
156
157 #define IS_POS_LEVEL_TABS(n)          ((n) >= ED_POS_LEVEL_TABS_FIRST && \
158                                        (n) <= ED_POS_LEVEL_TABS_LAST)
159 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
160                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
161 #define IS_POS_ELEMENT_TABS(n)        ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
162                                        (n) <= ED_POS_ELEMENT_TABS_LAST)
163 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
164                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
165
166 #define ED_LEVEL_TABS_LINE(n)           ((n) - ED_POS_LEVEL_TABS_FIRST)
167 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
168 #define ED_ELEMENT_TABS_LINE(n)         ((n) - ED_POS_ELEMENT_TABS_FIRST)
169 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
170
171 #define ED_LEVEL_TABS_X(n)              (ED_LEVEL_TABS_XSTART + \
172                                          (n) * ED_SETTINGS_TABS_XOFFSET)
173 #define ED_LEVEL_TABS_Y(n)              (ED_LEVEL_TABS_YSTART + \
174                                          (n) * ED_SETTINGS_TABS_YOFFSET)
175
176 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
177                                          (n) * ED_SETTINGS_XOFFSET)
178 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
179                                          (n) * ED_SETTINGS_YOFFSET)
180
181 #define ED_ELEMENT_TABS_X(n)            (ED_ELEMENT_TABS_XSTART +       \
182                                          (n) * ED_SETTINGS_TABS_XOFFSET)
183 #define ED_ELEMENT_TABS_Y(n)            (ED_ELEMENT_TABS_YSTART +       \
184                                          (n) * ED_SETTINGS_TABS_YOFFSET)
185
186 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
187                                          (n) * ED_SETTINGS_XOFFSET)
188 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
189                                          (n) * ED_SETTINGS_YOFFSET)
190
191 #define ED_POS_TO_LEVEL_TABS_X(n)       \
192   (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n)))
193 #define ED_POS_TO_LEVEL_TABS_Y(n)       \
194   (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n)))
195
196 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
197   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
198 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
199   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
200
201 #define ED_POS_TO_ELEMENT_TABS_X(n)     \
202   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
203 #define ED_POS_TO_ELEMENT_TABS_Y(n)     \
204   (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n)))
205
206 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
207   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
208 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
209   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
210
211 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_TABS(n) ? \
212                                          ED_POS_TO_LEVEL_TABS_X(n) : \
213                                          IS_POS_LEVEL_SETTINGS(n) ?     \
214                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
215                                          IS_POS_ELEMENT_TABS(n) ?       \
216                                          ED_POS_TO_ELEMENT_TABS_X(n) : \
217                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
218                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
219 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_TABS(n) ? \
220                                          ED_POS_TO_LEVEL_TABS_Y(n) : \
221                                          IS_POS_LEVEL_SETTINGS(n) ?     \
222                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
223                                          IS_POS_ELEMENT_TABS(n) ?       \
224                                          ED_POS_TO_ELEMENT_TABS_Y(n) : \
225                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
226                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
227
228 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
229                                          ED_DRAWINGAREA_TILE_SIZE)
230 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
231                                          ED_DRAWINGAREA_TILE_SIZE)
232
233 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
234                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
235 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
236                                          (ED_CHECKBUTTON_YSIZE -        \
237                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
238
239 #define ED_AREA_XOFFSET_2(n)      (0)
240 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
241                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
242
243 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
244                                     ED_SETTINGS_XOFF((i).xoffset) +     \
245                                     ED_AREA_XOFFSET_1((i).x) -          \
246                                     ED_AREA_XOFFSET_2((i).area_xsize))
247 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
248                                     ED_SETTINGS_YOFF((i).yoffset) +     \
249                                     ED_AREA_YOFFSET_1((i).y) -          \
250                                     ED_AREA_YOFFSET_2((i).area_ysize))
251
252 // values for element content drawing areas
253 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
254 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
255 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
256 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
257
258 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
259 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
260 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
261 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
262
263 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
264 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
265 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
266 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
267
268 // element content
269 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
270 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
271
272 // yamyam content
273 #define ED_XPOS_YAM                     0
274 #define ED_YPOS_YAM                     5
275 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
276 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
277 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
278 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
279 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
280                                          ED_SETTINGS_XOFF(n))
281 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
282                                          ED_SETTINGS_YOFF(n) +          \
283                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
284                                          ED_AREA_YOFFSET_2(3))
285
286 // magic ball content
287 #define ED_XPOS_BALL                    0
288 #define ED_YPOS_BALL                    6
289 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
290 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
291 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
292 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
293 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
294                                          ED_SETTINGS_XOFF(n))
295 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
296                                          ED_SETTINGS_YOFF(n) +          \
297                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
298                                          ED_AREA_YOFFSET_2(3))
299
300 // values for scrolling gadgets for drawing area
301 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
302 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
303
304 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
305 #define ED_SCROLL_UP_YPOS               (0)
306 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
307 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
308 #define ED_SCROLL_LEFT_XPOS             (0)
309 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
310 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
311 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
312 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
313                                          ED_SCROLLBUTTON_XSIZE)
314 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
315 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
316 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
317 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
318 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
319                                          ED_SCROLLBUTTON_YSIZE)
320 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
321 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
322
323 // values for scrolling gadgets for element list
324 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
325 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
326
327 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
328                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
329                                          ED_ELEMENTLIST_XSIZE)
330 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
331 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
332 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
333                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
334                                          ED_ELEMENTLIST_YSIZE -         \
335                                          ED_SCROLLBUTTON2_YSIZE)
336 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
337 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
338                                          ED_SCROLLBUTTON2_YSIZE)
339 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
340 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
341                                          ED_ELEMENTLIST_YSIZE -         \
342                                          2 * ED_SCROLLBUTTON2_YSIZE)
343
344 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText()
345 #define INFOTEXT_FONT           FONT_TEXT_2
346 #define INFOTEXT_XSIZE          SXSIZE
347 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
348 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
349 #define INFOTEXT_X              (editor.settings.tooltip.x)
350 #define INFOTEXT_Y              (editor.settings.tooltip.y)
351 #define INFOTEXT_XY_REDEFINED   (INFOTEXT_X != -1 || INFOTEXT_Y != -1)
352 #define INFOTEXT_XPOS           SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0)
353 #define INFOTEXT_YPOS           SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \
354                                       SYSIZE - INFOTEXT_YSIZE)
355
356
357 // ----------------------------------------------------------------------------
358 // editor gadget definitions
359 // ----------------------------------------------------------------------------
360
361 enum
362 {
363   GADGET_ID_NONE = -1,
364
365   // drawing toolbox buttons
366
367   GADGET_ID_SINGLE_ITEMS,
368   GADGET_ID_CONNECTED_ITEMS,
369   GADGET_ID_LINE,
370   GADGET_ID_ARC,
371   GADGET_ID_RECTANGLE,
372   GADGET_ID_FILLED_BOX,
373   GADGET_ID_WRAP_UP,
374   GADGET_ID_TEXT,
375   GADGET_ID_FLOOD_FILL,
376   GADGET_ID_WRAP_LEFT,
377   GADGET_ID_ZOOM,
378   GADGET_ID_WRAP_RIGHT,
379   GADGET_ID_RANDOM_PLACEMENT,
380   GADGET_ID_GRAB_BRUSH,
381   GADGET_ID_WRAP_DOWN,
382   GADGET_ID_PICK_ELEMENT,
383
384   GADGET_ID_UNDO,
385   GADGET_ID_CONF,
386   GADGET_ID_SAVE,
387   GADGET_ID_CLEAR,
388   GADGET_ID_TEST,
389   GADGET_ID_EXIT,
390
391   GADGET_ID_CUSTOM_COPY_FROM,
392   GADGET_ID_CUSTOM_COPY_TO,
393   GADGET_ID_CUSTOM_EXCHANGE,
394   GADGET_ID_CUSTOM_COPY,
395   GADGET_ID_CUSTOM_PASTE,
396
397   GADGET_ID_PROPERTIES,
398   GADGET_ID_ELEMENT_LEFT,
399   GADGET_ID_ELEMENT_MIDDLE,
400   GADGET_ID_ELEMENT_RIGHT,
401   GADGET_ID_PALETTE,
402
403   // counter gadget identifiers
404
405   GADGET_ID_SELECT_LEVEL_DOWN,
406   GADGET_ID_SELECT_LEVEL_TEXT,
407   GADGET_ID_SELECT_LEVEL_UP,
408   GADGET_ID_LEVEL_XSIZE_DOWN,
409   GADGET_ID_LEVEL_XSIZE_TEXT,
410   GADGET_ID_LEVEL_XSIZE_UP,
411   GADGET_ID_LEVEL_YSIZE_DOWN,
412   GADGET_ID_LEVEL_YSIZE_TEXT,
413   GADGET_ID_LEVEL_YSIZE_UP,
414   GADGET_ID_LEVEL_RANDOM_DOWN,
415   GADGET_ID_LEVEL_RANDOM_TEXT,
416   GADGET_ID_LEVEL_RANDOM_UP,
417   GADGET_ID_LEVEL_GEMSLIMIT_DOWN,
418   GADGET_ID_LEVEL_GEMSLIMIT_TEXT,
419   GADGET_ID_LEVEL_GEMSLIMIT_UP,
420   GADGET_ID_LEVEL_TIMELIMIT_DOWN,
421   GADGET_ID_LEVEL_TIMELIMIT_TEXT,
422   GADGET_ID_LEVEL_TIMELIMIT_UP,
423   GADGET_ID_LEVEL_TIMESCORE_DOWN,
424   GADGET_ID_LEVEL_TIMESCORE_TEXT,
425   GADGET_ID_LEVEL_TIMESCORE_UP,
426   GADGET_ID_LEVEL_RANDOM_SEED_DOWN,
427   GADGET_ID_LEVEL_RANDOM_SEED_TEXT,
428   GADGET_ID_LEVEL_RANDOM_SEED_UP,
429   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
430   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
431   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
432   GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,
433   GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,
434   GADGET_ID_BD_CYCLE_DELAY_MS_UP,
435   GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,
436   GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,
437   GADGET_ID_BD_CYCLE_DELAY_C64_UP,
438   GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,
439   GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,
440   GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
441   GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,
442   GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,
443   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
444   GADGET_ID_BD_PUSHING_PROB_DOWN,
445   GADGET_ID_BD_PUSHING_PROB_TEXT,
446   GADGET_ID_BD_PUSHING_PROB_UP,
447   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,
448   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,
449   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
450   GADGET_ID_ELEMENT_VALUE1_DOWN,
451   GADGET_ID_ELEMENT_VALUE1_TEXT,
452   GADGET_ID_ELEMENT_VALUE1_UP,
453   GADGET_ID_ELEMENT_VALUE2_DOWN,
454   GADGET_ID_ELEMENT_VALUE2_TEXT,
455   GADGET_ID_ELEMENT_VALUE2_UP,
456   GADGET_ID_ELEMENT_VALUE3_DOWN,
457   GADGET_ID_ELEMENT_VALUE3_TEXT,
458   GADGET_ID_ELEMENT_VALUE3_UP,
459   GADGET_ID_ELEMENT_VALUE4_DOWN,
460   GADGET_ID_ELEMENT_VALUE4_TEXT,
461   GADGET_ID_ELEMENT_VALUE4_UP,
462   GADGET_ID_YAMYAM_CONTENT_DOWN,
463   GADGET_ID_YAMYAM_CONTENT_TEXT,
464   GADGET_ID_YAMYAM_CONTENT_UP,
465   GADGET_ID_BALL_CONTENT_DOWN,
466   GADGET_ID_BALL_CONTENT_TEXT,
467   GADGET_ID_BALL_CONTENT_UP,
468   GADGET_ID_ANDROID_CONTENT_DOWN,
469   GADGET_ID_ANDROID_CONTENT_TEXT,
470   GADGET_ID_ANDROID_CONTENT_UP,
471   GADGET_ID_ENVELOPE_XSIZE_DOWN,
472   GADGET_ID_ENVELOPE_XSIZE_TEXT,
473   GADGET_ID_ENVELOPE_XSIZE_UP,
474   GADGET_ID_ENVELOPE_YSIZE_DOWN,
475   GADGET_ID_ENVELOPE_YSIZE_TEXT,
476   GADGET_ID_ENVELOPE_YSIZE_UP,
477   GADGET_ID_INVENTORY_SIZE_DOWN,
478   GADGET_ID_INVENTORY_SIZE_TEXT,
479   GADGET_ID_INVENTORY_SIZE_UP,
480   GADGET_ID_MM_BALL_CONTENT_DOWN,
481   GADGET_ID_MM_BALL_CONTENT_TEXT,
482   GADGET_ID_MM_BALL_CONTENT_UP,
483   GADGET_ID_CUSTOM_SCORE_DOWN,
484   GADGET_ID_CUSTOM_SCORE_TEXT,
485   GADGET_ID_CUSTOM_SCORE_UP,
486   GADGET_ID_CUSTOM_GEMCOUNT_DOWN,
487   GADGET_ID_CUSTOM_GEMCOUNT_TEXT,
488   GADGET_ID_CUSTOM_GEMCOUNT_UP,
489   GADGET_ID_CUSTOM_VALUE_FIX_DOWN,
490   GADGET_ID_CUSTOM_VALUE_FIX_TEXT,
491   GADGET_ID_CUSTOM_VALUE_FIX_UP,
492   GADGET_ID_CUSTOM_VALUE_RND_DOWN,
493   GADGET_ID_CUSTOM_VALUE_RND_TEXT,
494   GADGET_ID_CUSTOM_VALUE_RND_UP,
495   GADGET_ID_PUSH_DELAY_FIX_DOWN,
496   GADGET_ID_PUSH_DELAY_FIX_TEXT,
497   GADGET_ID_PUSH_DELAY_FIX_UP,
498   GADGET_ID_PUSH_DELAY_RND_DOWN,
499   GADGET_ID_PUSH_DELAY_RND_TEXT,
500   GADGET_ID_PUSH_DELAY_RND_UP,
501   GADGET_ID_DROP_DELAY_FIX_DOWN,
502   GADGET_ID_DROP_DELAY_FIX_TEXT,
503   GADGET_ID_DROP_DELAY_FIX_UP,
504   GADGET_ID_DROP_DELAY_RND_DOWN,
505   GADGET_ID_DROP_DELAY_RND_TEXT,
506   GADGET_ID_DROP_DELAY_RND_UP,
507   GADGET_ID_MOVE_DELAY_FIX_DOWN,
508   GADGET_ID_MOVE_DELAY_FIX_TEXT,
509   GADGET_ID_MOVE_DELAY_FIX_UP,
510   GADGET_ID_MOVE_DELAY_RND_DOWN,
511   GADGET_ID_MOVE_DELAY_RND_TEXT,
512   GADGET_ID_MOVE_DELAY_RND_UP,
513   GADGET_ID_STEP_DELAY_FIX_DOWN,
514   GADGET_ID_STEP_DELAY_FIX_TEXT,
515   GADGET_ID_STEP_DELAY_FIX_UP,
516   GADGET_ID_STEP_DELAY_RND_DOWN,
517   GADGET_ID_STEP_DELAY_RND_TEXT,
518   GADGET_ID_STEP_DELAY_RND_UP,
519   GADGET_ID_EXPLOSION_DELAY_DOWN,
520   GADGET_ID_EXPLOSION_DELAY_TEXT,
521   GADGET_ID_EXPLOSION_DELAY_UP,
522   GADGET_ID_IGNITION_DELAY_DOWN,
523   GADGET_ID_IGNITION_DELAY_TEXT,
524   GADGET_ID_IGNITION_DELAY_UP,
525   GADGET_ID_CHANGE_DELAY_FIX_DOWN,
526   GADGET_ID_CHANGE_DELAY_FIX_TEXT,
527   GADGET_ID_CHANGE_DELAY_FIX_UP,
528   GADGET_ID_CHANGE_DELAY_RND_DOWN,
529   GADGET_ID_CHANGE_DELAY_RND_TEXT,
530   GADGET_ID_CHANGE_DELAY_RND_UP,
531   GADGET_ID_CHANGE_CONT_RND_DOWN,
532   GADGET_ID_CHANGE_CONT_RND_TEXT,
533   GADGET_ID_CHANGE_CONT_RND_UP,
534   GADGET_ID_GROUP_CONTENT_DOWN,
535   GADGET_ID_GROUP_CONTENT_TEXT,
536   GADGET_ID_GROUP_CONTENT_UP,
537
538   // drawing area identifiers
539
540   GADGET_ID_DRAWING_LEVEL,
541   GADGET_ID_YAMYAM_CONTENT_0,
542   GADGET_ID_YAMYAM_CONTENT_1,
543   GADGET_ID_YAMYAM_CONTENT_2,
544   GADGET_ID_YAMYAM_CONTENT_3,
545   GADGET_ID_YAMYAM_CONTENT_4,
546   GADGET_ID_YAMYAM_CONTENT_5,
547   GADGET_ID_YAMYAM_CONTENT_6,
548   GADGET_ID_YAMYAM_CONTENT_7,
549   GADGET_ID_MAGIC_BALL_CONTENT_0,
550   GADGET_ID_MAGIC_BALL_CONTENT_1,
551   GADGET_ID_MAGIC_BALL_CONTENT_2,
552   GADGET_ID_MAGIC_BALL_CONTENT_3,
553   GADGET_ID_MAGIC_BALL_CONTENT_4,
554   GADGET_ID_MAGIC_BALL_CONTENT_5,
555   GADGET_ID_MAGIC_BALL_CONTENT_6,
556   GADGET_ID_MAGIC_BALL_CONTENT_7,
557   GADGET_ID_ANDROID_CONTENT,
558   GADGET_ID_AMOEBA_CONTENT,
559   GADGET_ID_BD_SNAP_ELEMENT,
560   GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,
561   GADGET_ID_BD_MAGIC_WALL_ROCK_TO,
562   GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
563   GADGET_ID_BD_MAGIC_WALL_NUT_TO,
564   GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
565   GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
566   GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
567   GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,
568   GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,
569   GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
570   GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
571   GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
572   GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
573   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
574   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
575   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
576   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
577   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
578   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
579   GADGET_ID_BD_ACID_EATS_ELEMENT,
580   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
581   GADGET_ID_BD_BITER_EATS_ELEMENT,
582   GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
583   GADGET_ID_BD_NUT_CONTENT,
584   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
585   GADGET_ID_BD_SAND_LOOKS_LIKE,
586   GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,
587   GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
588   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
589   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
590   GADGET_ID_BD_FIREFLY_EXPLODES_TO,
591   GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,
592   GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,
593   GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,
594   GADGET_ID_BD_STONEFLY_EXPLODES_TO,
595   GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,
596   GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,
597   GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,
598   GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,
599   GADGET_ID_BD_EXPLOSION_TURNS_TO,
600   GADGET_ID_START_ELEMENT,
601   GADGET_ID_ARTWORK_ELEMENT,
602   GADGET_ID_EXPLOSION_ELEMENT,
603   GADGET_ID_INVENTORY_CONTENT,
604   GADGET_ID_MM_BALL_CONTENT,
605   GADGET_ID_CUSTOM_GRAPHIC,
606   GADGET_ID_CUSTOM_CONTENT,
607   GADGET_ID_CUSTOM_MOVE_ENTER,
608   GADGET_ID_CUSTOM_MOVE_LEAVE,
609   GADGET_ID_CUSTOM_CHANGE_TARGET,
610   GADGET_ID_CUSTOM_CHANGE_CONTENT,
611   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
612   GADGET_ID_CUSTOM_CHANGE_ACTION,
613   GADGET_ID_GROUP_CONTENT,
614   GADGET_ID_RANDOM_BACKGROUND,
615
616   // text input identifiers
617
618   GADGET_ID_LEVEL_NAME,
619   GADGET_ID_LEVEL_AUTHOR,
620   GADGET_ID_LEVELSET_NAME,
621   GADGET_ID_LEVELSET_AUTHOR,
622   GADGET_ID_ELEMENT_NAME,
623
624   // text area identifiers
625
626   GADGET_ID_ENVELOPE_INFO,
627
628   // selectbox identifiers
629
630   GADGET_ID_TIME_OR_STEPS,
631   GADGET_ID_TIME_SCORE_BASE,
632   GADGET_ID_GAME_ENGINE_TYPE,
633   GADGET_ID_BD_SCHEDULING_TYPE,
634   GADGET_ID_LEVELSET_SAVE_MODE,
635   GADGET_ID_WIND_DIRECTION,
636   GADGET_ID_PLAYER_SPEED,
637   GADGET_ID_BD_GRAVITY_DIRECTION,
638   GADGET_ID_MM_BALL_CHOICE_MODE,
639   GADGET_ID_CUSTOM_WALK_TO_ACTION,
640   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
641   GADGET_ID_CUSTOM_DEADLINESS,
642   GADGET_ID_CUSTOM_MOVE_PATTERN,
643   GADGET_ID_CUSTOM_MOVE_DIRECTION,
644   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
645   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
646   GADGET_ID_CUSTOM_SMASH_TARGETS,
647   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
648   GADGET_ID_CUSTOM_ACCESS_TYPE,
649   GADGET_ID_CUSTOM_ACCESS_LAYER,
650   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
651   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
652   GADGET_ID_CHANGE_TIME_UNITS,
653   GADGET_ID_CHANGE_DIRECT_ACTION,
654   GADGET_ID_CHANGE_OTHER_ACTION,
655   GADGET_ID_CHANGE_SIDE,
656   GADGET_ID_CHANGE_PLAYER,
657   GADGET_ID_CHANGE_PAGE,
658   GADGET_ID_CHANGE_REPLACE_WHEN,
659   GADGET_ID_ACTION_TYPE,
660   GADGET_ID_ACTION_MODE,
661   GADGET_ID_ACTION_ARG,
662   GADGET_ID_SELECT_CHANGE_PAGE,
663   GADGET_ID_GROUP_CHOICE_MODE,
664
665   // textbutton identifiers
666
667   GADGET_ID_LEVELCONFIG_LEVEL,
668   GADGET_ID_LEVELCONFIG_LEVELSET,
669   GADGET_ID_LEVELCONFIG_EDITOR,
670   GADGET_ID_LEVELCONFIG_ENGINE,
671   GADGET_ID_PROPERTIES_INFO,
672   GADGET_ID_PROPERTIES_CONFIG,
673   GADGET_ID_PROPERTIES_CONFIG_1,
674   GADGET_ID_PROPERTIES_CONFIG_2,
675   GADGET_ID_PROPERTIES_CHANGE,
676   GADGET_ID_SAVE_AS_TEMPLATE_1,
677   GADGET_ID_SAVE_AS_TEMPLATE_2,
678   GADGET_ID_SAVE_LEVELSET,
679   GADGET_ID_ADD_CHANGE_PAGE,
680   GADGET_ID_DEL_CHANGE_PAGE,
681
682   // graphicbutton identifiers
683
684   GADGET_ID_PREV_CHANGE_PAGE,
685   GADGET_ID_NEXT_CHANGE_PAGE,
686   GADGET_ID_COPY_CHANGE_PAGE,
687   GADGET_ID_PASTE_CHANGE_PAGE,
688
689   // gadgets for scrolling of drawing area
690
691   GADGET_ID_SCROLL_UP,
692   GADGET_ID_SCROLL_DOWN,
693   GADGET_ID_SCROLL_LEFT,
694   GADGET_ID_SCROLL_RIGHT,
695   GADGET_ID_SCROLL_HORIZONTAL,
696   GADGET_ID_SCROLL_VERTICAL,
697
698   // gadgets for scrolling element list
699
700   GADGET_ID_SCROLL_LIST_UP,
701   GADGET_ID_SCROLL_LIST_DOWN,
702   GADGET_ID_SCROLL_LIST_VERTICAL,
703
704   // checkbuttons/radiobuttons for level/element properties
705
706   GADGET_ID_AUTO_COUNT_GEMS,
707   GADGET_ID_RATE_TIME_OVER_SCORE,
708   GADGET_ID_USE_LEVELSET_ARTWORK,
709   GADGET_ID_COPY_LEVEL_TEMPLATE,
710   GADGET_ID_RANDOM_PERCENTAGE,
711   GADGET_ID_RANDOM_QUANTITY,
712   GADGET_ID_RANDOM_RESTRICTED,
713   GADGET_ID_BD_INTERMISSION,
714   GADGET_ID_BD_PAL_TIMING,
715   GADGET_ID_BD_LINE_SHIFTING_BORDERS,
716   GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
717   GADGET_ID_BD_SHORT_EXPLOSIONS,
718   GADGET_ID_STICK_ELEMENT,
719   GADGET_ID_EM_SLIPPERY_GEMS,
720   GADGET_ID_EM_EXPLODES_BY_FIRE,
721   GADGET_ID_USE_SPRING_BUG,
722   GADGET_ID_USE_TIME_ORB_BUG,
723   GADGET_ID_USE_LIFE_BUGS,
724   GADGET_ID_RANDOM_BALL_CONTENT,
725   GADGET_ID_INITIAL_BALL_ACTIVE,
726   GADGET_ID_GROW_INTO_DIGGABLE,
727   GADGET_ID_SB_FIELDS_NEEDED,
728   GADGET_ID_SB_OBJECTS_NEEDED,
729   GADGET_ID_AUTO_EXIT_SOKOBAN,
730   GADGET_ID_SOLVED_BY_ONE_PLAYER,
731   GADGET_ID_FINISH_DIG_COLLECT,
732   GADGET_ID_KEEP_WALKABLE_CE,
733   GADGET_ID_CONTINUOUS_SNAPPING,
734   GADGET_ID_BLOCK_SNAP_FIELD,
735   GADGET_ID_BLOCK_LAST_FIELD,
736   GADGET_ID_SP_BLOCK_LAST_FIELD,
737   GADGET_ID_INSTANT_RELOCATION,
738   GADGET_ID_SHIFTED_RELOCATION,
739   GADGET_ID_LAZY_RELOCATION,
740   GADGET_ID_USE_START_ELEMENT,
741   GADGET_ID_USE_ARTWORK_ELEMENT,
742   GADGET_ID_USE_EXPLOSION_ELEMENT,
743   GADGET_ID_INITIAL_GRAVITY,
744   GADGET_ID_USE_INITIAL_INVENTORY,
745   GADGET_ID_CAN_PASS_TO_WALKABLE,
746   GADGET_ID_CAN_FALL_INTO_ACID,
747   GADGET_ID_CAN_MOVE_INTO_ACID,
748   GADGET_ID_DONT_COLLIDE_WITH,
749   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
750   GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
751   GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
752   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
753   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
754   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
755   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
756   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
757   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
758   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
759   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
760   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
761   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
762   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
763   GADGET_ID_BD_REPLICATORS_ACTIVE,
764   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
765   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
766   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
767   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
768   GADGET_ID_BD_INFINITE_ROCKETS,
769   GADGET_ID_BD_CREATURES_START_BACKWARDS,
770   GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
771   GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
772   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
773   GADGET_ID_ENVELOPE_AUTOWRAP,
774   GADGET_ID_ENVELOPE_CENTERED,
775   GADGET_ID_MM_LASER_RED,
776   GADGET_ID_MM_LASER_GREEN,
777   GADGET_ID_MM_LASER_BLUE,
778   GADGET_ID_DF_LASER_RED,
779   GADGET_ID_DF_LASER_GREEN,
780   GADGET_ID_DF_LASER_BLUE,
781   GADGET_ID_ROTATE_MM_BALL_CONTENT,
782   GADGET_ID_EXPLODE_MM_BALL,
783   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
784   GADGET_ID_CUSTOM_CAN_EXPLODE,
785   GADGET_ID_CUSTOM_EXPLODE_FIRE,
786   GADGET_ID_CUSTOM_EXPLODE_SMASH,
787   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
788   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
789   GADGET_ID_CUSTOM_DEADLY,
790   GADGET_ID_CUSTOM_CAN_MOVE,
791   GADGET_ID_CUSTOM_CAN_FALL,
792   GADGET_ID_CUSTOM_CAN_SMASH,
793   GADGET_ID_CUSTOM_SLIPPERY,
794   GADGET_ID_CUSTOM_ACCESSIBLE,
795   GADGET_ID_CUSTOM_GRAV_REACHABLE,
796   GADGET_ID_CUSTOM_USE_LAST_VALUE,
797   GADGET_ID_CUSTOM_USE_GRAPHIC,
798   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
799   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
800   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
801   GADGET_ID_CUSTOM_CAN_CHANGE,
802   GADGET_ID_CHANGE_USE_CONTENT,
803   GADGET_ID_CHANGE_USE_EXPLOSION,
804   GADGET_ID_CHANGE_ONLY_COMPLETE,
805   GADGET_ID_CHANGE_USE_RANDOM,
806   GADGET_ID_CHANGE_HAS_ACTION,
807   GADGET_ID_CHANGE_DELAY,
808   GADGET_ID_CHANGE_BY_DIRECT_ACT,
809   GADGET_ID_CHANGE_BY_OTHER_ACT,
810
811   NUM_STATIC_GADGET_IDS
812 };
813
814 // gadgets for buttons in element list (dynamic)
815 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
816 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
817                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
818
819 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
820
821 // radio button numbers
822 enum
823 {
824   RADIO_NR_NONE,
825   RADIO_NR_DRAWING_TOOLBOX,
826   RADIO_NR_RANDOM_ELEMENTS
827 };
828
829 // values for counter gadgets
830 enum
831 {
832   ED_COUNTER_ID_SELECT_LEVEL,
833   ED_COUNTER_ID_LEVEL_XSIZE,
834   ED_COUNTER_ID_LEVEL_YSIZE,
835   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
836   ED_COUNTER_ID_LEVEL_TIMELIMIT,
837   ED_COUNTER_ID_LEVEL_TIMESCORE,
838   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
839   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
840   ED_COUNTER_ID_LEVEL_RANDOM,
841   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
842   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
843   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
844   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
845   ED_COUNTER_ID_BD_PUSHING_PROB,
846   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
847   ED_COUNTER_ID_ELEMENT_VALUE1,
848   ED_COUNTER_ID_ELEMENT_VALUE2,
849   ED_COUNTER_ID_ELEMENT_VALUE3,
850   ED_COUNTER_ID_ELEMENT_VALUE4,
851   ED_COUNTER_ID_YAMYAM_CONTENT,
852   ED_COUNTER_ID_BALL_CONTENT,
853   ED_COUNTER_ID_ANDROID_CONTENT,
854   ED_COUNTER_ID_ENVELOPE_XSIZE,
855   ED_COUNTER_ID_ENVELOPE_YSIZE,
856   ED_COUNTER_ID_INVENTORY_SIZE,
857   ED_COUNTER_ID_MM_BALL_CONTENT,
858   ED_COUNTER_ID_CUSTOM_SCORE,
859   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
860   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
861   ED_COUNTER_ID_CUSTOM_VALUE_RND,
862   ED_COUNTER_ID_PUSH_DELAY_FIX,
863   ED_COUNTER_ID_PUSH_DELAY_RND,
864   ED_COUNTER_ID_DROP_DELAY_FIX,
865   ED_COUNTER_ID_DROP_DELAY_RND,
866   ED_COUNTER_ID_MOVE_DELAY_FIX,
867   ED_COUNTER_ID_MOVE_DELAY_RND,
868   ED_COUNTER_ID_STEP_DELAY_FIX,
869   ED_COUNTER_ID_STEP_DELAY_RND,
870   ED_COUNTER_ID_EXPLOSION_DELAY,
871   ED_COUNTER_ID_IGNITION_DELAY,
872   ED_COUNTER_ID_GROUP_CONTENT,
873   ED_COUNTER_ID_CHANGE_DELAY_FIX,
874   ED_COUNTER_ID_CHANGE_DELAY_RND,
875   ED_COUNTER_ID_CHANGE_CONT_RND,
876
877   ED_NUM_COUNTERBUTTONS
878 };
879
880 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
881 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
882 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
883 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
884 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
885 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
886
887 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
888 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
889 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
890 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
891 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
892 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
893
894 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
895 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
896
897 // values for scrollbutton gadgets
898 enum
899 {
900   ED_SCROLLBUTTON_ID_AREA_UP,
901   ED_SCROLLBUTTON_ID_AREA_DOWN,
902   ED_SCROLLBUTTON_ID_AREA_LEFT,
903   ED_SCROLLBUTTON_ID_AREA_RIGHT,
904   ED_SCROLLBUTTON_ID_LIST_UP,
905   ED_SCROLLBUTTON_ID_LIST_DOWN,
906
907   ED_NUM_SCROLLBUTTONS
908 };
909
910 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
911 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
912
913 // values for scrollbar gadgets
914 enum
915 {
916   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
917   ED_SCROLLBAR_ID_AREA_VERTICAL,
918   ED_SCROLLBAR_ID_LIST_VERTICAL,
919
920   ED_NUM_SCROLLBARS
921 };
922
923 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
924 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
925
926 // values for text input gadgets
927 enum
928 {
929   ED_TEXTINPUT_ID_LEVEL_NAME,
930   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
931   ED_TEXTINPUT_ID_LEVELSET_NAME,
932   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
933   ED_TEXTINPUT_ID_ELEMENT_NAME,
934
935   ED_NUM_TEXTINPUT
936 };
937
938 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
939 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
940
941 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
942 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
943
944 // values for text area gadgets
945 enum
946 {
947   ED_TEXTAREA_ID_ENVELOPE_INFO,
948
949   ED_NUM_TEXTAREAS
950 };
951
952 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
953 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
954
955 // values for selectbox gadgets
956 enum
957 {
958   ED_SELECTBOX_ID_TIME_OR_STEPS,
959   ED_SELECTBOX_ID_TIME_SCORE_BASE,
960   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
961   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
962   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
963   ED_SELECTBOX_ID_WIND_DIRECTION,
964   ED_SELECTBOX_ID_PLAYER_SPEED,
965   ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
966   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
967   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
968   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
969   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
970   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
971   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
972   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
973   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
974   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
975   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
976   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
977   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
978   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
979   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
980   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
981   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
982   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
983   ED_SELECTBOX_ID_CHANGE_SIDE,
984   ED_SELECTBOX_ID_CHANGE_PLAYER,
985   ED_SELECTBOX_ID_CHANGE_PAGE,
986   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
987   ED_SELECTBOX_ID_ACTION_TYPE,
988   ED_SELECTBOX_ID_ACTION_MODE,
989   ED_SELECTBOX_ID_ACTION_ARG,
990   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
991   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
992
993   ED_NUM_SELECTBOX
994 };
995
996 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
997 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
998
999 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1000 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1001
1002 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1003 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1004
1005 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
1006 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
1007 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
1008 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
1009 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
1010 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
1011
1012 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
1013 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
1014
1015 // values for textbutton gadgets
1016 enum
1017 {
1018   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
1019   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1020   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1021   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1022   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1023   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1024   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1025   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1026   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1027   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1028   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1029   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1030   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1031   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1032
1033   ED_NUM_TEXTBUTTONS
1034 };
1035
1036 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1037 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1038
1039 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1040 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1041
1042 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1043 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1044
1045 // values for graphicbutton gadgets
1046 enum
1047 {
1048   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1049   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1050   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1051   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1052
1053   ED_NUM_GRAPHICBUTTONS
1054 };
1055
1056 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1057 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1058
1059 // values for checkbutton gadgets
1060 enum
1061 {
1062   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1063   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1064   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1065   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1066   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1067   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1068   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1069   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1070   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1071   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1072   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1073   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1074   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1075   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1076   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1077   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1078   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1079   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1080   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1081   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1082   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1083   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1084   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1085   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1086   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1087   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1088   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1089   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1090   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1091   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1092   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1093   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1094   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1095   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1096   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1097   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1098   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1099   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1100   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1101   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1102   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1103   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1104   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1105   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1106   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1107   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1108   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1109   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1110   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1111   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1112   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1113   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1114   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1115   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1116   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1117   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1118   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1119   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1120   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1121   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1122   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1123   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1124   ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
1125   ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
1126   ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
1127   ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
1128   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1129   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1130   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1131   ED_CHECKBUTTON_ID_MM_LASER_RED,
1132   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1133   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1134   ED_CHECKBUTTON_ID_DF_LASER_RED,
1135   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1136   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1137   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1138   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1139   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1140   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1141   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1142   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1143   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1144   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1145   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1146   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1147   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1148   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1149   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1150   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1151   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1152   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1153   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1154   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1155   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1156   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1157   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1158   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1159   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1160   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1161   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1162   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1163   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1164
1165   ED_NUM_CHECKBUTTONS
1166 };
1167
1168 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1169 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1170
1171 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1172 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1173
1174 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1175 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1176
1177 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1178 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
1179
1180 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1181 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1182 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1183 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1184 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1185 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1186
1187 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1188 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1189
1190 // values for radiobutton gadgets
1191 enum
1192 {
1193   ED_RADIOBUTTON_ID_PERCENTAGE,
1194   ED_RADIOBUTTON_ID_QUANTITY,
1195
1196   ED_NUM_RADIOBUTTONS
1197 };
1198
1199 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1200 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1201
1202 // values for drawing area gadgets
1203 enum
1204 {
1205   ED_DRAWING_ID_DRAWING_LEVEL,
1206   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1207   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1208   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1209   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1210   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1211   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1212   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1213   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1214   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1215   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1216   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1217   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1218   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1219   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1220   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1221   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1222   ED_DRAWING_ID_ANDROID_CONTENT,
1223   ED_DRAWING_ID_AMOEBA_CONTENT,
1224   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1225   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1226   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1227   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1228   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1229   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1230   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1231   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1232   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1233   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1234   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1235   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1236   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1237   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1238   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1239   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1240   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1241   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1242   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1243   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1244   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1245   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1246   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1247   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1248   ED_DRAWING_ID_BD_NUT_CONTENT,
1249   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1250   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1251   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
1252   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
1253   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
1254   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
1255   ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
1256   ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
1257   ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
1258   ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
1259   ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
1260   ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
1261   ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
1262   ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
1263   ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
1264   ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
1265   ED_DRAWING_ID_START_ELEMENT,
1266   ED_DRAWING_ID_ARTWORK_ELEMENT,
1267   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1268   ED_DRAWING_ID_INVENTORY_CONTENT,
1269   ED_DRAWING_ID_MM_BALL_CONTENT,
1270   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1271   ED_DRAWING_ID_CUSTOM_CONTENT,
1272   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1273   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1274   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1275   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1276   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1277   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1278   ED_DRAWING_ID_GROUP_CONTENT,
1279   ED_DRAWING_ID_RANDOM_BACKGROUND,
1280
1281   ED_NUM_DRAWING_AREAS
1282 };
1283
1284 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1285 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1286
1287
1288 // ----------------------------------------------------------------------------
1289 // some internally used definitions
1290 // ----------------------------------------------------------------------------
1291
1292 // values for CopyLevelToUndoBuffer()
1293 #define UNDO_IMMEDIATE                  0
1294 #define UNDO_ACCUMULATE                 1
1295
1296 // values for scrollbars
1297 #define ED_SCROLL_NO                    0
1298 #define ED_SCROLL_LEFT                  1
1299 #define ED_SCROLL_RIGHT                 2
1300 #define ED_SCROLL_UP                    4
1301 #define ED_SCROLL_DOWN                  8
1302
1303 // screens in the level editor
1304 #define ED_MODE_DRAWING                 0
1305 #define ED_MODE_LEVELCONFIG             1
1306 #define ED_MODE_PROPERTIES              2
1307 #define ED_MODE_PALETTE                 3
1308
1309 // sub-screens in the global settings section
1310 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1311 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1312 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1313 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1314
1315 // sub-screens in the element properties section
1316 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1317 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1318 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1319 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1320 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1321
1322 // how many steps can be cancelled
1323 #define NUM_UNDO_STEPS                  (64 + 1)
1324
1325 // values for elements with score for certain actions
1326 #define MIN_SCORE                       0
1327 #define MAX_SCORE                       999
1328
1329 // values for elements with count for collecting
1330 #define MIN_COLLECT_COUNT               0
1331 #define MAX_COLLECT_COUNT               999
1332
1333 // values for random placement
1334 #define RANDOM_USE_PERCENTAGE           0
1335 #define RANDOM_USE_QUANTITY             1
1336
1337 // values for level set save mode
1338 #define LEVELSET_SAVE_MODE_UPDATE       0
1339 #define LEVELSET_SAVE_MODE_CREATE       1
1340
1341 // default value for element tile size in drawing area
1342 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1343 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1344
1345
1346 // ----------------------------------------------------------------------------
1347 // some internally used data structure definitions
1348 // ----------------------------------------------------------------------------
1349
1350 static struct
1351 {
1352   int graphic;
1353   int gadget_id;
1354   struct XYTileSize *pos;
1355   int gadget_type;
1356   char *infotext;
1357   char shortcut;
1358 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1359 {
1360   // note: some additional characters are already reserved for "cheat mode"
1361   // shortcuts (":XYZ" style) -- for details, see "events.c"
1362
1363   // ---------- toolbox control buttons ---------------------------------------
1364
1365   {
1366     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1367     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1368     "Draw single items",                        's'
1369   },
1370   {
1371     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1372     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1373     "Draw connected items",                     'd'
1374   },
1375   {
1376     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1377     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1378     "Draw lines",                               'l'
1379   },
1380   {
1381     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1382     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1383     "Draw arcs",                                'a'
1384   },
1385   {
1386     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1387     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1388     "Draw outline rectangles",                  'r'
1389   },
1390   {
1391     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1392     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1393     "Draw filled rectangles",                   'R'
1394   },
1395   {
1396     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1397     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1398     "Wrap (rotate) level up",                   0
1399   },
1400   {
1401     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1402     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1403     "Enter text elements",                      't'
1404   },
1405   {
1406     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1407     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1408     "Flood fill",                               'f'
1409   },
1410   {
1411     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1412     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1413     "Wrap (rotate) level left",                 0
1414   },
1415   {
1416     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1417     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1418     "Zoom level tile size",                     '+'
1419   },
1420   {
1421     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1422     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1423     "Wrap (rotate) level right",                0
1424   },
1425   {
1426     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1427     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1428     "Random element placement",                 0
1429   },
1430   {
1431     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1432     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1433     "Grab brush",                               'b'
1434   },
1435   {
1436     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1437     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1438     "Wrap (rotate) level down",                 0
1439   },
1440   {
1441     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1442     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1443     "Pick drawing element",                     ','
1444   },
1445
1446   // ---------- level control buttons -----------------------------------------
1447
1448   {
1449     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1450     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1451     "Undo/redo last operation",                 'u'
1452   },
1453   {
1454     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1455     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1456     "Level and editor settings",                'I'
1457   },
1458   {
1459     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1460     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1461     "Save level",                               'S'
1462   },
1463   {
1464     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1465     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1466     "Clear level",                              'C'
1467   },
1468   {
1469     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1470     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1471     "Test level",                               'T'
1472   },
1473   {
1474     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1475     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1476     "Exit level editor",                        'E'
1477   },
1478
1479   // ---------- CE and GE control buttons -------------------------------------
1480
1481   {
1482     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1483     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1484     "Copy settings from other element",         0
1485   },
1486   {
1487     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1488     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1489     "Copy settings to other element",           0
1490   },
1491   {
1492     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1493     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1494     "Exchange element with other element",      0
1495   },
1496   {
1497     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1498     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1499     "Copy settings from this element",          0
1500   },
1501   {
1502     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1503     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1504     "Paste settings to this element",           0
1505   },
1506
1507   // ---------- palette control buttons ---------------------------------------
1508
1509   {
1510     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1511     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1512     "Properties of drawing element",            'p'
1513   },
1514   {
1515     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1516     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1517     "Properties of drawing element 1",          '1'
1518   },
1519   {
1520     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1521     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1522     "Properties of drawing element 2",          '2'
1523   },
1524   {
1525     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1526     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1527     "Properties of drawing element 3",          '3'
1528   },
1529   {
1530     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1531     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1532     "Show list of elements",                    'e'
1533   }
1534 };
1535
1536 static int random_placement_value = 10;
1537 static int random_placement_method = RANDOM_USE_QUANTITY;
1538 static int random_placement_background_element = EL_SAND;
1539 static boolean random_placement_background_restricted = FALSE;
1540 static boolean stick_element_properties_window = FALSE;
1541 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1542 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1543 static struct ElementChangeInfo custom_element_change;
1544 static struct ElementGroupInfo group_element_info;
1545 static struct ElementInfo custom_element;
1546
1547 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1548 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1549 static int levelset_num_levels = 100;
1550 static boolean levelset_use_levelset_artwork = FALSE;
1551 static boolean levelset_copy_level_template = FALSE;
1552 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1553
1554 static struct
1555 {
1556   int gadget_type_id;
1557   int x, y;
1558   int min_value, max_value;
1559   int gadget_id_down, gadget_id_up;
1560   int gadget_id_text;
1561   int gadget_id_align;
1562   int *value;
1563   char *text_above, *text_left, *text_right;
1564 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1565 {
1566   // ---------- current level number ------------------------------------------
1567
1568   {
1569     ED_COUNTER_ID_SELECT_LEVEL,
1570     -1, -1,     // these values are not constant, but can change at runtime
1571     1,                                          100,
1572     GADGET_ID_SELECT_LEVEL_DOWN,                GADGET_ID_SELECT_LEVEL_UP,
1573     GADGET_ID_SELECT_LEVEL_TEXT,                GADGET_ID_NONE,
1574     &level_nr,
1575     NULL,                                       NULL, NULL
1576   },
1577
1578   // ---------- level and editor settings -------------------------------------
1579
1580   {
1581     ED_COUNTER_ID_LEVEL_XSIZE,
1582     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1583     MIN_LEV_FIELDX,                             MAX_LEV_FIELDX,
1584     GADGET_ID_LEVEL_XSIZE_DOWN,                 GADGET_ID_LEVEL_XSIZE_UP,
1585     GADGET_ID_LEVEL_XSIZE_TEXT,                 GADGET_ID_NONE,
1586     &level.fieldx,
1587     "Playfield size:",                          NULL, "Width",
1588   },
1589   {
1590     ED_COUNTER_ID_LEVEL_YSIZE,
1591     -1,                                         ED_LEVEL_SETTINGS_YPOS(4),
1592     MIN_LEV_FIELDY,                             MAX_LEV_FIELDY,
1593     GADGET_ID_LEVEL_YSIZE_DOWN,                 GADGET_ID_LEVEL_YSIZE_UP,
1594     GADGET_ID_LEVEL_YSIZE_TEXT,                 GADGET_ID_LEVEL_XSIZE_UP,
1595     &level.fieldy,
1596     NULL,                                       " ", "Height",
1597   },
1598   {
1599     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1600     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
1601     0,                                          999,
1602     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,             GADGET_ID_LEVEL_GEMSLIMIT_UP,
1603     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,             GADGET_ID_NONE,
1604     &level.gems_needed,
1605     NULL,                                       "Number of gems to collect:", NULL
1606   },
1607   {
1608     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1609     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
1610     0,                                          9999,
1611     GADGET_ID_LEVEL_TIMELIMIT_DOWN,             GADGET_ID_LEVEL_TIMELIMIT_UP,
1612     GADGET_ID_LEVEL_TIMELIMIT_TEXT,             GADGET_ID_NONE,
1613     &level.time,
1614     "Time or step limit to solve level:",       NULL, NULL
1615   },
1616   {
1617     ED_COUNTER_ID_LEVEL_TIMESCORE,
1618     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
1619     0,                                          999,
1620     GADGET_ID_LEVEL_TIMESCORE_DOWN,             GADGET_ID_LEVEL_TIMESCORE_UP,
1621     GADGET_ID_LEVEL_TIMESCORE_TEXT,             GADGET_ID_NONE,
1622     &level.score[SC_TIME_BONUS],
1623     "Score for time or steps left:",            NULL, NULL
1624   },
1625   {
1626     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1627     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(13),
1628     0,                                          9999,
1629     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,           GADGET_ID_LEVEL_RANDOM_SEED_UP,
1630     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,           GADGET_ID_NONE,
1631     &level.random_seed,
1632     NULL,                                       "Random seed:", "(0 => random)"
1633   },
1634   {
1635     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1636     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1637     1,                                          MAX_LEVELS,
1638     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,         GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1639     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,         GADGET_ID_NONE,
1640     &levelset_num_levels,
1641     "Number of levels:",                        NULL, NULL,
1642   },
1643   {
1644     ED_COUNTER_ID_LEVEL_RANDOM,
1645     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1646     1,                                          100,
1647     GADGET_ID_LEVEL_RANDOM_DOWN,                GADGET_ID_LEVEL_RANDOM_UP,
1648     GADGET_ID_LEVEL_RANDOM_TEXT,                GADGET_ID_NONE,
1649     &random_placement_value,
1650     "Random element placement:",                NULL, "in"
1651   },
1652   {
1653     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1654     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1655     50,                                         500,
1656     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,           GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1657     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,           GADGET_ID_NONE,
1658     &level.bd_cycle_delay_ms,
1659     NULL,                                       NULL, "Game cycle delay (ms)"
1660   },
1661   {
1662     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1663     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1664     0,                                          32,
1665     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,          GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1666     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,          GADGET_ID_NONE,
1667     &level.bd_cycle_delay_c64,
1668     NULL,                                       NULL, "Game cycle delay (C64-style)"
1669   },
1670   {
1671     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1672     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1673     1,                                          40,
1674     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1675     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1676     &level.bd_hatching_delay_cycles,
1677     NULL,                                       NULL, "Hatching delay (cycles)"
1678   },
1679   {
1680     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1681     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1682     1,                                          40,
1683     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1684     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1685     &level.bd_hatching_delay_seconds,
1686     NULL,                                       NULL, "Hatching delay (seconds)"
1687   },
1688
1689   // ---------- element settings: configure (various elements) ----------------
1690
1691   {
1692     ED_COUNTER_ID_BD_PUSHING_PROB,
1693     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1694     0,                                          100,
1695     GADGET_ID_BD_PUSHING_PROB_DOWN,             GADGET_ID_BD_PUSHING_PROB_UP,
1696     GADGET_ID_BD_PUSHING_PROB_TEXT,             GADGET_ID_NONE,
1697     &level.bd_pushing_prob,
1698     NULL,                                       NULL, "Push probability"
1699   },
1700   {
1701     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1702     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1703     0,                                          100,
1704     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1705     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1706     &level.bd_pushing_prob_with_sweet,
1707     NULL,                                       NULL, "Push probability with sweet"
1708   },
1709   {
1710     ED_COUNTER_ID_ELEMENT_VALUE1,
1711     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1712     MIN_SCORE,                                  MAX_SCORE,
1713     GADGET_ID_ELEMENT_VALUE1_DOWN,              GADGET_ID_ELEMENT_VALUE1_UP,
1714     GADGET_ID_ELEMENT_VALUE1_TEXT,              GADGET_ID_NONE,
1715     NULL,                                       // will be set when used
1716     NULL,                                       NULL, NULL
1717   },
1718   {
1719     ED_COUNTER_ID_ELEMENT_VALUE2,
1720     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
1721     MIN_SCORE,                                  MAX_SCORE,
1722     GADGET_ID_ELEMENT_VALUE2_DOWN,              GADGET_ID_ELEMENT_VALUE2_UP,
1723     GADGET_ID_ELEMENT_VALUE2_TEXT,              GADGET_ID_NONE,
1724     NULL,                                       // will be set when used
1725     NULL,                                       NULL, NULL
1726   },
1727   {
1728     ED_COUNTER_ID_ELEMENT_VALUE3,
1729     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1730     MIN_SCORE,                                  MAX_SCORE,
1731     GADGET_ID_ELEMENT_VALUE3_DOWN,              GADGET_ID_ELEMENT_VALUE3_UP,
1732     GADGET_ID_ELEMENT_VALUE3_TEXT,              GADGET_ID_NONE,
1733     NULL,                                       // will be set when used
1734     NULL,                                       NULL, NULL
1735   },
1736   {
1737     ED_COUNTER_ID_ELEMENT_VALUE4,
1738     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1739     MIN_SCORE,                                  MAX_SCORE,
1740     GADGET_ID_ELEMENT_VALUE4_DOWN,              GADGET_ID_ELEMENT_VALUE4_UP,
1741     GADGET_ID_ELEMENT_VALUE4_TEXT,              GADGET_ID_NONE,
1742     NULL,                                       // will be set when used
1743     NULL,                                       NULL, NULL
1744   },
1745   {
1746     ED_COUNTER_ID_YAMYAM_CONTENT,
1747     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1748     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1749     GADGET_ID_YAMYAM_CONTENT_DOWN,              GADGET_ID_YAMYAM_CONTENT_UP,
1750     GADGET_ID_YAMYAM_CONTENT_TEXT,              GADGET_ID_NONE,
1751     &level.num_yamyam_contents,
1752     NULL,                                       NULL, "Number of content areas"
1753   },
1754   {
1755     ED_COUNTER_ID_BALL_CONTENT,
1756     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1757     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1758     GADGET_ID_BALL_CONTENT_DOWN,                GADGET_ID_BALL_CONTENT_UP,
1759     GADGET_ID_BALL_CONTENT_TEXT,                GADGET_ID_NONE,
1760     &level.num_ball_contents,
1761     NULL,                                       NULL, "Number of content areas"
1762   },
1763   {
1764     ED_COUNTER_ID_ANDROID_CONTENT,
1765     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1766     MIN_ANDROID_ELEMENTS,                       MAX_ANDROID_ELEMENTS,
1767     GADGET_ID_ANDROID_CONTENT_DOWN,             GADGET_ID_ANDROID_CONTENT_UP,
1768     GADGET_ID_ANDROID_CONTENT_TEXT,             GADGET_ID_NONE,
1769     &level.num_android_clone_elements,
1770     NULL,                                       NULL, "Number of clonable elements"
1771   },
1772   {
1773     ED_COUNTER_ID_ENVELOPE_XSIZE,
1774     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1775     MIN_ENVELOPE_XSIZE,                         MAX_ENVELOPE_XSIZE,
1776     GADGET_ID_ENVELOPE_XSIZE_DOWN,              GADGET_ID_ENVELOPE_XSIZE_UP,
1777     GADGET_ID_ENVELOPE_XSIZE_TEXT,              GADGET_ID_NONE,
1778     NULL,                                       // will be set when used
1779     NULL,                                       NULL, "Width",
1780   },
1781   {
1782     ED_COUNTER_ID_ENVELOPE_YSIZE,
1783     -1,                                         ED_ELEMENT_SETTINGS_YPOS(0),
1784     MIN_ENVELOPE_YSIZE,                         MAX_ENVELOPE_YSIZE,
1785     GADGET_ID_ENVELOPE_YSIZE_DOWN,              GADGET_ID_ENVELOPE_YSIZE_UP,
1786     GADGET_ID_ENVELOPE_YSIZE_TEXT,              GADGET_ID_ENVELOPE_XSIZE_UP,
1787     NULL,                                       // will be set when used
1788     NULL,                                       " ", "Height",
1789   },
1790   {
1791     ED_COUNTER_ID_INVENTORY_SIZE,
1792     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1793     MIN_INITIAL_INVENTORY_SIZE,                 MAX_INITIAL_INVENTORY_SIZE,
1794     GADGET_ID_INVENTORY_SIZE_DOWN,              GADGET_ID_INVENTORY_SIZE_UP,
1795     GADGET_ID_INVENTORY_SIZE_TEXT,              GADGET_ID_NONE,
1796     &level.initial_inventory_size[0],
1797     NULL,                                       NULL, "Number of inventory elements"
1798   },
1799   {
1800     ED_COUNTER_ID_MM_BALL_CONTENT,
1801     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1802     MIN_ELEMENTS_IN_GROUP,                      MAX_MM_BALL_CONTENTS,
1803     GADGET_ID_MM_BALL_CONTENT_DOWN,             GADGET_ID_MM_BALL_CONTENT_UP,
1804     GADGET_ID_MM_BALL_CONTENT_TEXT,             GADGET_ID_NONE,
1805     &level.num_mm_ball_contents,
1806     NULL,                                       NULL, "Number of content elements"
1807   },
1808
1809   // ---------- element settings: configure 1 (custom elements) ---------------
1810
1811   {
1812     ED_COUNTER_ID_CUSTOM_SCORE,
1813     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1814     MIN_SCORE,                                  MAX_SCORE,
1815     GADGET_ID_CUSTOM_SCORE_DOWN,                GADGET_ID_CUSTOM_SCORE_UP,
1816     GADGET_ID_CUSTOM_SCORE_TEXT,                GADGET_ID_NONE,
1817     &custom_element.collect_score_initial,
1818     NULL,                                       "CE score", " "
1819   },
1820   {
1821     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1822     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1823     MIN_COLLECT_COUNT,                          MAX_COLLECT_COUNT,
1824     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,             GADGET_ID_CUSTOM_GEMCOUNT_UP,
1825     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,             GADGET_ID_CUSTOM_SCORE_UP,
1826     &custom_element.collect_count_initial,
1827     NULL,                                       "CE count", NULL
1828   },
1829   {
1830     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1831     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1832     0,                                          9999,
1833     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1834     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,            GADGET_ID_NONE,
1835     &custom_element.ce_value_fixed_initial,
1836     NULL,                                       "CE value", NULL
1837   },
1838   {
1839     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1840     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1841     0,                                          9999,
1842     GADGET_ID_CUSTOM_VALUE_RND_DOWN,            GADGET_ID_CUSTOM_VALUE_RND_UP,
1843     GADGET_ID_CUSTOM_VALUE_RND_TEXT,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1844     &custom_element.ce_value_random_initial,
1845     NULL,                                       "+random", NULL
1846   },
1847   {
1848     ED_COUNTER_ID_PUSH_DELAY_FIX,
1849     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1850     0,                                          999,
1851     GADGET_ID_PUSH_DELAY_FIX_DOWN,              GADGET_ID_PUSH_DELAY_FIX_UP,
1852     GADGET_ID_PUSH_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1853     &custom_element.push_delay_fixed,
1854     NULL,                                       "Push delay", NULL
1855   },
1856   {
1857     ED_COUNTER_ID_PUSH_DELAY_RND,
1858     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1859     0,                                          999,
1860     GADGET_ID_PUSH_DELAY_RND_DOWN,              GADGET_ID_PUSH_DELAY_RND_UP,
1861     GADGET_ID_PUSH_DELAY_RND_TEXT,              GADGET_ID_PUSH_DELAY_FIX_UP,
1862     &custom_element.push_delay_random,
1863     NULL,                                       "+random", NULL
1864   },
1865   {
1866     ED_COUNTER_ID_DROP_DELAY_FIX,
1867     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(7),
1868     0,                                          999,
1869     GADGET_ID_DROP_DELAY_FIX_DOWN,              GADGET_ID_DROP_DELAY_FIX_UP,
1870     GADGET_ID_DROP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1871     &custom_element.drop_delay_fixed,
1872     NULL,                                       "Drop delay", NULL
1873   },
1874   {
1875     ED_COUNTER_ID_DROP_DELAY_RND,
1876     -1,                                         ED_ELEMENT_SETTINGS_YPOS(7),
1877     0,                                          999,
1878     GADGET_ID_DROP_DELAY_RND_DOWN,              GADGET_ID_DROP_DELAY_RND_UP,
1879     GADGET_ID_DROP_DELAY_RND_TEXT,              GADGET_ID_DROP_DELAY_FIX_UP,
1880     &custom_element.drop_delay_random,
1881     NULL,                                       "+random", NULL
1882   },
1883
1884   // ---------- element settings: configure 2 (custom elements) ---------------
1885
1886   {
1887     ED_COUNTER_ID_MOVE_DELAY_FIX,
1888     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1889     0,                                          999,
1890     GADGET_ID_MOVE_DELAY_FIX_DOWN,              GADGET_ID_MOVE_DELAY_FIX_UP,
1891     GADGET_ID_MOVE_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1892     &custom_element.move_delay_fixed,
1893     NULL,                                       "Move delay", NULL
1894   },
1895   {
1896     ED_COUNTER_ID_MOVE_DELAY_RND,
1897     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1898     0,                                          999,
1899     GADGET_ID_MOVE_DELAY_RND_DOWN,              GADGET_ID_MOVE_DELAY_RND_UP,
1900     GADGET_ID_MOVE_DELAY_RND_TEXT,              GADGET_ID_MOVE_DELAY_FIX_UP,
1901     &custom_element.move_delay_random,
1902     NULL,                                       "+random", NULL
1903   },
1904   {
1905     ED_COUNTER_ID_STEP_DELAY_FIX,
1906     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1907     0,                                          999,
1908     GADGET_ID_STEP_DELAY_FIX_DOWN,              GADGET_ID_STEP_DELAY_FIX_UP,
1909     GADGET_ID_STEP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1910     &custom_element.step_delay_fixed,
1911     NULL,                                       "Step delay", NULL
1912   },
1913   {
1914     ED_COUNTER_ID_STEP_DELAY_RND,
1915     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1916     0,                                          999,
1917     GADGET_ID_STEP_DELAY_RND_DOWN,              GADGET_ID_STEP_DELAY_RND_UP,
1918     GADGET_ID_STEP_DELAY_RND_TEXT,              GADGET_ID_STEP_DELAY_FIX_UP,
1919     &custom_element.step_delay_random,
1920     NULL,                                       "+random", NULL
1921   },
1922   {
1923     ED_COUNTER_ID_EXPLOSION_DELAY,
1924     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
1925     0,                                          999,
1926     GADGET_ID_EXPLOSION_DELAY_DOWN,             GADGET_ID_EXPLOSION_DELAY_UP,
1927     GADGET_ID_EXPLOSION_DELAY_TEXT,             GADGET_ID_NONE,
1928     &custom_element.explosion_delay,
1929     NULL,                                       "Explosion delay", NULL
1930   },
1931   {
1932     ED_COUNTER_ID_IGNITION_DELAY,
1933     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
1934     0,                                          999,
1935     GADGET_ID_IGNITION_DELAY_DOWN,              GADGET_ID_IGNITION_DELAY_UP,
1936     GADGET_ID_IGNITION_DELAY_TEXT,              GADGET_ID_NONE,
1937     &custom_element.ignition_delay,
1938     NULL,                                       "Ignition delay", "(by fire)"
1939   },
1940
1941   // ---------- element settings: configure (group elements) ------------------
1942
1943   {
1944     ED_COUNTER_ID_GROUP_CONTENT,
1945     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1946     MIN_ELEMENTS_IN_GROUP,                      MAX_ELEMENTS_IN_GROUP,
1947     GADGET_ID_GROUP_CONTENT_DOWN,               GADGET_ID_GROUP_CONTENT_UP,
1948     GADGET_ID_GROUP_CONTENT_TEXT,               GADGET_ID_NONE,
1949     &group_element_info.num_elements,
1950     NULL,                                       NULL, "Number of elements in group"
1951   },
1952
1953   // ---------- element settings: advanced (custom elements) ------------------
1954
1955   {
1956     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1957     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(2),
1958     0,                                          999,
1959     GADGET_ID_CHANGE_DELAY_FIX_DOWN,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1960     GADGET_ID_CHANGE_DELAY_FIX_TEXT,            GADGET_ID_NONE,
1961     &custom_element_change.delay_fixed,
1962     NULL,                                       "CE delay", NULL,
1963   },
1964   {
1965     ED_COUNTER_ID_CHANGE_DELAY_RND,
1966     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
1967     0,                                          999,
1968     GADGET_ID_CHANGE_DELAY_RND_DOWN,            GADGET_ID_CHANGE_DELAY_RND_UP,
1969     GADGET_ID_CHANGE_DELAY_RND_TEXT,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1970     &custom_element_change.delay_random,
1971     NULL,                                       "+random", NULL
1972   },
1973   {
1974     ED_COUNTER_ID_CHANGE_CONT_RND,
1975     ED_ELEMENT_SETTINGS_XPOS(3),                ED_ELEMENT_SETTINGS_YPOS(12),
1976     0,                                          100,
1977     GADGET_ID_CHANGE_CONT_RND_DOWN,             GADGET_ID_CHANGE_CONT_RND_UP,
1978     GADGET_ID_CHANGE_CONT_RND_TEXT,             GADGET_ID_NONE,
1979     &custom_element_change.random_percentage,
1980     NULL,                                       "Use random replace:", "%"
1981   },
1982 };
1983
1984 static struct
1985 {
1986   int gadget_type_id;
1987   int x, y;
1988   int gadget_id;
1989   int size;
1990   char *value;
1991   char *text_above, *infotext;
1992 } textinput_info[ED_NUM_TEXTINPUT] =
1993 {
1994   {
1995     ED_TEXTINPUT_ID_LEVEL_NAME,
1996     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1997     GADGET_ID_LEVEL_NAME,
1998     MAX_LEVEL_NAME_LEN,
1999     level.name,
2000     "Title:", "Title for this level"
2001   },
2002   {
2003     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
2004     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2005     GADGET_ID_LEVEL_AUTHOR,
2006     MAX_LEVEL_AUTHOR_LEN,
2007     level.author,
2008     "Author:", "Author for this level"
2009   },
2010   {
2011     ED_TEXTINPUT_ID_LEVELSET_NAME,
2012     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
2013     GADGET_ID_LEVELSET_NAME,
2014     MAX_LEVEL_NAME_LEN,
2015     levelset_name,
2016     "Title:", "Title for this or new level set"
2017   },
2018   {
2019     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
2020     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2021     GADGET_ID_LEVELSET_AUTHOR,
2022     MAX_LEVEL_AUTHOR_LEN,
2023     levelset_author,
2024     "Author:", "Author for this or new level set"
2025   },
2026   {
2027     ED_TEXTINPUT_ID_ELEMENT_NAME,
2028     -1, -1,     // these values are not constant, but can change at runtime
2029     GADGET_ID_ELEMENT_NAME,
2030     MAX_ELEMENT_NAME_LEN - 2,                   // currently 2 chars less editable
2031     custom_element.description,
2032     NULL, "Element name"
2033   }
2034 };
2035
2036 static struct
2037 {
2038   int gadget_type_id;
2039   int x, y;
2040   int gadget_id;
2041   int xsize, ysize;
2042   char *value;
2043   char *text_above, *text_above_cropped, *infotext;
2044 } textarea_info[ED_NUM_TEXTAREAS] =
2045 {
2046   {
2047     ED_TEXTAREA_ID_ENVELOPE_INFO,
2048     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
2049     GADGET_ID_ENVELOPE_INFO,
2050     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2051     NULL,
2052     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2053   }
2054 };
2055
2056 static struct ValueTextInfo options_time_or_steps[] =
2057 {
2058   { 0,                                  "seconds"                       },
2059   { 1,                                  "steps"                         },
2060
2061   { -1,                                 NULL                            }
2062 };
2063
2064 static struct ValueTextInfo options_time_score_base[] =
2065 {
2066   { 1,                                  "per second/step"               },
2067   { 10,                                 "per 10 seconds/steps"          },
2068
2069   { -1,                                 NULL                            }
2070 };
2071
2072 static struct ValueTextInfo options_game_engine_type[] =
2073 {
2074   { GAME_ENGINE_TYPE_RND,               "Rocks'n'Diamonds"              },
2075   { GAME_ENGINE_TYPE_BD,                "Boulder Dash"                  },
2076   { GAME_ENGINE_TYPE_EM,                "Emerald Mine"                  },
2077   { GAME_ENGINE_TYPE_SP,                "Supaplex"                      },
2078   { GAME_ENGINE_TYPE_MM,                "Mirror Magic"                  },
2079
2080   { -1,                                 NULL                            }
2081 };
2082
2083 static struct ValueTextInfo options_levelset_save_mode[] =
2084 {
2085   { LEVELSET_SAVE_MODE_UPDATE,          "Update this level set"         },
2086   { LEVELSET_SAVE_MODE_CREATE,          "Create new level set"          },
2087
2088   { -1,                                 NULL                            }
2089 };
2090
2091 static struct ValueTextInfo options_bd_gravity_direction[] =
2092 {
2093   { GD_MV_DOWN,                         "down"                          },
2094   { GD_MV_UP,                           "up"                            },
2095   { GD_MV_LEFT,                         "left"                          },
2096   { GD_MV_RIGHT,                        "right"                         },
2097
2098   { -1,                                 NULL                            }
2099 };
2100
2101 static struct ValueTextInfo options_wind_direction[] =
2102 {
2103   { MV_START_NONE,                      "none"                          },
2104   { MV_START_LEFT,                      "left"                          },
2105   { MV_START_RIGHT,                     "right"                         },
2106   { MV_START_UP,                        "up"                            },
2107   { MV_START_DOWN,                      "down"                          },
2108
2109   { -1,                                 NULL                            }
2110 };
2111
2112 static struct ValueTextInfo options_player_speed[] =
2113 {
2114   { 0,                                  "frozen"                        },
2115   { 1,                                  "very slow"                     },
2116   { 2,                                  "slow"                          },
2117   { 4,                                  "normal"                        },
2118   { 8,                                  "fast"                          },
2119   { 16,                                 "very fast"                     },
2120   { 32,                                 "ultrafast"                     },
2121
2122   { -1,                                 NULL                            }
2123 };
2124
2125 static struct ValueTextInfo options_access_type[] =
2126 {
2127   { EP_WALKABLE,                        "walkable"                      },
2128   { EP_PASSABLE,                        "passable"                      },
2129
2130   { -1,                                 NULL                            }
2131 };
2132
2133 static struct ValueTextInfo options_access_layer[] =
2134 {
2135   { EP_ACCESSIBLE_OVER,                 "over"                          },
2136   { EP_ACCESSIBLE_INSIDE,               "inside"                        },
2137   { EP_ACCESSIBLE_UNDER,                "under"                         },
2138
2139   { -1,                                 NULL                            }
2140 };
2141
2142 static struct ValueTextInfo options_access_protected[] =
2143 {
2144   { 0,                                  "unprotected"                   },
2145   { 1,                                  "protected"                     },
2146
2147   { -1,                                 NULL                            }
2148 };
2149
2150 static struct ValueTextInfo options_access_direction[] =
2151 {
2152   { MV_NO_DIRECTION,                    "no direction"                  },
2153   { MV_LEFT,                            "left"                          },
2154   { MV_RIGHT,                           "right"                         },
2155   { MV_UP,                              "up"                            },
2156   { MV_DOWN,                            "down"                          },
2157   { MV_LEFT  | MV_UP,                   "left + up"                     },
2158   { MV_LEFT  | MV_DOWN,                 "left + down"                   },
2159   { MV_RIGHT | MV_UP,                   "right + up"                    },
2160   { MV_RIGHT | MV_DOWN,                 "right + down"                  },
2161   { MV_HORIZONTAL,                      "horizontal"                    },
2162   { MV_VERTICAL,                        "vertical"                      },
2163   { MV_HORIZONTAL | MV_UP,              "horizontal + up"               },
2164   { MV_HORIZONTAL | MV_DOWN,            "horizontal + down"             },
2165   { MV_VERTICAL   | MV_LEFT,            "vertical + left"               },
2166   { MV_VERTICAL   | MV_RIGHT,           "vertical + right"              },
2167   { MV_ALL_DIRECTIONS,                  "all directions"                },
2168
2169   { -1,                                 NULL                            }
2170 };
2171
2172 static struct ValueTextInfo options_walk_to_action[] =
2173 {
2174   { EP_DIGGABLE,                        "diggable"                      },
2175   { EP_COLLECTIBLE_ONLY,                "collectible"                   },
2176   { EP_DROPPABLE,                       "collectible & droppable"       },
2177   { EP_THROWABLE,                       "collectible & throwable"       },
2178   { EP_PUSHABLE,                        "pushable"                      },
2179
2180   { -1,                                 NULL                            }
2181 };
2182
2183 static struct ValueTextInfo options_move_pattern[] =
2184 {
2185   { MV_LEFT,                            "left"                          },
2186   { MV_RIGHT,                           "right"                         },
2187   { MV_UP,                              "up"                            },
2188   { MV_DOWN,                            "down"                          },
2189   { MV_HORIZONTAL,                      "horizontal"                    },
2190   { MV_VERTICAL,                        "vertical"                      },
2191   { MV_ALL_DIRECTIONS,                  "all directions"                },
2192   { MV_WIND_DIRECTION,                  "wind direction"                },
2193   { MV_TOWARDS_PLAYER,                  "towards player"                },
2194   { MV_AWAY_FROM_PLAYER,                "away from player"              },
2195   { MV_ALONG_LEFT_SIDE,                 "along left side"               },
2196   { MV_ALONG_RIGHT_SIDE,                "along right side"              },
2197   { MV_TURNING_LEFT,                    "turning left"                  },
2198   { MV_TURNING_RIGHT,                   "turning right"                 },
2199   { MV_TURNING_LEFT_RIGHT,              "turning left, right"           },
2200   { MV_TURNING_RIGHT_LEFT,              "turning right, left"           },
2201   { MV_TURNING_RANDOM,                  "turning random"                },
2202   { MV_MAZE_RUNNER,                     "maze runner style"             },
2203   { MV_MAZE_HUNTER,                     "maze hunter style"             },
2204   { MV_WHEN_PUSHED,                     "when pushed"                   },
2205   { MV_WHEN_DROPPED,                    "when dropped/thrown"           },
2206
2207   { -1,                                 NULL                            }
2208 };
2209
2210 static struct ValueTextInfo options_move_direction[] =
2211 {
2212   { MV_START_AUTOMATIC,                 "automatic"                     },
2213   { MV_START_LEFT,                      "left"                          },
2214   { MV_START_RIGHT,                     "right"                         },
2215   { MV_START_UP,                        "up"                            },
2216   { MV_START_DOWN,                      "down"                          },
2217   { MV_START_RANDOM,                    "random"                        },
2218   { MV_START_PREVIOUS,                  "previous"                      },
2219
2220   { -1,                                 NULL                            }
2221 };
2222
2223 static struct ValueTextInfo options_move_stepsize[] =
2224 {
2225   { 0,                                  "not moving"                    },
2226   { 1,                                  "very slow"                     },
2227   { 2,                                  "slow"                          },
2228   { 4,                                  "normal"                        },
2229   { 8,                                  "fast"                          },
2230   { 16,                                 "very fast"                     },
2231   { 32,                                 "even faster"                   },
2232
2233   { -1,                                 NULL                            }
2234 };
2235
2236 static struct ValueTextInfo options_move_leave_type[] =
2237 {
2238   { LEAVE_TYPE_UNLIMITED,               "leave behind"                  },
2239   { LEAVE_TYPE_LIMITED,                 "change it to"                  },
2240
2241   { -1,                                 NULL                            }
2242 };
2243
2244 static struct ValueTextInfo options_smash_targets[] =
2245 {
2246   { EP_CAN_SMASH_PLAYER,                "player"                        },
2247 #if 0
2248   { EP_CAN_SMASH_ENEMIES,               "enemies"                       },
2249 #endif
2250   { EP_CAN_SMASH_EVERYTHING,            "everything"                    },
2251
2252   { -1,                                 NULL                            }
2253 };
2254
2255 static struct ValueTextInfo options_slippery_type[] =
2256 {
2257   { SLIPPERY_ANY_RANDOM,                "random"                        },
2258   { SLIPPERY_ANY_LEFT_RIGHT,            "left, right"                   },
2259   { SLIPPERY_ANY_RIGHT_LEFT,            "right, left"                   },
2260   { SLIPPERY_ONLY_LEFT,                 "only left"                     },
2261   { SLIPPERY_ONLY_RIGHT,                "only right"                    },
2262
2263   { -1,                                 NULL                            }
2264 };
2265
2266 static struct ValueTextInfo options_deadliness[] =
2267 {
2268   { EP_DONT_RUN_INTO,                   "running into"                  },
2269   { EP_DONT_COLLIDE_WITH,               "colliding with"                },
2270   { EP_DONT_GET_HIT_BY,                 "getting hit by"                },
2271   { EP_DONT_TOUCH,                      "touching"                      },
2272
2273   { -1,                                 NULL                            }
2274 };
2275
2276 static struct ValueTextInfo options_explosion_type[] =
2277 {
2278   { EXPLODES_3X3,                       "3x3"                           },
2279   { EXPLODES_CROSS,                     "3+3"                           },
2280   { EXPLODES_1X1,                       "1x1"                           },
2281
2282   { -1,                                 NULL                            }
2283 };
2284
2285 static struct ValueTextInfo options_time_units[] =
2286 {
2287   { 1,                                  "frames"                        },
2288   { FRAMES_PER_SECOND,                  "seconds"                       },
2289
2290   { -1,                                 NULL                            }
2291 };
2292
2293 static struct ValueTextInfo options_change_direct_action[] =
2294 {
2295   { CE_TOUCHED_BY_PLAYER,               "touched by player"             },
2296   { CE_PRESSED_BY_PLAYER,               "pressed by player"             },
2297   { CE_SWITCHED_BY_PLAYER,              "switched by player"            },
2298   { CE_SNAPPED_BY_PLAYER,               "snapped by player"             },
2299   { CE_PUSHED_BY_PLAYER,                "pushed by player"              },
2300   { CE_ENTERED_BY_PLAYER,               "entered by player"             },
2301   { CE_LEFT_BY_PLAYER,                  "left by player"                },
2302   { CE_DROPPED_BY_PLAYER,               "dropped/thrown by player"      },
2303   { CE_SWITCHED,                        "switched"                      },
2304   { CE_HITTING_SOMETHING,               "hitting something"             },
2305   { CE_HIT_BY_SOMETHING,                "hit by something"              },
2306 #if 0
2307   { CE_BLOCKED,                         "blocked"                       },
2308 #endif
2309   { CE_IMPACT,                          "impact (on something)"         },
2310   { CE_SMASHED,                         "smashed (from above)"          },
2311 #if 0
2312   { CE_VALUE_CHANGES,                   "CE value changes"              },
2313   { CE_SCORE_CHANGES,                   "CE score changes"              },
2314 #endif
2315   { CE_VALUE_GETS_ZERO,                 "CE value gets 0"               },
2316   { CE_SCORE_GETS_ZERO,                 "CE score gets 0"               },
2317   { CE_UNDEFINED,                       " "                             },
2318   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2319   { CE_CLICKED_BY_MOUSE,                "clicked by mouse"              },
2320   { CE_PRESSED_BY_MOUSE,                "pressed by mouse"              },
2321   { CE_UNDEFINED,                       " "                             },
2322   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2323   { CE_NEXT_TO_PLAYER,                  "next to player"                },
2324
2325   { -1,                                 NULL                            }
2326 };
2327
2328 static struct ValueTextInfo options_change_other_action[] =
2329 {
2330   { CE_PLAYER_TOUCHES_X,                "player touches"                },
2331   { CE_PLAYER_PRESSES_X,                "player presses"                },
2332   { CE_PLAYER_SWITCHES_X,               "player switches"               },
2333   { CE_PLAYER_SNAPS_X,                  "player snaps"                  },
2334   { CE_PLAYER_PUSHES_X,                 "player pushes"                 },
2335   { CE_PLAYER_ENTERS_X,                 "player enters"                 },
2336   { CE_PLAYER_LEAVES_X,                 "player leaves"                 },
2337   { CE_PLAYER_DIGS_X,                   "player digs"                   },
2338   { CE_PLAYER_COLLECTS_X,               "player collects"               },
2339   { CE_PLAYER_DROPS_X,                  "player drops/throws"           },
2340   { CE_TOUCHING_X,                      "touching"                      },
2341   { CE_HITTING_X,                       "hitting"                       },
2342   { CE_DIGGING_X,                       "digging"                       },
2343   { CE_HIT_BY_X,                        "hit by"                        },
2344   { CE_SWITCH_OF_X,                     "switch of"                     },
2345   { CE_CHANGE_OF_X,                     "change by page of"             },
2346   { CE_EXPLOSION_OF_X,                  "explosion of"                  },
2347   { CE_MOVE_OF_X,                       "move of"                       },
2348   { CE_CREATION_OF_X,                   "creation of"                   },
2349   { CE_VALUE_CHANGES_OF_X,              "CE value changes of"           },
2350   { CE_SCORE_CHANGES_OF_X,              "CE score changes of"           },
2351   { CE_VALUE_GETS_ZERO_OF_X,            "CE value gets 0 of"            },
2352   { CE_SCORE_GETS_ZERO_OF_X,            "CE score gets 0 of"            },
2353   { CE_UNDEFINED,                       " "                             },
2354   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2355   { CE_MOUSE_CLICKED_ON_X,              "mouse clicked on"              },
2356   { CE_MOUSE_PRESSED_ON_X,              "mouse pressed on"              },
2357   { CE_UNDEFINED,                       " "                             },
2358   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2359   { CE_PLAYER_NEXT_TO_X,                "player next to"                },
2360   { CE_NEXT_TO_X,                       "next to"                       },
2361
2362   { -1,                                 NULL                            }
2363 };
2364
2365 static struct ValueTextInfo options_change_trigger_side[] =
2366 {
2367   { CH_SIDE_LEFT,                       "left"                          },
2368   { CH_SIDE_RIGHT,                      "right"                         },
2369   { CH_SIDE_TOP,                        "top"                           },
2370   { CH_SIDE_BOTTOM,                     "bottom"                        },
2371   { CH_SIDE_LEFT_RIGHT,                 "left/right"                    },
2372   { CH_SIDE_TOP_BOTTOM,                 "top/bottom"                    },
2373   { CH_SIDE_ANY,                        "any"                           },
2374
2375   { -1,                                 NULL                            }
2376 };
2377
2378 static struct ValueTextInfo options_change_trigger_player[] =
2379 {
2380   { CH_PLAYER_1,                        "1"                             },
2381   { CH_PLAYER_2,                        "2"                             },
2382   { CH_PLAYER_3,                        "3"                             },
2383   { CH_PLAYER_4,                        "4"                             },
2384   { CH_PLAYER_ANY,                      "any"                           },
2385
2386   { -1,                                 NULL                            }
2387 };
2388
2389 static struct ValueTextInfo options_change_trigger_page[] =
2390 {
2391   { (1u << 0),                          "1"                             },
2392   { (1u << 1),                          "2"                             },
2393   { (1u << 2),                          "3"                             },
2394   { (1u << 3),                          "4"                             },
2395   { (1u << 4),                          "5"                             },
2396   { (1u << 5),                          "6"                             },
2397   { (1u << 6),                          "7"                             },
2398   { (1u << 7),                          "8"                             },
2399   { (1u << 8),                          "9"                             },
2400   { (1u << 9),                          "10"                            },
2401   { (1u << 10),                         "11"                            },
2402   { (1u << 11),                         "12"                            },
2403   { (1u << 12),                         "13"                            },
2404   { (1u << 13),                         "14"                            },
2405   { (1u << 14),                         "15"                            },
2406   { (1u << 15),                         "16"                            },
2407   { (1u << 16),                         "17"                            },
2408   { (1u << 17),                         "18"                            },
2409   { (1u << 18),                         "19"                            },
2410   { (1u << 19),                         "20"                            },
2411   { (1u << 20),                         "21"                            },
2412   { (1u << 21),                         "22"                            },
2413   { (1u << 22),                         "23"                            },
2414   { (1u << 23),                         "24"                            },
2415   { (1u << 24),                         "25"                            },
2416   { (1u << 25),                         "26"                            },
2417   { (1u << 26),                         "27"                            },
2418   { (1u << 27),                         "28"                            },
2419   { (1u << 28),                         "29"                            },
2420   { (1u << 29),                         "30"                            },
2421   { (1u << 30),                         "31"                            },
2422   { (1u << 31),                         "32"                            },
2423   { CH_PAGE_ANY,                        "any"                           },
2424
2425   { -1,                                 NULL                            }
2426 };
2427
2428 static struct ValueTextInfo options_change_replace_when[] =
2429 {
2430   { CP_WHEN_EMPTY,                      "empty"                         },
2431   { CP_WHEN_WALKABLE,                   "walkable"                      },
2432   { CP_WHEN_DIGGABLE,                   "diggable"                      },
2433   { CP_WHEN_COLLECTIBLE,                "collectible"                   },
2434   { CP_WHEN_REMOVABLE,                  "removable"                     },
2435   { CP_WHEN_DESTRUCTIBLE,               "destructible"                  },
2436
2437   { -1,                                 NULL                            }
2438 };
2439
2440 static struct ValueTextInfo options_action_type[] =
2441 {
2442   { CA_NO_ACTION,                       "no action"                     },
2443   { CA_UNDEFINED,                       " "                             },
2444   { CA_HEADLINE_LEVEL_ACTIONS,          "[level]"                       },
2445   { CA_RESTART_LEVEL,                   "restart level"                 },
2446   { CA_SHOW_ENVELOPE,                   "show envelope"                 },
2447   { CA_SET_LEVEL_TIME,                  "set time"                      },
2448   { CA_SET_LEVEL_SCORE,                 "set score"                     },
2449   { CA_SET_LEVEL_GEMS,                  "set gems"                      },
2450   { CA_SET_LEVEL_WIND,                  "set wind dir."                 },
2451   { CA_SET_LEVEL_RANDOM_SEED,           "set random seed"               },
2452   { CA_UNDEFINED,                       " "                             },
2453   { CA_HEADLINE_PLAYER_ACTIONS,         "[player]"                      },
2454   { CA_MOVE_PLAYER,                     "move player"                   },
2455   { CA_MOVE_PLAYER_NEW,                 "move player new"               },
2456   { CA_EXIT_PLAYER,                     "exit player"                   },
2457   { CA_KILL_PLAYER,                     "kill player"                   },
2458   { CA_SET_PLAYER_KEYS,                 "set keys"                      },
2459   { CA_SET_PLAYER_SPEED,                "set speed"                     },
2460   { CA_SET_PLAYER_SHIELD,               "set shield"                    },
2461   { CA_SET_PLAYER_GRAVITY,              "set gravity"                   },
2462   { CA_SET_PLAYER_ARTWORK,              "set artwork"                   },
2463   { CA_SET_PLAYER_INVENTORY,            "set inventory"                 },
2464   { CA_UNDEFINED,                       " "                             },
2465   { CA_HEADLINE_CE_ACTIONS,             "[CE]"                          },
2466   { CA_SET_CE_VALUE,                    "set CE value"                  },
2467   { CA_SET_CE_SCORE,                    "set CE score"                  },
2468   { CA_SET_CE_ARTWORK,                  "set CE artwork"                },
2469   { CA_UNDEFINED,                       " "                             },
2470   { CA_HEADLINE_ENGINE_ACTIONS,         "[engine]"                      },
2471   { CA_SET_ENGINE_SCAN_MODE,            "set scan mode"                 },
2472
2473   { -1,                                 NULL                            }
2474 };
2475
2476 static struct ValueTextInfo options_action_mode_none[] =
2477 {
2478   { CA_MODE_UNDEFINED,                  " "                             },
2479
2480   { -1,                                 NULL                            }
2481 };
2482
2483 static struct ValueTextInfo options_action_mode_assign[] =
2484 {
2485   { CA_MODE_SET,                        "="                             },
2486
2487   { -1,                                 NULL                            }
2488 };
2489
2490 static struct ValueTextInfo options_action_mode_add_remove[] =
2491 {
2492   { CA_MODE_ADD,                        "+"                             },
2493   { CA_MODE_SUBTRACT,                   "-"                             },
2494
2495   { -1,                                 NULL                            }
2496 };
2497
2498 static struct ValueTextInfo options_action_mode_calculate[] =
2499 {
2500   { CA_MODE_SET,                        "="                             },
2501   { CA_MODE_ADD,                        "+"                             },
2502   { CA_MODE_SUBTRACT,                   "-"                             },
2503   { CA_MODE_MULTIPLY,                   "*"                             },
2504   { CA_MODE_DIVIDE,                     "/"                             },
2505   { CA_MODE_MODULO,                     "%"                             },
2506
2507   { -1,                                 NULL                            }
2508 };
2509
2510 static struct ValueTextInfo options_action_arg_none[] =
2511 {
2512   { CA_ARG_UNDEFINED,                   "         "                     },
2513
2514   { -1,                                 NULL                            }
2515 };
2516
2517 static struct ValueTextInfo options_action_arg_player[] =
2518 {
2519   { CA_ARG_PLAYER_HEADLINE,             "[player]"                      },
2520   { CA_ARG_PLAYER_1,                    "1"                             },
2521   { CA_ARG_PLAYER_2,                    "2"                             },
2522   { CA_ARG_PLAYER_3,                    "3"                             },
2523   { CA_ARG_PLAYER_4,                    "4"                             },
2524   { CA_ARG_PLAYER_ANY,                  "any"                           },
2525   { CA_ARG_PLAYER_TRIGGER,              "trigger"                       },
2526   { CA_ARG_PLAYER_ACTION,               "action ->"                     },
2527
2528   { -1,                                 NULL                            }
2529 };
2530
2531 static struct ValueTextInfo options_action_arg_number[] =
2532 {
2533   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2534   { CA_ARG_0,                           "0"                             },
2535   { CA_ARG_1,                           "1"                             },
2536   { CA_ARG_2,                           "2"                             },
2537   { CA_ARG_3,                           "3"                             },
2538   { CA_ARG_4,                           "4"                             },
2539   { CA_ARG_5,                           "5"                             },
2540   { CA_ARG_10,                          "10"                            },
2541   { CA_ARG_100,                         "100"                           },
2542   { CA_ARG_1000,                        "1000"                          },
2543   { CA_ARG_UNDEFINED,                   " "                             },
2544   { CA_ARG_NUMBER_MIN,                  "min"                           },
2545   { CA_ARG_NUMBER_MAX,                  "max"                           },
2546   { CA_ARG_UNDEFINED,                   " "                             },
2547   { CA_ARG_NUMBER_RESET,                "reset"                         },
2548   { CA_ARG_UNDEFINED,                   " "                             },
2549   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2550   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2551   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2552   { CA_ARG_UNDEFINED,                   " "                             },
2553   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2554   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2555   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2556   { CA_ARG_UNDEFINED,                   " "                             },
2557   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2558   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2559   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2560   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2561   { CA_ARG_UNDEFINED,                   " "                             },
2562   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2563   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2564   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2565   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2566
2567   { -1,                                 NULL                            }
2568 };
2569
2570 static struct ValueTextInfo options_action_arg_value[] =
2571 {
2572   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2573   { CA_ARG_0,                           "0"                             },
2574   { CA_ARG_1,                           "1"                             },
2575   { CA_ARG_2,                           "2"                             },
2576   { CA_ARG_3,                           "3"                             },
2577   { CA_ARG_4,                           "4"                             },
2578   { CA_ARG_5,                           "5"                             },
2579   { CA_ARG_10,                          "10"                            },
2580   { CA_ARG_100,                         "100"                           },
2581   { CA_ARG_1000,                        "1000"                          },
2582   { CA_ARG_UNDEFINED,                   " "                             },
2583   { CA_ARG_NUMBER_MIN,                  "min"                           },
2584   { CA_ARG_NUMBER_MAX,                  "max"                           },
2585   { CA_ARG_UNDEFINED,                   " "                             },
2586   { CA_ARG_NUMBER_RESET,                "reset"                         },
2587   { CA_ARG_UNDEFINED,                   " "                             },
2588   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2589   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2590   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2591   { CA_ARG_UNDEFINED,                   " "                             },
2592   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2593   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2594   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2595   { CA_ARG_UNDEFINED,                   " "                             },
2596   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2597   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2598   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2599   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2600   { CA_ARG_UNDEFINED,                   " "                             },
2601   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2602   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2603   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2604   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2605   { CA_ARG_UNDEFINED,                   " "                             },
2606   { CA_ARG_ELEMENT_NR_HEADLINE,         "[element]"                     },
2607   { CA_ARG_ELEMENT_NR_TARGET,           "target"                        },
2608   { CA_ARG_ELEMENT_NR_TRIGGER,          "trigger"                       },
2609   { CA_ARG_ELEMENT_NR_ACTION,           "action ->"                     },
2610
2611   { -1,                                 NULL                            }
2612 };
2613
2614 static struct ValueTextInfo options_action_arg_envelope[] =
2615 {
2616   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2617   { CA_ARG_1,                           "1"                             },
2618   { CA_ARG_2,                           "2"                             },
2619   { CA_ARG_3,                           "3"                             },
2620   { CA_ARG_4,                           "4"                             },
2621   { CA_ARG_UNDEFINED,                   " "                             },
2622   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2623   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2624   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2625   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2626
2627   { -1,                                 NULL                            }
2628 };
2629
2630 static struct ValueTextInfo options_action_arg_key[] =
2631 {
2632   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2633   { CA_ARG_1,                           "1"                             },
2634   { CA_ARG_2,                           "2"                             },
2635   { CA_ARG_3,                           "3"                             },
2636   { CA_ARG_4,                           "4"                             },
2637   { CA_ARG_5,                           "5"                             },
2638   { CA_ARG_6,                           "6"                             },
2639   { CA_ARG_7,                           "7"                             },
2640   { CA_ARG_8,                           "8"                             },
2641   { CA_ARG_UNDEFINED,                   " "                             },
2642   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2643   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2644   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2645   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2646
2647   { -1,                                 NULL                            }
2648 };
2649
2650 static struct ValueTextInfo options_action_arg_speed[] =
2651 {
2652   { CA_ARG_SPEED_HEADLINE,              "[speed]"                       },
2653   { CA_ARG_SPEED_NOT_MOVING,            "frozen"                        },
2654   { CA_ARG_SPEED_VERY_SLOW,             "very slow"                     },
2655   { CA_ARG_SPEED_SLOW,                  "slow"                          },
2656   { CA_ARG_SPEED_NORMAL,                "normal"                        },
2657   { CA_ARG_SPEED_FAST,                  "fast"                          },
2658   { CA_ARG_SPEED_VERY_FAST,             "very fast"                     },
2659   { CA_ARG_SPEED_EVEN_FASTER,           "ultrafast"                     },
2660   { CA_ARG_UNDEFINED,                   " "                             },
2661   { CA_ARG_SPEED_SLOWER,                "slower"                        },
2662   { CA_ARG_SPEED_FASTER,                "faster"                        },
2663   { CA_ARG_UNDEFINED,                   " "                             },
2664   { CA_ARG_SPEED_RESET,                 "reset"                         },
2665
2666   { -1,                                 NULL                            }
2667 };
2668
2669 static struct ValueTextInfo options_action_arg_shield[] =
2670 {
2671   { CA_ARG_SHIELD_HEADLINE,             "[shield]"                      },
2672   { CA_ARG_SHIELD_OFF,                  "off"                           },
2673   { CA_ARG_SHIELD_NORMAL,               "normal"                        },
2674   { CA_ARG_SHIELD_DEADLY,               "deadly"                        },
2675
2676   { -1,                                 NULL                            }
2677 };
2678
2679 static struct ValueTextInfo options_action_arg_artwork[] =
2680 {
2681   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2682   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2683   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2684   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2685   { CA_ARG_UNDEFINED,                   " "                             },
2686   { CA_ARG_ELEMENT_RESET,               "reset"                         },
2687
2688   { -1,                                 NULL                            }
2689 };
2690
2691 static struct ValueTextInfo options_action_arg_gravity[] =
2692 {
2693   { CA_ARG_GRAVITY_HEADLINE,            "[gravity]"                     },
2694   { CA_ARG_GRAVITY_ON,                  "on"                            },
2695   { CA_ARG_GRAVITY_OFF,                 "off"                           },
2696   { CA_ARG_GRAVITY_TOGGLE,              "toggle"                        },
2697
2698   { -1,                                 NULL                            }
2699 };
2700
2701 static struct ValueTextInfo options_action_arg_direction[] =
2702 {
2703   { CA_ARG_DIRECTION_HEADLINE,          "[dir.]"                        },
2704   { CA_ARG_DIRECTION_NONE,              "none"                          },
2705   { CA_ARG_DIRECTION_LEFT,              "left"                          },
2706   { CA_ARG_DIRECTION_RIGHT,             "right"                         },
2707   { CA_ARG_DIRECTION_UP,                "up"                            },
2708   { CA_ARG_DIRECTION_DOWN,              "down"                          },
2709   { CA_ARG_DIRECTION_TRIGGER,           "trigger"                       },
2710   { CA_ARG_DIRECTION_TRIGGER_BACK,      "-trigger"                      },
2711
2712   { -1,                                 NULL                            }
2713 };
2714
2715 static struct ValueTextInfo options_action_arg_scan_mode[] =
2716 {
2717   { CA_ARG_SCAN_MODE_HEADLINE,          "[mode]"                        },
2718   { CA_ARG_SCAN_MODE_NORMAL,            "normal"                        },
2719   { CA_ARG_SCAN_MODE_REVERSE,           "reverse"                       },
2720
2721   { -1,                                 NULL                            }
2722 };
2723
2724 static struct ValueTextInfo options_action_arg_inventory[] =
2725 {
2726   { CA_ARG_INVENTORY_HEADLINE,          "[add]"                         },
2727   { CA_ARG_ELEMENT_TARGET,              "+ target"                      },
2728   { CA_ARG_ELEMENT_TRIGGER,             "+ trigger"                     },
2729   { CA_ARG_ELEMENT_ACTION,              "+ action"                      },
2730   { CA_ARG_UNDEFINED,                   " "                             },
2731   { CA_ARG_INVENTORY_RM_HEADLINE,       "[remove]"                      },
2732   { CA_ARG_INVENTORY_RM_TARGET,         "- target"                      },
2733   { CA_ARG_INVENTORY_RM_TRIGGER,        "- trigger"                     },
2734   { CA_ARG_INVENTORY_RM_ACTION,         "- action"                      },
2735   { CA_ARG_INVENTORY_RM_FIRST,          "- first"                       },
2736   { CA_ARG_INVENTORY_RM_LAST,           "- last"                        },
2737   { CA_ARG_INVENTORY_RM_ALL,            "- all"                         },
2738   { CA_ARG_UNDEFINED,                   " "                             },
2739   { CA_ARG_INVENTORY_RESET,             "reset"                         },
2740
2741   { -1,                                 NULL                            }
2742 };
2743
2744 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2745 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2746 {
2747   { -1,                                 NULL                            }
2748 };
2749
2750 static struct ValueTextInfo options_group_choice_mode[] =
2751 {
2752   { ANIM_RANDOM,                        "random"                        },
2753   { ANIM_LOOP,                          "loop"                          },
2754   { ANIM_LINEAR,                        "linear"                        },
2755   { ANIM_PINGPONG,                      "pingpong"                      },
2756   { ANIM_PINGPONG2,                     "pingpong 2"                    },
2757   { ANIM_LEVEL_NR,                      "level number"                  },
2758
2759   { -1,                                 NULL                            }
2760 };
2761
2762 static struct ValueTextInfo options_bd_scheduling_type[] =
2763 {
2764   { GD_SCHEDULING_MILLISECONDS,         "Milliseconds"                  },
2765   { GD_SCHEDULING_BD1,                  "BD1"                           },
2766   { GD_SCHEDULING_BD2,                  "BD2"                           },
2767   { GD_SCHEDULING_PLCK,                 "Construction Kit"              },
2768   { GD_SCHEDULING_CRDR,                 "Crazy Dream 7"                 },
2769   { GD_SCHEDULING_BD1_ATARI,            "Atari BD1"                     },
2770   { GD_SCHEDULING_BD2_PLCK_ATARI,       "Atari BD2 / PLCK"              },
2771
2772   { -1,                                   NULL                          }
2773 };
2774
2775 static struct ValueTextInfo *action_arg_modes[] =
2776 {
2777   options_action_mode_none,
2778   options_action_mode_assign,
2779   options_action_mode_add_remove,
2780   options_action_mode_calculate,
2781 };
2782
2783 static struct
2784 {
2785   int value;
2786   int mode;
2787   struct ValueTextInfo *options;
2788 }
2789 action_arg_options[] =
2790 {
2791   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2792   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2793   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2794   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2795   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2796   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2797   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2798   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2799   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2800   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2801   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2802   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2803   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2804   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2805   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2806   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2807   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2808   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2809   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2810   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2811   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2812   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2813
2814   { -1,                         FALSE,  NULL                            }
2815 };
2816
2817 static struct
2818 {
2819   int gadget_type_id;
2820   int x, y;
2821   int gadget_id;
2822   int gadget_id_align;
2823   int size;     // char size of selectbox or '-1' (dynamically determined)
2824   struct ValueTextInfo *options;
2825   int *value;
2826   char *text_above, *text_left, *text_right, *infotext;
2827 } selectbox_info[ED_NUM_SELECTBOX] =
2828 {
2829   // ---------- level and editor settings -------------------------------------
2830
2831   {
2832     ED_SELECTBOX_ID_TIME_OR_STEPS,
2833     -1,                                         ED_LEVEL_SETTINGS_YPOS(8),
2834     GADGET_ID_TIME_OR_STEPS,                    GADGET_ID_LEVEL_TIMELIMIT_UP,
2835     -1,
2836     options_time_or_steps,
2837     &level.use_step_counter,
2838     NULL, NULL, "(0 => no limit)",              "Select time or step limit"
2839   },
2840   {
2841     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2842     -1,                                         ED_LEVEL_SETTINGS_YPOS(10),
2843     GADGET_ID_TIME_SCORE_BASE,                  GADGET_ID_LEVEL_TIMESCORE_UP,
2844     -1,
2845     options_time_score_base,
2846     &level.time_score_base,
2847     NULL, NULL, NULL,                           "Select time score for 1 or 10 seconds/steps"
2848   },
2849   {
2850     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2851     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(12),
2852     GADGET_ID_GAME_ENGINE_TYPE,                 GADGET_ID_NONE,
2853     -1,
2854     options_game_engine_type,
2855     &level.game_engine_type,
2856     NULL, "Game engine:", NULL,                 "Select game engine"
2857   },
2858   {
2859     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2860     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
2861     GADGET_ID_BD_SCHEDULING_TYPE,               GADGET_ID_NONE,
2862     -1,
2863     options_bd_scheduling_type,
2864     &level.bd_scheduling_type,
2865     NULL, "Scheduling type:", NULL,             "Select level timing"
2866   },
2867   {
2868     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2869     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
2870     GADGET_ID_LEVELSET_SAVE_MODE,               GADGET_ID_NONE,
2871     -1,
2872     options_levelset_save_mode,
2873     &levelset_save_mode,
2874     "Action:", NULL, NULL,                      "Select action when saving level set"
2875   },
2876
2877   // ---------- element settings: configure (several elements) ----------------
2878
2879   {
2880     ED_SELECTBOX_ID_WIND_DIRECTION,
2881     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2882     GADGET_ID_WIND_DIRECTION,                   GADGET_ID_NONE,
2883     -1,
2884     options_wind_direction,
2885     &level.wind_direction_initial,
2886     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2887   },
2888   {
2889     ED_SELECTBOX_ID_PLAYER_SPEED,
2890     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(7),
2891     GADGET_ID_PLAYER_SPEED,                     GADGET_ID_NONE,
2892     -1,
2893     options_player_speed,
2894     &level.initial_player_stepsize[0],
2895     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2896   },
2897   {
2898     ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
2899     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2900     GADGET_ID_BD_GRAVITY_DIRECTION,             GADGET_ID_NONE,
2901     -1,
2902     options_bd_gravity_direction,
2903     &level.bd_gravity_direction,
2904     NULL, "Gravity direction:", NULL,           "Select initial gravity direction"
2905   },
2906   {
2907     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2908     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
2909     GADGET_ID_MM_BALL_CHOICE_MODE,              GADGET_ID_NONE,
2910     -1,
2911     options_group_choice_mode,
2912     &level.mm_ball_choice_mode,
2913     NULL, "Choice type:", NULL,                 "Select type of content choice"
2914   },
2915
2916   // ---------- element settings: configure 1 (custom elements) ---------------
2917
2918   {
2919     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2920     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2921     GADGET_ID_CUSTOM_ACCESS_TYPE,               GADGET_ID_NONE,
2922     -1,
2923     options_access_type,
2924     &custom_element.access_type,
2925     NULL, NULL, NULL,                           "Select type of access to this field"
2926   },
2927   {
2928     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2929     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2930     GADGET_ID_CUSTOM_ACCESS_LAYER,              GADGET_ID_CUSTOM_ACCESS_TYPE,
2931     -1,
2932     options_access_layer,
2933     &custom_element.access_layer,
2934     NULL, NULL, NULL,                           "Select layer of access for this field"
2935   },
2936   {
2937     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2938     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2939     GADGET_ID_CUSTOM_ACCESS_PROTECTED,          GADGET_ID_CUSTOM_ACCESS_LAYER,
2940     -1,
2941     options_access_protected,
2942     &custom_element.access_protected,
2943     NULL, NULL, NULL,                           "Select protected access for this field"
2944   },
2945   {
2946     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2947     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2948     GADGET_ID_CUSTOM_ACCESS_DIRECTION,          GADGET_ID_NONE,
2949     -1,
2950     options_access_direction,
2951     &custom_element.access_direction,
2952     NULL, "from", NULL,                         "Select access direction for this field"
2953   },
2954   {
2955     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2956     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2957     GADGET_ID_CUSTOM_WALK_TO_ACTION,            GADGET_ID_NONE,
2958     -1,
2959     options_walk_to_action,
2960     &custom_element.walk_to_action,
2961     NULL, NULL, NULL,                           "Select diggable/collectible/pushable"
2962   },
2963
2964   // ---------- element settings: configure 2 (custom elements) ---------------
2965
2966   {
2967     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2968     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(1),
2969     GADGET_ID_CUSTOM_MOVE_PATTERN,              GADGET_ID_NONE,
2970     -1,
2971     options_move_pattern,
2972     &custom_element.move_pattern,
2973     NULL, "Can move", NULL,                     "Select element move pattern"
2974   },
2975   {
2976     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2977     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2978     GADGET_ID_CUSTOM_MOVE_DIRECTION,            GADGET_ID_NONE,
2979     -1,
2980     options_move_direction,
2981     &custom_element.move_direction_initial,
2982     NULL, "Starts moving", NULL,                "Select initial element move direction"
2983   },
2984   {
2985     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2986     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2987     GADGET_ID_CUSTOM_MOVE_STEPSIZE,             GADGET_ID_NONE,
2988     -1,
2989     options_move_stepsize,
2990     &custom_element.move_stepsize,
2991     NULL, "Move/fall speed", NULL,              "Select speed of element movement"
2992   },
2993   {
2994     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2995     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2996     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,           GADGET_ID_NONE,
2997     -1,
2998     options_move_leave_type,
2999     &custom_element.move_leave_type,
3000     // left text with leading spaces to place gadget next to "can dig" gadget
3001     // (needed because drawing area gadgets created after selectbox gadgets)
3002     // NULL, "can dig:    can", ":",            "leave behind or change element"
3003     NULL, "            Can", ":",               "Select leave behind or change element"
3004   },
3005   {
3006     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
3007     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
3008     GADGET_ID_CUSTOM_SMASH_TARGETS,             GADGET_ID_CUSTOM_CAN_SMASH,
3009     -1,
3010     options_smash_targets,
3011     &custom_element.smash_targets,
3012     NULL, "Can smash", NULL,                    "Select elements that can be smashed"
3013   },
3014   {
3015     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
3016     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
3017     GADGET_ID_CUSTOM_SLIPPERY_TYPE,             GADGET_ID_NONE,
3018     -1,
3019     options_slippery_type,
3020     &custom_element.slippery_type,
3021     NULL, "Slippery", NULL,                     "Select where other elements fall down"
3022   },
3023   {
3024     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
3025     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(10),
3026     GADGET_ID_CUSTOM_DEADLINESS,                GADGET_ID_NONE,
3027     -1,
3028     options_deadliness,
3029     &custom_element.deadliness,
3030     NULL, "Deadly when", NULL,                  "Select deadliness of element"
3031   },
3032   {
3033     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
3034     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(11),
3035     GADGET_ID_CUSTOM_EXPLOSION_TYPE,            GADGET_ID_NONE,
3036     -1,
3037     options_explosion_type,
3038     &custom_element.explosion_type,
3039     NULL, "Can explode", NULL,                  "Select explosion type"
3040   },
3041
3042   // ---------- element settings: advanced (custom elements) ------------------
3043
3044   {
3045     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
3046     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(3),
3047     GADGET_ID_CHANGE_TIME_UNITS,                GADGET_ID_NONE,
3048     -1,
3049     options_time_units,
3050     &custom_element_change.delay_frames,
3051     NULL, "Delay time given in", NULL,          "Select delay time units for change"
3052   },
3053   {
3054     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
3055     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(4),
3056     GADGET_ID_CHANGE_DIRECT_ACTION,             GADGET_ID_NONE,
3057     -1,
3058     options_change_direct_action,
3059     &custom_element_change.direct_action,
3060     NULL, NULL, NULL,                           "Select type of direct action"
3061   },
3062   {
3063     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3064     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(5),
3065     GADGET_ID_CHANGE_OTHER_ACTION,              GADGET_ID_NONE,
3066     -1,
3067     options_change_other_action,
3068     &custom_element_change.other_action,
3069     NULL, NULL, "element:",                     "Select type of other element action"
3070   },
3071   {
3072     ED_SELECTBOX_ID_CHANGE_SIDE,
3073     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(6),
3074     GADGET_ID_CHANGE_SIDE,                      GADGET_ID_NONE,
3075     -1,
3076     options_change_trigger_side,
3077     &custom_element_change.trigger_side,
3078     NULL, "at", "side",                         "Select element side triggering change"
3079   },
3080   {
3081     ED_SELECTBOX_ID_CHANGE_PLAYER,
3082     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3083     GADGET_ID_CHANGE_PLAYER,                    GADGET_ID_NONE,
3084     -1,
3085     options_change_trigger_player,
3086     &custom_element_change.trigger_player,
3087     NULL, "Player:", " ",                       "Select player that causes change"
3088   },
3089   {
3090     ED_SELECTBOX_ID_CHANGE_PAGE,
3091     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3092     GADGET_ID_CHANGE_PAGE,                      GADGET_ID_CHANGE_PLAYER,
3093     -1,
3094     options_change_trigger_page,
3095     &custom_element_change.trigger_page,
3096     NULL, "Page:", NULL,                        "Select change page that causes change"
3097   },
3098   {
3099     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3100     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(10),
3101     GADGET_ID_CHANGE_REPLACE_WHEN,              GADGET_ID_NONE,
3102     -1,
3103     options_change_replace_when,
3104     &custom_element_change.replace_when,
3105     NULL, "Replace when", NULL,                 "Select which elements can be replaced"
3106   },
3107   {
3108     ED_SELECTBOX_ID_ACTION_TYPE,
3109     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
3110     GADGET_ID_ACTION_TYPE,                      GADGET_ID_NONE,
3111     15,
3112     options_action_type,
3113     &custom_element_change.action_type,
3114     NULL, NULL, NULL,                           "Select action on specified condition"
3115   },
3116   {
3117     ED_SELECTBOX_ID_ACTION_MODE,
3118     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3119     GADGET_ID_ACTION_MODE,                      GADGET_ID_ACTION_TYPE,
3120     -1,
3121     options_action_mode_none,
3122     &custom_element_change.action_mode,
3123     NULL, NULL, NULL,                           "Select action operator"
3124   },
3125   {
3126     ED_SELECTBOX_ID_ACTION_ARG,
3127     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3128     GADGET_ID_ACTION_ARG,                       GADGET_ID_ACTION_MODE,
3129     -1,
3130     options_action_arg_none,
3131     &custom_element_change.action_arg,
3132     NULL, NULL, NULL,                           "Select action parameter"
3133   },
3134   {
3135     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3136     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
3137     GADGET_ID_SELECT_CHANGE_PAGE,               GADGET_ID_NONE,
3138     3,
3139     options_change_page,
3140     &custom_element.current_change_page,
3141     NULL, NULL, NULL,                           "Select element change page"
3142   },
3143
3144   // ---------- element settings: configure (group elements) ------------------
3145
3146   {
3147     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3148     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3149     GADGET_ID_GROUP_CHOICE_MODE,                GADGET_ID_NONE,
3150     -1,
3151     options_group_choice_mode,
3152     &group_element_info.choice_mode,
3153     NULL, "Choice type:", NULL,                 "Select type of group element choice"
3154   },
3155 };
3156
3157 static struct
3158 {
3159   int gadget_type_id;
3160   int x, y;
3161   int gadget_id;
3162   int gadget_id_align;
3163   int size;
3164   char *text;
3165   char *text_above, *text_left, *text_right, *infotext;
3166 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3167 {
3168   // ---------- level and editor settings (tabs) ------------------------------
3169
3170   {
3171     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3172     ED_LEVEL_TABS_XPOS(0),                      ED_LEVEL_TABS_YPOS(0),
3173     GADGET_ID_LEVELCONFIG_LEVEL,                GADGET_ID_NONE,
3174     8,                                          "Level",
3175     NULL, NULL, NULL,                           "Configure level settings"
3176   },
3177   {
3178     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3179     -1,                                         -1,
3180     GADGET_ID_LEVELCONFIG_LEVELSET,             GADGET_ID_LEVELCONFIG_LEVEL,
3181     8,                                          "Levelset",
3182     NULL, NULL, NULL,                           "Update this or create new level set"
3183   },
3184   {
3185     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3186     -1,                                         -1,
3187     GADGET_ID_LEVELCONFIG_EDITOR,               GADGET_ID_LEVELCONFIG_LEVELSET,
3188     8,                                          "Editor",
3189     NULL, NULL, NULL,                           "Configure editor settings"
3190   },
3191   {
3192     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3193     -1,                                         -1,
3194     GADGET_ID_LEVELCONFIG_ENGINE,               GADGET_ID_LEVELCONFIG_EDITOR,
3195     8,                                          "Engine",
3196     NULL, NULL, NULL,                           "Configure engine settings"
3197   },
3198
3199   // ---------- element settings (tabs) ---------------------------------------
3200
3201   {
3202     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3203     ED_ELEMENT_TABS_XPOS(0),                    ED_ELEMENT_TABS_YPOS(0),
3204     GADGET_ID_PROPERTIES_INFO,                  GADGET_ID_NONE,
3205     8,                                          "Info",
3206     NULL, NULL, NULL,                           "Show information about element"
3207   },
3208   {
3209     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3210     -1,                                         -1,
3211     GADGET_ID_PROPERTIES_CONFIG,                GADGET_ID_PROPERTIES_INFO,
3212     8,                                          "Config",
3213     NULL, NULL, NULL,                           "Configure element properties"
3214   },
3215   {
3216     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3217     -1,                                         -1,
3218     GADGET_ID_PROPERTIES_CONFIG_1,              GADGET_ID_PROPERTIES_INFO,
3219     8,                                          "Config 1",
3220     NULL, NULL, NULL,                           "Configure element properties, part 1"
3221   },
3222   {
3223     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3224     -1,                                         -1,
3225     GADGET_ID_PROPERTIES_CONFIG_2,              GADGET_ID_PROPERTIES_CONFIG_1,
3226     8,                                          "Config 2",
3227     NULL, NULL, NULL,                           "Configure element properties, part 2"
3228   },
3229   {
3230     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3231     -1,                                         -1,
3232     GADGET_ID_PROPERTIES_CHANGE,                GADGET_ID_PROPERTIES_CONFIG_2,
3233     8,                                          "Change",
3234     NULL, NULL, NULL,                           "Configure custom element change pages"
3235   },
3236
3237   // ---------- level and editor settings (buttons) ---------------------------
3238
3239   {
3240     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3241     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
3242     GADGET_ID_SAVE_LEVELSET,                    GADGET_ID_LEVELSET_SAVE_MODE,
3243     -1,                                         "Save",
3244     NULL, NULL, NULL,                           "Update or create level set"
3245   },
3246   {
3247     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3248     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3249     GADGET_ID_SAVE_AS_TEMPLATE_2,               GADGET_ID_NONE,
3250     -1,                                         "Save",
3251     NULL, NULL,                                 "this level as level template",
3252     "Save current settings as new template"
3253   },
3254
3255   // ---------- element settings (buttons) ------------------------------------
3256
3257   {
3258     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3259     -1,                                         -1,
3260     GADGET_ID_SAVE_AS_TEMPLATE_1,               GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3261     -1,                                         "Save",
3262     NULL, " ",                                  "As Template",
3263     "Save current settings as new template"
3264   },
3265   {
3266     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3267     -1,                                         -1,
3268     GADGET_ID_ADD_CHANGE_PAGE,                  GADGET_ID_PASTE_CHANGE_PAGE,
3269     -1,                                         "New",
3270     NULL, NULL, NULL,                           "Add new change page"
3271   },
3272   {
3273     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3274     -1,                                         -1,
3275     GADGET_ID_DEL_CHANGE_PAGE,                  GADGET_ID_ADD_CHANGE_PAGE,
3276     -1,                                         "Delete",
3277     NULL, NULL, NULL,                           "Delete current change page"
3278   },
3279 };
3280
3281 static struct
3282 {
3283   int gadget_type_id;
3284   int graphic;
3285   int x, y;
3286   int gadget_id;
3287   int gadget_id_align;
3288   char *text_left, *text_right, *infotext;
3289 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3290 {
3291   {
3292     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3293     IMG_EDITOR_COUNTER_DOWN,
3294     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3295     GADGET_ID_PREV_CHANGE_PAGE,                 GADGET_ID_NONE,
3296     NULL, NULL,                                 "Select previous change page"
3297   },
3298   {
3299     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3300     IMG_EDITOR_COUNTER_UP,
3301     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3302     GADGET_ID_NEXT_CHANGE_PAGE,                 GADGET_ID_SELECT_CHANGE_PAGE,
3303     NULL, "Change page",                        "Select next change page"
3304   },
3305   {
3306     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3307     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3308     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3309     GADGET_ID_COPY_CHANGE_PAGE,                 GADGET_ID_NEXT_CHANGE_PAGE,
3310     " ", NULL,                                  "Copy settings from this change page"
3311   },
3312   {
3313     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3314     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3315     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3316     GADGET_ID_PASTE_CHANGE_PAGE,                GADGET_ID_COPY_CHANGE_PAGE,
3317     NULL, NULL,                                 "Paste settings to this change page"
3318   },
3319 };
3320
3321 static struct
3322 {
3323   int x, y;
3324 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3325
3326 static struct
3327 {
3328   int gadget_type_id;
3329   int graphic;
3330   int gadget_id;
3331   char *infotext;
3332 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3333 {
3334   {
3335     ED_SCROLLBUTTON_ID_AREA_UP,
3336     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3337     GADGET_ID_SCROLL_UP,
3338     "Scroll level editing area up"
3339   },
3340   {
3341     ED_SCROLLBUTTON_ID_AREA_DOWN,
3342     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3343     GADGET_ID_SCROLL_DOWN,
3344     "Scroll level editing area down"
3345   },
3346   {
3347     ED_SCROLLBUTTON_ID_AREA_LEFT,
3348     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3349     GADGET_ID_SCROLL_LEFT,
3350     "Scroll level editing area left"
3351   },
3352   {
3353     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3354     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3355     GADGET_ID_SCROLL_RIGHT,
3356     "Scroll level editing area right"
3357   },
3358   {
3359     ED_SCROLLBUTTON_ID_LIST_UP,
3360     IMG_EDITOR_PALETTE_SCROLL_UP,
3361     GADGET_ID_SCROLL_LIST_UP,
3362     "Scroll element list up ('Page Up')"
3363   },
3364   {
3365     ED_SCROLLBUTTON_ID_LIST_DOWN,
3366     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3367     GADGET_ID_SCROLL_LIST_DOWN,
3368     "Scroll element list down ('Page Down')"
3369   },
3370 };
3371
3372 static struct
3373 {
3374   int x, y;
3375   int width, height;
3376   int wheel_x, wheel_y;
3377   int wheel_width, wheel_height;
3378 } scrollbar_pos[ED_NUM_SCROLLBARS];
3379
3380 static struct
3381 {
3382   int gadget_type_id;
3383   int graphic;
3384   int type;
3385   int gadget_id;
3386   char *infotext;
3387 } scrollbar_info[ED_NUM_SCROLLBARS] =
3388 {
3389   {
3390     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3391     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3392     GD_TYPE_SCROLLBAR_HORIZONTAL,
3393     GADGET_ID_SCROLL_HORIZONTAL,
3394     "Scroll level editing area horizontally"
3395   },
3396   {
3397     ED_SCROLLBAR_ID_AREA_VERTICAL,
3398     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3399     GD_TYPE_SCROLLBAR_VERTICAL,
3400     GADGET_ID_SCROLL_VERTICAL,
3401     "Scroll level editing area vertically"
3402   },
3403   {
3404     ED_SCROLLBAR_ID_LIST_VERTICAL,
3405     IMG_EDITOR_PALETTE_SCROLLBAR,
3406     GD_TYPE_SCROLLBAR_VERTICAL,
3407     GADGET_ID_SCROLL_LIST_VERTICAL,
3408     "Scroll element list vertically"
3409   }
3410 };
3411
3412
3413 static struct
3414 {
3415   int gadget_type_id;
3416   int x, y;
3417   int gadget_id;
3418   int gadget_id_align;
3419   int radio_button_nr;
3420   int *value;
3421   int checked_value;
3422   char *text_left, *text_right, *infotext;
3423 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3424 {
3425   {
3426     ED_RADIOBUTTON_ID_PERCENTAGE,
3427     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3428     GADGET_ID_RANDOM_PERCENTAGE,                GADGET_ID_LEVEL_RANDOM_UP,
3429     RADIO_NR_RANDOM_ELEMENTS,
3430     &random_placement_method,                   RANDOM_USE_PERCENTAGE,
3431     " ", "percentage",                          "Use percentage for random elements"
3432   },
3433   {
3434     ED_RADIOBUTTON_ID_QUANTITY,
3435     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3436     GADGET_ID_RANDOM_QUANTITY,                  GADGET_ID_RANDOM_PERCENTAGE,
3437     RADIO_NR_RANDOM_ELEMENTS,
3438     &random_placement_method,                   RANDOM_USE_QUANTITY,
3439     " ", "quantity",                            "Use quantity for random elements"
3440   }
3441 };
3442
3443 static struct
3444 {
3445   int gadget_type_id;
3446   int x, y;
3447   int gadget_id;
3448   int gadget_id_align;
3449   boolean *value;
3450   char *text_above, *text_left, *text_right, *infotext;
3451 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3452 {
3453   // ---------- level and editor settings -------------------------------------
3454
3455   {
3456     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3457     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3458     GADGET_ID_AUTO_COUNT_GEMS,                  GADGET_ID_NONE,
3459     &level.auto_count_gems,
3460     NULL, NULL,
3461     "Automatically count gems needed",          "Set counter to number of gems"
3462   },
3463   {
3464     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3465     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(11),
3466     GADGET_ID_RATE_TIME_OVER_SCORE,             GADGET_ID_NONE,
3467     &level.rate_time_over_score,
3468     NULL, NULL,
3469     "Rate time/steps used over score",          "Sort high scores by playing time/steps"
3470   },
3471   {
3472     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3473     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3474     GADGET_ID_USE_LEVELSET_ARTWORK,             GADGET_ID_NONE,
3475     &levelset_use_levelset_artwork,
3476     NULL, NULL,
3477     "Use current custom artwork",               "Use custom artwork of this level set"
3478   },
3479   {
3480     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3481     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3482     GADGET_ID_COPY_LEVEL_TEMPLATE,              GADGET_ID_NONE,
3483     &levelset_copy_level_template,
3484     NULL, NULL,
3485     "Copy current level template",              "Copy level template of this level set"
3486   },
3487   {
3488     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3489     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
3490     GADGET_ID_RANDOM_RESTRICTED,                GADGET_ID_NONE,
3491     &random_placement_background_restricted,
3492     NULL, NULL,
3493     "Restrict random placement to:",            "Set random placement restriction"
3494   },
3495   {
3496     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3497     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
3498     GADGET_ID_CUSTOM_USE_TEMPLATE_3,            GADGET_ID_NONE,
3499     &setup.editor.use_template_for_new_levels,
3500     "Template for new levels and CE/GE:", NULL,
3501     "Use template for new levels",              "Use template for level properties"
3502   },
3503   {
3504     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3505     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
3506     GADGET_ID_CUSTOM_USE_TEMPLATE_2,            GADGET_ID_NONE,
3507     &level.use_custom_template,
3508     NULL, NULL,
3509     "Use template for custom elements",         "Use template for custom properties"
3510   },
3511   {
3512     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3513     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
3514     GADGET_ID_BD_INTERMISSION,                  GADGET_ID_NONE,
3515     &level.bd_intermission,
3516     "Boulder Dash game engine settings:", NULL,
3517     "Intermission",                             "Level is an intermission level"
3518   },
3519   {
3520     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3521     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
3522     GADGET_ID_BD_PAL_TIMING,                    GADGET_ID_NONE,
3523     &level.bd_pal_timing,
3524     NULL, NULL,
3525     "PAL timing",                               "Use slower timer (like PAL C64)"
3526   },
3527   {
3528     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3529     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3530     GADGET_ID_BD_LINE_SHIFTING_BORDERS,         GADGET_ID_NONE,
3531     &level.bd_line_shifting_borders,
3532     "Compatibility settings:", NULL,
3533     "Line-shifting borders",                    "Use line-shifting wrap-around"
3534   },
3535   {
3536     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3537     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3538     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,       GADGET_ID_NONE,
3539     &level.bd_scan_first_and_last_row,
3540     NULL, NULL,
3541     "Scan first and last row",                  "Also process top/bottom border rows"
3542   },
3543   {
3544     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3545     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3546     GADGET_ID_BD_SHORT_EXPLOSIONS,              GADGET_ID_NONE,
3547     &level.bd_short_explosions,
3548     NULL, NULL,
3549     "Short explosions",                         "Use four game cycles for explosions"
3550   },
3551
3552   // ---------- element settings: configure (various elements) ----------------
3553
3554   {
3555     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3556     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3557     GADGET_ID_STICK_ELEMENT,                    GADGET_ID_NONE,
3558     &stick_element_properties_window,
3559     NULL, NULL,
3560     "Stick this screen to edit content",        "Stick this screen to edit content"
3561   },
3562   {
3563     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3564     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3565     GADGET_ID_EM_SLIPPERY_GEMS,                 GADGET_ID_NONE,
3566     &level.em_slippery_gems,
3567     NULL, NULL,
3568     "Slip down from certain flat walls",        "Use EM/DC style slipping behaviour"
3569   },
3570   {
3571     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3572     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3573     GADGET_ID_EM_EXPLODES_BY_FIRE,              GADGET_ID_NONE,
3574     &level.em_explodes_by_fire,
3575     NULL, NULL,
3576     "Explodes with chain reaction",             "Use R'n'D style explosion behaviour"
3577   },
3578   {
3579     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3580     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3581     GADGET_ID_USE_SPRING_BUG,                   GADGET_ID_NONE,
3582     &level.use_spring_bug,
3583     NULL, NULL,
3584     "Use spring pushing bug",                   "Use odd spring pushing behaviour"
3585   },
3586   {
3587     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3588     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3589     GADGET_ID_USE_TIME_ORB_BUG,                 GADGET_ID_NONE,
3590     &level.use_time_orb_bug,
3591     NULL, NULL,
3592     "Use time orb bug",                         "Use odd time orb behaviour"
3593   },
3594   {
3595     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3596     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3597     GADGET_ID_USE_LIFE_BUGS,                    GADGET_ID_NONE,
3598     &level.use_life_bugs,
3599     NULL, NULL,
3600     "Use buggy element behaviour",              "Use odd (historic) element behaviour"
3601   },
3602   {
3603     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3604     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3605     GADGET_ID_RANDOM_BALL_CONTENT,              GADGET_ID_NONE,
3606     &level.ball_random,
3607     NULL, NULL,
3608     "Create single random element",             "Only create one element from content"
3609   },
3610   {
3611     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3612     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3613     GADGET_ID_INITIAL_BALL_ACTIVE,              GADGET_ID_NONE,
3614     &level.ball_active_initial,
3615     NULL, NULL,
3616     "Magic ball initially activated",           "Activate magic ball after level start"
3617   },
3618   {
3619     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3620     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3621     GADGET_ID_GROW_INTO_DIGGABLE,               GADGET_ID_NONE,
3622     &level.grow_into_diggable,
3623     NULL, NULL,
3624     "Can grow into anything diggable",          "Grow into more than just sand"
3625   },
3626   {
3627     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3628     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3629     GADGET_ID_SB_FIELDS_NEEDED,                 GADGET_ID_NONE,
3630     &level.sb_fields_needed,
3631     NULL, NULL,
3632     "All fields need to be filled",             "Require all SB fields to be solved"
3633   },
3634   {
3635     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3636     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3637     GADGET_ID_SB_OBJECTS_NEEDED,                GADGET_ID_NONE,
3638     &level.sb_objects_needed,
3639     NULL, NULL,
3640     "All objects need to be placed",            "Require all SB objects to be solved"
3641   },
3642   {
3643     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3644     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3645     GADGET_ID_AUTO_EXIT_SOKOBAN,                GADGET_ID_NONE,
3646     &level.auto_exit_sokoban,
3647     NULL, NULL,
3648     "Exit level if all tasks solved",           "Automatically finish Sokoban levels"
3649   },
3650   {
3651     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3652     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3653     GADGET_ID_SOLVED_BY_ONE_PLAYER,             GADGET_ID_NONE,
3654     &level.solved_by_one_player,
3655     NULL, NULL,
3656     "Only one player must enter exit",          "Level solved by first player in exit"
3657   },
3658   {
3659     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3660     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3661     GADGET_ID_FINISH_DIG_COLLECT,               GADGET_ID_NONE,
3662     &level.finish_dig_collect,
3663     NULL, NULL,
3664     "CE action on finished dig/collect",        "Only finished dig/collect triggers CE"
3665   },
3666   {
3667     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3668     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3669     GADGET_ID_KEEP_WALKABLE_CE,                 GADGET_ID_NONE,
3670     &level.keep_walkable_ce,
3671     NULL, NULL,
3672     "Keep walkable CE changed to player",       "Keep CE changing to player if walkable"
3673   },
3674   {
3675     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3676     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3677     GADGET_ID_CONTINUOUS_SNAPPING,              GADGET_ID_NONE,
3678     &level.continuous_snapping,
3679     NULL, NULL,
3680     "Continuous snapping",                      "Use snapping without releasing key"
3681   },
3682   {
3683     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3684     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
3685     GADGET_ID_BLOCK_SNAP_FIELD,                 GADGET_ID_NONE,
3686     &level.block_snap_field,
3687     NULL, NULL,
3688     "Block snapped field when snapping",        "Use snapping delay to show animation"
3689   },
3690   {
3691     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3692     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3693     GADGET_ID_BLOCK_LAST_FIELD,                 GADGET_ID_NONE,
3694     &level.block_last_field,
3695     NULL, NULL,
3696     "Block last field when moving",             "Player blocks last field when moving"
3697   },
3698   {
3699     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3700     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3701     GADGET_ID_SP_BLOCK_LAST_FIELD,              GADGET_ID_NONE,
3702     &level.sp_block_last_field,
3703     NULL, NULL,
3704     "Block last field when moving",             "Player blocks last field when moving"
3705   },
3706   {
3707     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3708     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3709     GADGET_ID_INSTANT_RELOCATION,               GADGET_ID_NONE,
3710     &level.instant_relocation,
3711     NULL, NULL,
3712     "No scrolling when relocating",             "Player gets relocated without delay"
3713   },
3714   {
3715     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3716     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3717     GADGET_ID_SHIFTED_RELOCATION,               GADGET_ID_NONE,
3718     &level.shifted_relocation,
3719     NULL, NULL,
3720     "No centering when relocating",             "Level not centered after relocation"
3721   },
3722   {
3723     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3724     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3725     GADGET_ID_LAZY_RELOCATION,                  GADGET_ID_NONE,
3726     &level.lazy_relocation,
3727     NULL, NULL,
3728     "Only redraw off-screen relocation",        "No redraw if relocation target visible"
3729   },
3730   {
3731     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3732     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
3733     GADGET_ID_USE_START_ELEMENT,                GADGET_ID_NONE,
3734     &level.use_start_element[0],
3735     NULL, NULL,
3736     "Use level start element:",                "Start level at this element's position"
3737   },
3738   {
3739     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3740     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
3741     GADGET_ID_USE_ARTWORK_ELEMENT,              GADGET_ID_NONE,
3742     &level.use_artwork_element[0],
3743     NULL, NULL,
3744     "Use artwork from element:",                "Use player artwork from other element"
3745   },
3746   {
3747     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3748     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(12),
3749     GADGET_ID_USE_EXPLOSION_ELEMENT,            GADGET_ID_NONE,
3750     &level.use_explosion_element[0],
3751     NULL, NULL,
3752     "Use explosion from element:",              "Use explosion properties from element"
3753   },
3754   {
3755     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3756     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
3757     GADGET_ID_INITIAL_GRAVITY,                  GADGET_ID_NONE,
3758     &level.initial_player_gravity[0],
3759     NULL, NULL,
3760     "Use initial gravity",                      "Set initial player gravity"
3761   },
3762   {
3763     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3764     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3765     GADGET_ID_USE_INITIAL_INVENTORY,            GADGET_ID_NONE,
3766     &level.use_initial_inventory[0],
3767     NULL, NULL,
3768     "Use initial inventory:",                   "Use collected elements on level start"
3769   },
3770   {
3771     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3772     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
3773     GADGET_ID_CAN_PASS_TO_WALKABLE,             GADGET_ID_NONE,
3774     &level.can_pass_to_walkable,
3775     NULL, NULL,
3776     "Can pass to walkable element",             "Player can pass to empty or walkable"
3777   },
3778   {
3779     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3780     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3781     GADGET_ID_CAN_FALL_INTO_ACID,               GADGET_ID_NONE,
3782     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3783     NULL, NULL,
3784     "Can fall into acid (with gravity)",        "Player can fall into acid pool"
3785   },
3786   {
3787     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3788     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3789     GADGET_ID_CAN_MOVE_INTO_ACID,               GADGET_ID_NONE,
3790     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3791     NULL, NULL,
3792     "Can move into acid",                       "Element can move into acid pool"
3793   },
3794   {
3795     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3796     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3797     GADGET_ID_DONT_COLLIDE_WITH,                GADGET_ID_NONE,
3798     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3799     NULL, NULL,
3800     "Deadly when colliding with",               "Element is deadly when hitting player"
3801   },
3802   {
3803     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3804     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3805     GADGET_ID_BD_DIAGONAL_MOVEMENTS,            GADGET_ID_NONE,
3806     &level.bd_diagonal_movements,
3807     NULL, NULL,
3808     "Can move diagonally",                      "Player can move diagonally"
3809   },
3810   {
3811     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3812     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3813     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,         GADGET_ID_NONE,
3814     &level.bd_topmost_player_active,
3815     NULL, NULL,
3816     "Topmost player is active",                 "Use first player found on playfield"
3817   },
3818   {
3819     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3820     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3821     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,     GADGET_ID_NONE,
3822     &level.bd_push_mega_rock_with_sweet,
3823     NULL, NULL,
3824     "Mega rocks pushable with sweet",           "Push mega rocks after eating sweet"
3825   },
3826   {
3827     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3828     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3829     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,      GADGET_ID_NONE,
3830     &level.bd_magic_wall_wait_hatching,
3831     NULL, NULL,
3832     "Wait for player's birth",                  "Timer start waits for player's birth"
3833   },
3834   {
3835     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3836     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3837     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,       GADGET_ID_NONE,
3838     &level.bd_magic_wall_stops_amoeba,
3839     NULL, NULL,
3840     "Turn amoeba to diamonds",                  "Activation changes amoeba to diamonds"
3841   },
3842   {
3843     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3844     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3845     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,      GADGET_ID_NONE,
3846     &level.bd_amoeba_wait_for_hatching,
3847     NULL, NULL,
3848     "Wait for player's birth",                  "Timer start waits for player's birth"
3849   },
3850   {
3851     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3852     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3853     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,      GADGET_ID_NONE,
3854     &level.bd_amoeba_start_immediately,
3855     NULL, NULL,
3856     "Start growing immediately",                "Start slow growth time immediately"
3857   },
3858   {
3859     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3860     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3861     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,    GADGET_ID_NONE,
3862     &level.bd_amoeba_2_explode_by_amoeba,
3863     NULL, NULL,
3864     "Explodes if touched by amoeba",            "Amoeba 2 explodes if touched by amoeba"
3865   },
3866   {
3867     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3868     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3869     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,      GADGET_ID_NONE,
3870     &level.bd_voodoo_collects_diamonds,
3871     NULL, NULL,
3872     "Can collect diamonds",                     "Can collect diamonds for the player"
3873   },
3874   {
3875     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3876     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3877     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,      GADGET_ID_NONE,
3878     &level.bd_voodoo_hurt_kills_player,
3879     NULL, NULL,
3880     "Player is killed if hurt",                 "If hurt in any way, player is killed"
3881   },
3882   {
3883     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3884     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3885     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,           GADGET_ID_NONE,
3886     &level.bd_voodoo_dies_by_rock,
3887     NULL, NULL,
3888     "Killed by falling rock",                   "Can be killed by a falling rock"
3889   },
3890   {
3891     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3892     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3893     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,    GADGET_ID_NONE,
3894     &level.bd_voodoo_vanish_by_explosion,
3895     NULL, NULL,
3896     "Disappears in explosions",                 "Can be destroyed by explosions"
3897   },
3898   {
3899     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3900     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3901     GADGET_ID_BD_SLIME_IS_PREDICTABLE,          GADGET_ID_NONE,
3902     &level.bd_slime_is_predictable,
3903     NULL, NULL,
3904     "Slime is predictable",                     "Use predictable random numbers"
3905   },
3906   {
3907     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3908     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3909     GADGET_ID_BD_CHANGE_EXPANDING_WALL,         GADGET_ID_NONE,
3910     &level.bd_change_expanding_wall,
3911     NULL, NULL,
3912     "Change direction",                         "Switch horizontal/vertical direction"
3913   },
3914   {
3915     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3916     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3917     GADGET_ID_BD_REPLICATORS_ACTIVE,            GADGET_ID_NONE,
3918     &level.bd_replicators_active,
3919     NULL, NULL,
3920     "Active at start",                          "Replicators start in active state"
3921   },
3922   {
3923     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3924     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3925     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,         GADGET_ID_NONE,
3926     &level.bd_conveyor_belts_active,
3927     NULL, NULL,
3928     "Active at start",                          "Conveyor belts start in active state"
3929   },
3930   {
3931     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3932     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3933     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,        GADGET_ID_NONE,
3934     &level.bd_conveyor_belts_changed,
3935     NULL, NULL,
3936     "Change direction",                         "Switch conveyor belt direction"
3937   },
3938   {
3939     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3940     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3941     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,        GADGET_ID_NONE,
3942     &level.bd_water_cannot_flow_down,
3943     NULL, NULL,
3944     "Does not flow downwards",                  "Water can only flow up, left and right"
3945   },
3946   {
3947     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3948     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3949     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,         GADGET_ID_NONE,
3950     &level.bd_hammer_walls_reappear,
3951     NULL, NULL,
3952     "Hammered walls reappear",                  "Hammered walls reappear after delay"
3953   },
3954   {
3955     ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
3956     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3957     GADGET_ID_BD_INFINITE_ROCKETS,              GADGET_ID_NONE,
3958     &level.bd_infinite_rockets,
3959     NULL, NULL,
3960     "Infinite rockets",                         "Rocket launcher has infinite rockets"
3961   },
3962   {
3963     ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
3964     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3965     GADGET_ID_BD_CREATURES_START_BACKWARDS,     GADGET_ID_NONE,
3966     &level.bd_creatures_start_backwards,
3967     NULL, NULL,
3968     "Creatures start moving backwards",         "Creatures start in opposite direction"
3969   },
3970   {
3971     ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
3972     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3973     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3974     &level.bd_creatures_turn_on_hatching,
3975     NULL, NULL,
3976     "Creatures auto turn on hatching",          "Creatures change direction on hatching"
3977   },
3978   {
3979     ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
3980     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3981     GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,         GADGET_ID_NONE,
3982     &level.bd_gravity_switch_active,
3983     NULL, NULL,
3984     "Gravity switch active at start",           "Gravity switch starts in active state"
3985   },
3986   {
3987     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
3988     ED_LEVEL_SETTINGS_XPOS(0),                  ED_ELEMENT_SETTINGS_YPOS(3),
3989     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,           GADGET_ID_NONE,
3990     &level.bd_gravity_affects_all,
3991     NULL, NULL,
3992     "Gravity change affects everything",        "Gravity affects all falling objects"
3993   },
3994   {
3995     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
3996     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3997     GADGET_ID_ENVELOPE_AUTOWRAP,                GADGET_ID_NONE,
3998     &level.envelope[0].autowrap,
3999     NULL, NULL,
4000     "Auto-wrap",                                "Automatically wrap envelope text"
4001   },
4002   {
4003     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
4004     -1,                                         ED_ELEMENT_SETTINGS_YPOS(1),
4005     GADGET_ID_ENVELOPE_CENTERED,                GADGET_ID_ENVELOPE_AUTOWRAP,
4006     &level.envelope[0].centered,
4007     NULL, " ",
4008     "Centered",                                 "Automatically center envelope text"
4009   },
4010   {
4011     ED_CHECKBUTTON_ID_MM_LASER_RED,
4012     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4013     GADGET_ID_MM_LASER_RED,                     GADGET_ID_NONE,
4014     &level.mm_laser_red,
4015     "Choose color components for laser:", NULL,
4016     "Red",                                      "Use red color components in laser"
4017   },
4018   {
4019     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
4020     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4021     GADGET_ID_MM_LASER_GREEN,                   GADGET_ID_NONE,
4022     &level.mm_laser_green,
4023     NULL, NULL,
4024     "Green",                                    "Use green color components in laser"
4025   },
4026   {
4027     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
4028     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4029     GADGET_ID_MM_LASER_BLUE,                    GADGET_ID_NONE,
4030     &level.mm_laser_blue,
4031     NULL, NULL,
4032     "Blue",                                     "Use blue color components in laser"
4033   },
4034   {
4035     ED_CHECKBUTTON_ID_DF_LASER_RED,
4036     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4037     GADGET_ID_DF_LASER_RED,                     GADGET_ID_NONE,
4038     &level.df_laser_red,
4039     "Choose color components for laser:", NULL,
4040     "Red",                                      "Use red color components in laser"
4041   },
4042   {
4043     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
4044     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4045     GADGET_ID_DF_LASER_GREEN,                   GADGET_ID_NONE,
4046     &level.df_laser_green,
4047     NULL, NULL,
4048     "Green",                                    "Use green color components in laser"
4049   },
4050   {
4051     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
4052     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4053     GADGET_ID_DF_LASER_BLUE,                    GADGET_ID_NONE,
4054     &level.df_laser_blue,
4055     NULL, NULL,
4056     "Blue",                                     "Use blue color components in laser"
4057   },
4058   {
4059     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
4060     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
4061     GADGET_ID_ROTATE_MM_BALL_CONTENT,           GADGET_ID_NONE,
4062     &level.rotate_mm_ball_content,
4063     NULL, NULL,
4064     "Randomly rotate created content",          "Randomly rotate newly created content"
4065   },
4066   {
4067     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
4068     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
4069     GADGET_ID_EXPLODE_MM_BALL,                  GADGET_ID_NONE,
4070     &level.explode_mm_ball,
4071     NULL, NULL,
4072     "Explode ball instead of melting",          "Use explosion to release ball content"
4073   },
4074
4075   // ---------- element settings: configure 1 (custom elements) ---------------
4076
4077   {
4078     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
4079     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4080     GADGET_ID_CUSTOM_USE_GRAPHIC,               GADGET_ID_NONE,
4081     &custom_element.use_gfx_element,
4082     NULL, NULL,
4083     "Use graphic of element:",                  "Use existing element graphic"
4084   },
4085   {
4086     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
4087     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
4088     GADGET_ID_CUSTOM_USE_TEMPLATE_1,            GADGET_ID_NONE,
4089     &level.use_custom_template,
4090     NULL, NULL,
4091     "Use template",                             "Use template for custom properties"
4092   },
4093   {
4094     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4095     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4096     GADGET_ID_CUSTOM_ACCESSIBLE,                GADGET_ID_NONE,
4097     &custom_element_properties[EP_ACCESSIBLE],
4098     NULL, NULL,
4099     NULL,                                       "Player can walk to or pass this field"
4100   },
4101   {
4102     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4103     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4104     GADGET_ID_CUSTOM_GRAV_REACHABLE,            GADGET_ID_NONE,
4105     &custom_element_properties[EP_GRAVITY_REACHABLE],
4106     NULL, NULL,
4107     "Reachable despite gravity",                "Player can walk/dig despite gravity"
4108   },
4109   {
4110     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4111     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4112     GADGET_ID_CUSTOM_USE_LAST_VALUE,            GADGET_ID_NONE,
4113     &custom_element.use_last_ce_value,
4114     NULL, NULL,
4115     "Use last CE value after change",           "Use last CE value after change"
4116   },
4117   {
4118     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4119     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
4120     GADGET_ID_CUSTOM_WALK_TO_OBJECT,            GADGET_ID_NONE,
4121     &custom_element_properties[EP_WALK_TO_OBJECT],
4122     NULL, NULL,
4123     NULL,                                       "Player can dig/collect/push element"
4124   },
4125   {
4126     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4127     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4128     GADGET_ID_CUSTOM_INDESTRUCTIBLE,            GADGET_ID_NONE,
4129     &custom_element_properties[EP_INDESTRUCTIBLE],
4130     NULL, NULL,
4131     "Indestructible",                           "Element is indestructible"
4132   },
4133
4134   // ---------- element settings: configure 2 (custom elements) ---------------
4135
4136   {
4137     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4138     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4139     GADGET_ID_CUSTOM_CAN_MOVE,                  GADGET_ID_NONE,
4140     &custom_element_properties[EP_CAN_MOVE],
4141     NULL, NULL,
4142     NULL,                                       "Element can move with some pattern"
4143   },
4144   {
4145     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4146     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4147     GADGET_ID_CUSTOM_CAN_FALL,                  GADGET_ID_NONE,
4148     &custom_element_properties[EP_CAN_FALL],
4149     NULL, NULL,
4150     "Can fall",                                 "Element can fall down"
4151   },
4152   {
4153     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4154     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
4155     GADGET_ID_CUSTOM_CAN_SMASH,                 GADGET_ID_CUSTOM_CAN_FALL,
4156     &custom_element_properties[EP_CAN_SMASH],
4157     NULL, " ",
4158     NULL,                                       "Element can smash other elements"
4159   },
4160   {
4161     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4162     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4163     GADGET_ID_CUSTOM_SLIPPERY,                  GADGET_ID_NONE,
4164     &custom_element_properties[EP_SLIPPERY],
4165     NULL, NULL,
4166     NULL,                                       "Other elements can fall down from it"
4167   },
4168   {
4169     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4170     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
4171     GADGET_ID_CUSTOM_DEADLY,                    GADGET_ID_NONE,
4172     &custom_element_properties[EP_DEADLY],
4173     NULL, NULL,
4174     NULL,                                       "Element can kill the player"
4175   },
4176   {
4177     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4178     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4179     GADGET_ID_CUSTOM_CAN_EXPLODE,               GADGET_ID_NONE,
4180     &custom_element_properties[EP_CAN_EXPLODE],
4181     NULL, NULL,
4182     NULL,                                       "Element can explode"
4183   },
4184   {
4185     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4186     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(12),
4187     GADGET_ID_CUSTOM_EXPLODE_FIRE,              GADGET_ID_NONE,
4188     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4189     NULL, NULL,
4190     "By fire",                                  "Element can explode by fire/explosion"
4191   },
4192   {
4193     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4194     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4195     GADGET_ID_CUSTOM_EXPLODE_SMASH,             GADGET_ID_CUSTOM_EXPLODE_FIRE,
4196     &custom_element_properties[EP_EXPLODES_SMASHED],
4197     NULL, " ",
4198     "Smashed",                                  "Element can explode when smashed"
4199   },
4200   {
4201     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4202     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4203     GADGET_ID_CUSTOM_EXPLODE_IMPACT,            GADGET_ID_CUSTOM_EXPLODE_SMASH,
4204     &custom_element_properties[EP_EXPLODES_IMPACT],
4205     NULL, " ",
4206     "Impact",                                   "Element can explode on impact"
4207   },
4208
4209   // ---------- element settings: advanced (custom elements) ------------------
4210
4211   {
4212     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4213     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4214     GADGET_ID_CUSTOM_CAN_CHANGE,                GADGET_ID_NONE,
4215     &custom_element_change.can_change,
4216     NULL, NULL,
4217     "Element changes to:",                      "Change element on specified condition"
4218   },
4219   {
4220     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4221     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
4222     GADGET_ID_CHANGE_DELAY,                     GADGET_ID_NONE,
4223     &custom_element_change_events[CE_DELAY],
4224     NULL, NULL,
4225     NULL,                                       "Element changes after delay"
4226   },
4227   {
4228     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4229     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
4230     GADGET_ID_CHANGE_BY_DIRECT_ACT,             GADGET_ID_NONE,
4231     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4232     NULL, NULL,
4233     NULL,                                       "Element changes by direct action"
4234   },
4235   {
4236     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4237     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
4238     GADGET_ID_CHANGE_BY_OTHER_ACT,              GADGET_ID_NONE,
4239     &custom_element_change_events[CE_BY_OTHER_ACTION],
4240     NULL, NULL,
4241     NULL,                                       "Element changes by other element"
4242   },
4243   {
4244     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4245     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(8),
4246     GADGET_ID_CHANGE_USE_EXPLOSION,             GADGET_ID_NONE,
4247     &custom_element_change.explode,
4248     NULL, NULL,
4249     "Explode instead of change",                "Element explodes instead of change"
4250   },
4251   {
4252     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4253     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
4254     GADGET_ID_CHANGE_USE_CONTENT,               GADGET_ID_NONE,
4255     &custom_element_change.use_target_content,
4256     NULL, NULL,
4257     "Use extended change target:",              "Element changes to more elements"
4258   },
4259   {
4260     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4261     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(11),
4262     GADGET_ID_CHANGE_ONLY_COMPLETE,             GADGET_ID_NONE,
4263     &custom_element_change.only_if_complete,
4264     NULL, NULL,
4265     "Replace all or nothing",                   "Only replace when all can be changed"
4266   },
4267   {
4268     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4269     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(12),
4270     GADGET_ID_CHANGE_USE_RANDOM,                GADGET_ID_NONE,
4271     &custom_element_change.use_random_replace,
4272     NULL, NULL,
4273     NULL,                                       "Use percentage for random replace"
4274   },
4275   {
4276     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4277     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
4278     GADGET_ID_CHANGE_HAS_ACTION,                GADGET_ID_NONE,
4279     &custom_element_change.has_action,
4280     NULL, NULL,
4281     NULL,                                       "Execute action on specified condition"
4282   },
4283 };
4284
4285 static struct
4286 {
4287   int gadget_type_id;
4288   int x, y;
4289   int xoffset, yoffset;
4290   int gadget_id;
4291   int gadget_id_align;
4292   int *value;
4293   int area_xsize, area_ysize;
4294   char *text_left, *text_right, *text_above, *text_below, *infotext;
4295 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4296 {
4297   // ---------- level playfield content ---------------------------------------
4298
4299   {
4300     ED_DRAWING_ID_DRAWING_LEVEL,
4301     0,                                          0,
4302     0,                                          0,
4303     GADGET_ID_DRAWING_LEVEL,                    GADGET_ID_NONE,
4304     NULL,
4305     -1, -1,     // these values are not constant, but can change at runtime
4306     NULL, NULL, NULL, NULL,                     NULL
4307   },
4308
4309   // ---------- yam yam content -----------------------------------------------
4310
4311   {
4312     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4313     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4314     ED_AREA_YAMYAM_CONTENT_XOFF(0),             ED_AREA_YAMYAM_CONTENT_YOFF(0),
4315     GADGET_ID_YAMYAM_CONTENT_0,                 GADGET_ID_NONE,
4316     &level.yamyam_content[0].e[0][0],           3, 3,
4317     NULL, NULL, NULL, "1",                      NULL
4318   },
4319   {
4320     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4321     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4322     ED_AREA_YAMYAM_CONTENT_XOFF(1),             ED_AREA_YAMYAM_CONTENT_YOFF(1),
4323     GADGET_ID_YAMYAM_CONTENT_1,                 GADGET_ID_NONE,
4324     &level.yamyam_content[1].e[0][0],           3, 3,
4325     NULL, NULL, NULL, "2",                      NULL
4326   },
4327   {
4328     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4329     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4330     ED_AREA_YAMYAM_CONTENT_XOFF(2),             ED_AREA_YAMYAM_CONTENT_YOFF(2),
4331     GADGET_ID_YAMYAM_CONTENT_2,                 GADGET_ID_NONE,
4332     &level.yamyam_content[2].e[0][0],           3, 3,
4333     NULL, NULL, NULL, "3",                      NULL
4334   },
4335   {
4336     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4337     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4338     ED_AREA_YAMYAM_CONTENT_XOFF(3),             ED_AREA_YAMYAM_CONTENT_YOFF(3),
4339     GADGET_ID_YAMYAM_CONTENT_3,                 GADGET_ID_NONE,
4340     &level.yamyam_content[3].e[0][0],           3, 3,
4341     NULL, NULL, NULL, "4",                      NULL
4342   },
4343   {
4344     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4345     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4346     ED_AREA_YAMYAM_CONTENT_XOFF(4),             ED_AREA_YAMYAM_CONTENT_YOFF(4),
4347     GADGET_ID_YAMYAM_CONTENT_4,                 GADGET_ID_NONE,
4348     &level.yamyam_content[4].e[0][0],           3, 3,
4349     NULL, NULL, NULL, "5",                      NULL
4350   },
4351   {
4352     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4353     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4354     ED_AREA_YAMYAM_CONTENT_XOFF(5),             ED_AREA_YAMYAM_CONTENT_YOFF(5),
4355     GADGET_ID_YAMYAM_CONTENT_5,                 GADGET_ID_NONE,
4356     &level.yamyam_content[5].e[0][0],           3, 3,
4357     NULL, NULL, NULL, "6",                      NULL
4358   },
4359   {
4360     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4361     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4362     ED_AREA_YAMYAM_CONTENT_XOFF(6),             ED_AREA_YAMYAM_CONTENT_YOFF(6),
4363     GADGET_ID_YAMYAM_CONTENT_6,                 GADGET_ID_NONE,
4364     &level.yamyam_content[6].e[0][0],           3, 3,
4365     NULL, NULL, NULL, "7",                      NULL
4366   },
4367   {
4368     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4369     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4370     ED_AREA_YAMYAM_CONTENT_XOFF(7),             ED_AREA_YAMYAM_CONTENT_YOFF(7),
4371     GADGET_ID_YAMYAM_CONTENT_7,                 GADGET_ID_NONE,
4372     &level.yamyam_content[7].e[0][0],           3, 3,
4373     NULL, NULL, NULL, "8",                      NULL
4374   },
4375
4376   // ---------- magic ball content --------------------------------------------
4377
4378   {
4379     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4380     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4381     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4382     GADGET_ID_MAGIC_BALL_CONTENT_0,             GADGET_ID_NONE,
4383     &level.ball_content[0].e[0][0],             3, 3,
4384     NULL, NULL, NULL, "1",                      NULL
4385   },
4386   {
4387     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4388     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4389     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4390     GADGET_ID_MAGIC_BALL_CONTENT_1,             GADGET_ID_NONE,
4391     &level.ball_content[1].e[0][0],             3, 3,
4392     NULL, NULL, NULL, "2",                      NULL
4393   },
4394   {
4395     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4396     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4397     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4398     GADGET_ID_MAGIC_BALL_CONTENT_2,             GADGET_ID_NONE,
4399     &level.ball_content[2].e[0][0],             3, 3,
4400     NULL, NULL, NULL, "3",                      NULL
4401   },
4402   {
4403     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4404     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4405     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4406     GADGET_ID_MAGIC_BALL_CONTENT_3,             GADGET_ID_NONE,
4407     &level.ball_content[3].e[0][0],             3, 3,
4408     NULL, NULL, NULL, "4",                      NULL
4409   },
4410   {
4411     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4412     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4413     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4414     GADGET_ID_MAGIC_BALL_CONTENT_4,             GADGET_ID_NONE,
4415     &level.ball_content[4].e[0][0],             3, 3,
4416     NULL, NULL, NULL, "5",                      NULL
4417   },
4418   {
4419     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4420     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4421     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4422     GADGET_ID_MAGIC_BALL_CONTENT_5,             GADGET_ID_NONE,
4423     &level.ball_content[5].e[0][0],             3, 3,
4424     NULL, NULL, NULL, "6",                      NULL
4425   },
4426   {
4427     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4428     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4429     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4430     GADGET_ID_MAGIC_BALL_CONTENT_6,             GADGET_ID_NONE,
4431     &level.ball_content[6].e[0][0],             3, 3,
4432     NULL, NULL, NULL, "7",                      NULL
4433   },
4434   {
4435     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4436     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4437     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4438     GADGET_ID_MAGIC_BALL_CONTENT_7,             GADGET_ID_NONE,
4439     &level.ball_content[7].e[0][0],             3, 3,
4440     NULL, NULL, NULL, "8",                      NULL
4441   },
4442
4443   // ---------- android content -----------------------------------------------
4444
4445   {
4446     ED_DRAWING_ID_ANDROID_CONTENT,
4447     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4448     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4449     GADGET_ID_ANDROID_CONTENT,                  GADGET_ID_NONE,
4450     &level.android_clone_element[0],            MAX_ANDROID_ELEMENTS, 1,
4451     NULL, NULL, "Elements:", NULL,              "Elements android can clone"
4452   },
4453
4454   // ---------- amoeba content ------------------------------------------------
4455
4456   {
4457     ED_DRAWING_ID_AMOEBA_CONTENT,
4458     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4459     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4460     GADGET_ID_AMOEBA_CONTENT,                   GADGET_ID_NONE,
4461     &level.amoeba_content,                      1, 1,
4462     "Content:", NULL, NULL, NULL,               "Amoeba content"
4463   },
4464
4465   // ---------- BD snap element -----------------------------------------------
4466
4467   {
4468     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4469     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4470     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4471     GADGET_ID_BD_SNAP_ELEMENT,                  GADGET_ID_NONE,
4472     &level.bd_snap_element,                     1, 1,
4473     "Snap element:", NULL, NULL, NULL,          "Element created when snapping"
4474   },
4475
4476   // ---------- BD magic wall elements ----------------------------------------
4477
4478   {
4479     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4480     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(4),
4481     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4482     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,         GADGET_ID_NONE,
4483     &level.bd_magic_wall_diamond_to,            1, 1,
4484     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4485   },
4486   {
4487     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4488     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4489     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4490     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,            GADGET_ID_NONE,
4491     &level.bd_magic_wall_rock_to,               1, 1,
4492     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4493   },
4494   {
4495     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4496     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4497     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4498     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,       GADGET_ID_NONE,
4499     &level.bd_magic_wall_mega_rock_to,          1, 1,
4500     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4501   },
4502   {
4503     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4504     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4505     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4506     GADGET_ID_BD_MAGIC_WALL_NUT_TO,             GADGET_ID_NONE,
4507     &level.bd_magic_wall_nut_to,                1, 1,
4508     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4509   },
4510   {
4511     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4512     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4513     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4514     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,      GADGET_ID_NONE,
4515     &level.bd_magic_wall_nitro_pack_to,         1, 1,
4516     "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
4517   },
4518   {
4519     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4520     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(9),
4521     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4522     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,  GADGET_ID_NONE,
4523     &level.bd_magic_wall_flying_diamond_to,     1, 1,
4524     "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
4525   },
4526   {
4527     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4528     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4529     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4530     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,     GADGET_ID_NONE,
4531     &level.bd_magic_wall_flying_rock_to,        1, 1,
4532     "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
4533   },
4534
4535   // ---------- BD amoeba content ---------------------------------------------
4536
4537   {
4538     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4539     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4540     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4541     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,        GADGET_ID_NONE,
4542     &level.bd_amoeba_content_too_big,           1, 1,
4543     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba content if too big"
4544   },
4545   {
4546     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4547     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4548     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4549     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,       GADGET_ID_NONE,
4550     &level.bd_amoeba_content_enclosed,          1, 1,
4551     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba content if enclosed"
4552   },
4553
4554   // ---------- BD amoeba 2 content -------------------------------------------
4555
4556   {
4557     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4558     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4559     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4560     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,      GADGET_ID_NONE,
4561     &level.bd_amoeba_2_content_too_big,         1, 1,
4562     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if too big"
4563   },
4564   {
4565     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4566     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4567     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4568     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,     GADGET_ID_NONE,
4569     &level.bd_amoeba_2_content_enclosed,        1, 1,
4570     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if enclosed"
4571   },
4572   {
4573     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4574     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4575     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4576     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,    GADGET_ID_NONE,
4577     &level.bd_amoeba_2_content_exploding,       1, 1,
4578     "If exploding, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if exploding"
4579   },
4580   {
4581     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4582     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4583     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4584     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4585     &level.bd_amoeba_2_content_looks_like,      1, 1,
4586     "Use graphic of element:", NULL, NULL, NULL, "BD amoeba 2 looks like this element"
4587   },
4588   {
4589     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4590     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4591     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4592     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,          GADGET_ID_NONE,
4593     &level.bd_slime_eats_element_1,             1, 1,
4594     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4595   },
4596   {
4597     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4598     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4599     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4600     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4601     &level.bd_slime_converts_to_element_1,      1, 1,
4602     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4603   },
4604   {
4605     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4606     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4607     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4608     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,          GADGET_ID_NONE,
4609     &level.bd_slime_eats_element_2,             1, 1,
4610     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4611   },
4612   {
4613     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4614     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4615     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4616     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4617     &level.bd_slime_converts_to_element_2,      1, 1,
4618     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4619   },
4620   {
4621     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4622     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4623     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4624     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,          GADGET_ID_NONE,
4625     &level.bd_slime_eats_element_3,             1, 1,
4626     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4627   },
4628   {
4629     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4630     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4631     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4632     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4633     &level.bd_slime_converts_to_element_3,      1, 1,
4634     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4635   },
4636   {
4637     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4638     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4639     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4640     GADGET_ID_BD_ACID_EATS_ELEMENT,             GADGET_ID_NONE,
4641     &level.bd_acid_eats_element,                1, 1,
4642     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4643   },
4644   {
4645     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4646     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4647     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4648     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,         GADGET_ID_NONE,
4649     &level.bd_acid_turns_to_element,            1, 1,
4650     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4651   },
4652   {
4653     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4654     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4655     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4656     GADGET_ID_BD_BITER_EATS_ELEMENT,            GADGET_ID_NONE,
4657     &level.bd_biter_eats_element,               1, 1,
4658     "Can eat:", NULL, NULL, NULL,               "Eats this element when moving"
4659   },
4660   {
4661     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4662     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4663     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4664     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
4665     &level.bd_bladder_converts_by_element,      1, 1,
4666     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
4667   },
4668   {
4669     ED_DRAWING_ID_BD_NUT_CONTENT,
4670     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4671     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4672     GADGET_ID_BD_NUT_CONTENT,                   GADGET_ID_NONE,
4673     &level.bd_nut_content,                      1, 1,
4674     "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
4675   },
4676   {
4677     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4678     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4679     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4680     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,     GADGET_ID_NONE,
4681     &level.bd_expanding_wall_looks_like,        1, 1,
4682     "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
4683   },
4684   {
4685     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4686     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4687     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4688     GADGET_ID_BD_SAND_LOOKS_LIKE,               GADGET_ID_NONE,
4689     &level.bd_sand_looks_like,                  1, 1,
4690     "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
4691   },
4692   {
4693     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
4694     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4695     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4696     GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,      GADGET_ID_NONE,
4697     &level.bd_rock_turns_to_on_falling,         1, 1,
4698     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4699   },
4700   {
4701     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
4702     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4703     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4704     GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,       GADGET_ID_NONE,
4705     &level.bd_rock_turns_to_on_impact,          1, 1,
4706     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4707   },
4708   {
4709     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
4710     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4711     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4712     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,   GADGET_ID_NONE,
4713     &level.bd_diamond_turns_to_on_falling,      1, 1,
4714     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4715   },
4716   {
4717     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
4718     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4719     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4720     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,    GADGET_ID_NONE,
4721     &level.bd_diamond_turns_to_on_impact,       1, 1,
4722     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4723   },
4724   {
4725     ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
4726     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4727     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4728     GADGET_ID_BD_FIREFLY_EXPLODES_TO,           GADGET_ID_NONE,
4729     &level.bd_firefly_explodes_to,              1, 1,
4730     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4731   },
4732   {
4733     ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
4734     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4735     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4736     GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,         GADGET_ID_NONE,
4737     &level.bd_firefly_2_explodes_to,            1, 1,
4738     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4739   },
4740   {
4741     ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
4742     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4743     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4744     GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,         GADGET_ID_NONE,
4745     &level.bd_butterfly_explodes_to,            1, 1,
4746     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4747   },
4748   {
4749     ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
4750     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4751     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4752     GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,       GADGET_ID_NONE,
4753     &level.bd_butterfly_2_explodes_to,          1, 1,
4754     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4755   },
4756   {
4757     ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
4758     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4759     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4760     GADGET_ID_BD_STONEFLY_EXPLODES_TO,          GADGET_ID_NONE,
4761     &level.bd_stonefly_explodes_to,             1, 1,
4762     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4763   },
4764   {
4765     ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
4766     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4767     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4768     GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,         GADGET_ID_NONE,
4769     &level.bd_dragonfly_explodes_to,            1, 1,
4770     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4771   },
4772   {
4773     ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
4774     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4775     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4776     GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,        GADGET_ID_NONE,
4777     &level.bd_diamond_birth_turns_to,           1, 1,
4778     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4779   },
4780   {
4781     ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
4782     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4783     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4784     GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,       GADGET_ID_NONE,
4785     &level.bd_bomb_explosion_turns_to,          1, 1,
4786     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4787   },
4788   {
4789     ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
4790     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4791     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4792     GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,      GADGET_ID_NONE,
4793     &level.bd_nitro_explosion_turns_to,         1, 1,
4794     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4795   },
4796   {
4797     ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
4798     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4799     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4800     GADGET_ID_BD_EXPLOSION_TURNS_TO,            GADGET_ID_NONE,
4801     &level.bd_explosion_turns_to,               1, 1,
4802     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4803   },
4804
4805   // ---------- level start element -------------------------------------------
4806
4807   {
4808     ED_DRAWING_ID_START_ELEMENT,
4809     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(10),
4810     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4811     GADGET_ID_START_ELEMENT,                    GADGET_ID_USE_START_ELEMENT,
4812     &level.start_element[0],                    1, 1,
4813     NULL, NULL, NULL, NULL,                     "Level start element"
4814   },
4815
4816   // ---------- player artwork element ----------------------------------------
4817
4818   {
4819     ED_DRAWING_ID_ARTWORK_ELEMENT,
4820     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(11),
4821     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4822     GADGET_ID_ARTWORK_ELEMENT,                  GADGET_ID_USE_ARTWORK_ELEMENT,
4823     &level.artwork_element[0],                  1, 1,
4824     NULL, NULL, NULL, NULL,                     "Element for player artwork"
4825   },
4826
4827   // ---------- player explosion element --------------------------------------
4828
4829   {
4830     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4831     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(12),
4832     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4833     GADGET_ID_EXPLOSION_ELEMENT,                GADGET_ID_USE_EXPLOSION_ELEMENT,
4834     &level.explosion_element[0],                1, 1,
4835     NULL, NULL, NULL, NULL,                     "Element for player explosion"
4836   },
4837
4838   // ---------- player initial inventory --------------------------------------
4839
4840   {
4841     ED_DRAWING_ID_INVENTORY_CONTENT,
4842     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4843     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4844     GADGET_ID_INVENTORY_CONTENT,                GADGET_ID_USE_INITIAL_INVENTORY,
4845     &level.initial_inventory_content[0][0],     MAX_INITIAL_INVENTORY_SIZE, 1,
4846     NULL, NULL, NULL, NULL,                     "Content for initial inventory"
4847   },
4848
4849   // ---------- gray ball content -----------------------------------------
4850
4851   {
4852     ED_DRAWING_ID_MM_BALL_CONTENT,
4853     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4854     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4855     GADGET_ID_MM_BALL_CONTENT,                  GADGET_ID_NONE,
4856     &level.mm_ball_content[0],                  MAX_MM_BALL_CONTENTS, 1,
4857     "Content:", NULL, NULL, NULL,               "Content for gray ball"
4858   },
4859
4860   // ---------- element settings: configure 1 (custom elements) ---------------
4861
4862   // ---------- custom graphic ------------------------------------------------
4863
4864   {
4865     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4866     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4867     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4868     GADGET_ID_CUSTOM_GRAPHIC,                   GADGET_ID_CUSTOM_USE_GRAPHIC,
4869     &custom_element.gfx_element_initial,        1, 1,
4870     NULL, NULL, NULL, NULL,                     "Custom graphic element"
4871   },
4872
4873   // ---------- element settings: configure 2 (custom elements) ---------------
4874
4875   // ---------- custom content (when exploding) -------------------------------
4876
4877   {
4878     ED_DRAWING_ID_CUSTOM_CONTENT,
4879     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(11),
4880     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4881     GADGET_ID_CUSTOM_CONTENT,                   GADGET_ID_NONE,         // align three rows
4882     &custom_element.content.e[0][0],            3, 3,
4883     "Content:", NULL, NULL, NULL,               NULL
4884   },
4885
4886   // ---------- custom enter and leave element (when moving) ------------------
4887
4888   {
4889     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4890     ED_AREA_1X1_SETTINGS_XPOS(1),               ED_AREA_1X1_SETTINGS_YPOS(3),
4891     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4892     GADGET_ID_CUSTOM_MOVE_ENTER,                GADGET_ID_NONE,
4893     &custom_element.move_enter_element,         1, 1,
4894     "Can dig:", " ", NULL, NULL,                "Element that can be digged/collected"
4895   },
4896   {
4897     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4898     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(3),
4899     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4900     GADGET_ID_CUSTOM_MOVE_LEAVE,                GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4901     &custom_element.move_leave_element,         1, 1,
4902     NULL, NULL, NULL, NULL,                     "Element that will be left behind"
4903   },
4904
4905   // ---------- element settings: advanced (custom elements) ------------------
4906
4907   // ---------- custom change target ------------------------------------------
4908
4909   {
4910     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4911     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4912     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4913     GADGET_ID_CUSTOM_CHANGE_TARGET,             GADGET_ID_CUSTOM_CAN_CHANGE,
4914     &custom_element_change.target_element,      1, 1,
4915     NULL, "after/when:", NULL, NULL,            "New target element after change"
4916   },
4917
4918   // ---------- custom change content (extended change target) ----------------
4919
4920   {
4921     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4922     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(9),
4923     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4924     GADGET_ID_CUSTOM_CHANGE_CONTENT,            GADGET_ID_NONE,         // align three rows
4925     &custom_element_change.target_content.e[0][0], 3, 3,
4926     NULL, NULL, NULL, NULL,                     "New extended elements after change"
4927   },
4928
4929   // ---------- custom change trigger (element causing change) ----------------
4930
4931   {
4932     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4933     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(5),
4934     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4935     GADGET_ID_CUSTOM_CHANGE_TRIGGER,            GADGET_ID_CHANGE_OTHER_ACTION,
4936     &custom_element_change.initial_trigger_element, 1, 1,
4937     NULL, NULL, NULL, NULL,                     "Other element triggering change"
4938   },
4939
4940   // ---------- custom change action (element used for action) ----------------
4941
4942   {
4943     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4944     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(13),
4945     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4946     GADGET_ID_CUSTOM_CHANGE_ACTION,             GADGET_ID_ACTION_ARG,
4947     &custom_element_change.action_element,      1, 1,
4948     NULL, NULL, NULL, NULL,                     "Element used as action parameter"
4949   },
4950
4951   // ---------- group element content -----------------------------------------
4952
4953   {
4954     ED_DRAWING_ID_GROUP_CONTENT,
4955     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4956     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4957     GADGET_ID_GROUP_CONTENT,                    GADGET_ID_NONE,
4958     &group_element_info.element[0],             MAX_ELEMENTS_IN_GROUP, 1,
4959     "Content:", NULL, NULL, NULL,               NULL
4960   },
4961
4962   // ---------- random background (for random painting) -----------------------
4963
4964   {
4965     ED_DRAWING_ID_RANDOM_BACKGROUND,
4966     -1,                                         ED_AREA_1X1_LSETTINGS_YPOS(1),
4967     0,                                          ED_AREA_1X1_LSETTINGS_YOFF,
4968     GADGET_ID_RANDOM_BACKGROUND,                GADGET_ID_RANDOM_RESTRICTED,
4969     &random_placement_background_element,       1, 1,
4970     NULL, NULL, NULL, NULL,                     "Random placement background"
4971   },
4972 };
4973
4974
4975 // ----------------------------------------------------------------------------
4976 // some internally used variables
4977 // ----------------------------------------------------------------------------
4978
4979 // maximal size of level editor drawing area
4980 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
4981
4982 // actual size of level editor drawing area
4983 static int ed_fieldx, ed_fieldy;
4984
4985 // actual position of level editor drawing area in level playfield
4986 static int level_xpos = -1, level_ypos = -1;
4987
4988 // actual tile size used to display playfield drawing area
4989 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
4990 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
4991
4992 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
4993
4994 // drawing elements on the three mouse buttons
4995 static int new_element1 = EL_WALL;
4996 static int new_element2 = EL_EMPTY;
4997 static int new_element3 = EL_SAND;
4998
4999 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
5000 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
5001                                 (button) == 2 ? new_element2 : \
5002                                 (button) == 3 ? new_element3 : EL_EMPTY)
5003
5004 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
5005
5006 static int use_permanent_palette = TRUE;
5007
5008 #define PX              (use_permanent_palette ? DX : SX)
5009 #define PY              (use_permanent_palette ? DY : SY)
5010 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
5011 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
5012
5013 // forward declaration for internal use
5014 static void CopyBrushToCursor(int, int);
5015 static void DeleteBrushFromCursor(void);
5016 static void ModifyEditorCounterValue(int, int);
5017 static void ModifyEditorCounterLimits(int, int, int);
5018 static void ModifyEditorSelectboxValue(int, int);
5019 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
5020 static void ModifyEditorDrawingArea(int, int, int);
5021 static void ModifyEditorElementList(void);
5022 static void AdjustElementListScrollbar(void);
5023 static void RedrawDrawingElements(void);
5024 static void DrawDrawingWindowExt(boolean);
5025 static void DrawDrawingWindow(void);
5026 static void DrawLevelConfigWindow(void);
5027 static void DrawPropertiesWindow(void);
5028 static void DrawPaletteWindow(void);
5029 static void UpdateCustomElementGraphicGadgets(void);
5030 static boolean checkPropertiesConfig(int);
5031 static void SetAutomaticNumberOfGemsNeeded(void);
5032 static void ClearEditorGadgetInfoText(void);
5033 static void CopyLevelToUndoBuffer(int);
5034 static void HandleDrawingAreas(struct GadgetInfo *);
5035 static void HandleCounterButtons(struct GadgetInfo *);
5036 static void HandleTextInputGadgets(struct GadgetInfo *);
5037 static void HandleTextAreaGadgets(struct GadgetInfo *);
5038 static void HandleSelectboxGadgets(struct GadgetInfo *);
5039 static void HandleTextbuttonGadgets(struct GadgetInfo *);
5040 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
5041 static void HandleRadiobuttons(struct GadgetInfo *);
5042 static void HandleCheckbuttons(struct GadgetInfo *);
5043 static void HandleControlButtons(struct GadgetInfo *);
5044 static void HandleDrawingAreaInfo(struct GadgetInfo *);
5045 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
5046 static boolean AskToCopyAndModifyLevelTemplate(void);
5047 static boolean getDrawModeHiRes(void);
5048 static int getTabulatorBarWidth(void);
5049 static int getTabulatorBarHeight(void);
5050 static Pixel getTabulatorBarColor(void);
5051 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
5052 static int numHiresTiles(int);
5053
5054 static int num_editor_gadgets = 0;      // dynamically determined
5055
5056 static struct GadgetInfo **level_editor_gadget = NULL;
5057 static int *right_gadget_border = NULL;
5058
5059 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
5060 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
5061 static boolean draw_with_brush = FALSE;
5062 static int properties_element = 0;
5063
5064 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5065 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5066 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5067 static int undo_buffer_position = 0;
5068 static int undo_buffer_steps = 0;
5069 static int redo_buffer_steps = 0;
5070
5071 static int edit_mode;
5072 static int edit_mode_levelconfig;
5073 static int edit_mode_properties;
5074
5075 static int element_shift = 0;
5076
5077 static int editor_el_players[] =
5078 {
5079   EL_PLAYER_1,
5080   EL_PLAYER_2,
5081   EL_PLAYER_3,
5082   EL_PLAYER_4
5083 };
5084 static int *editor_el_players_ptr = editor_el_players;
5085 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
5086
5087 static int editor_hl_boulderdash[] =
5088 {
5089   EL_INTERNAL_CASCADE_BD_ACTIVE,
5090   EL_CHAR('B'),
5091   EL_CHAR('D'),
5092   EL_EMPTY,
5093 };
5094
5095 static int editor_el_boulderdash[] =
5096 {
5097   EL_EMPTY,
5098   EL_SAND,
5099   EL_BD_ROCK,
5100   EL_BD_DIAMOND,
5101
5102   EL_STEELWALL,
5103   EL_BD_WALL,
5104   EL_BD_EXPANDABLE_WALL,
5105   EL_BD_MAGIC_WALL,
5106
5107   EL_BD_AMOEBA,
5108   EL_BD_BUTTERFLY_UP,
5109   EL_BD_FIREFLY_UP,
5110   EL_EXIT_CLOSED,
5111
5112   EL_BD_BUTTERFLY_LEFT,
5113   EL_BD_FIREFLY_LEFT,
5114   EL_BD_BUTTERFLY_RIGHT,
5115   EL_BD_FIREFLY_RIGHT,
5116
5117   EL_EMPTY,
5118   EL_BD_BUTTERFLY_DOWN,
5119   EL_BD_FIREFLY_DOWN,
5120   EL_EXIT_OPEN,
5121 };
5122 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
5123 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
5124 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
5125 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
5126
5127 static int editor_hl_boulderdash_native[] =
5128 {
5129   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
5130   EL_CHAR('B'),
5131   EL_CHAR('D'),
5132   EL_EMPTY,
5133 };
5134
5135 static int editor_el_boulderdash_native[] =
5136 {
5137   EL_EMPTY,
5138   EL_BD_SAND,
5139   EL_BD_ROCK,
5140   EL_BD_DIAMOND,
5141
5142   EL_BD_INBOX,
5143   EL_BD_STEELWALL,
5144   EL_BD_WALL,
5145   EL_BD_MAGIC_WALL,
5146
5147   EL_BD_AMOEBA,
5148   EL_BD_BUTTERFLY_UP,
5149   EL_BD_FIREFLY_UP,
5150   EL_BD_EXIT_CLOSED,
5151
5152   EL_BD_BUTTERFLY_LEFT,
5153   EL_BD_FIREFLY_LEFT,
5154   EL_BD_BUTTERFLY_RIGHT,
5155   EL_BD_FIREFLY_RIGHT,
5156
5157   EL_BD_SAND_2,
5158   EL_BD_BUTTERFLY_DOWN,
5159   EL_BD_FIREFLY_DOWN,
5160   EL_BD_EXIT_OPEN,
5161
5162   EL_BD_AMOEBA_2,
5163   EL_BD_BUTTERFLY_2_UP,
5164   EL_BD_FIREFLY_2_UP,
5165   EL_BD_SLIME,
5166
5167   EL_BD_BUTTERFLY_2_LEFT,
5168   EL_BD_FIREFLY_2_LEFT,
5169   EL_BD_BUTTERFLY_2_RIGHT,
5170   EL_BD_FIREFLY_2_RIGHT,
5171
5172   EL_BD_BOMB,
5173   EL_BD_BUTTERFLY_2_DOWN,
5174   EL_BD_FIREFLY_2_DOWN,
5175   EL_BD_FLYING_DIAMOND,
5176
5177   EL_BD_NITRO_PACK,
5178   EL_BD_DRAGONFLY_UP,
5179   EL_BD_STONEFLY_UP,
5180   EL_BD_DIAMOND_GLUED,
5181
5182   EL_BD_DRAGONFLY_LEFT,
5183   EL_BD_STONEFLY_LEFT,
5184   EL_BD_DRAGONFLY_RIGHT,
5185   EL_BD_STONEFLY_RIGHT,
5186
5187   EL_BD_NUT,
5188   EL_BD_DRAGONFLY_DOWN,
5189   EL_BD_STONEFLY_DOWN,
5190   EL_EMPTY,
5191
5192   EL_BD_BITER_SWITCH_1,
5193   EL_BD_BITER_UP,
5194   EL_BD_COW_UP,
5195   EL_EMPTY,
5196
5197   EL_BD_BITER_LEFT,
5198   EL_BD_COW_LEFT,
5199   EL_BD_BITER_RIGHT,
5200   EL_BD_COW_RIGHT,
5201
5202   EL_BD_VOODOO_DOLL,
5203   EL_BD_BITER_DOWN,
5204   EL_BD_COW_DOWN,
5205   EL_BD_GHOST,
5206
5207   EL_BD_SAND_GLUED,
5208   EL_BD_SAND_BALL,
5209   EL_BD_SAND_LOOSE,
5210   EL_BD_WALL_NON_SLOPED,
5211
5212   EL_BD_SAND_SLOPED_UP_LEFT,
5213   EL_BD_SAND_SLOPED_UP_RIGHT,
5214   EL_BD_WALL_SLOPED_UP_LEFT,
5215   EL_BD_WALL_SLOPED_UP_RIGHT,
5216
5217   EL_BD_SAND_SLOPED_DOWN_LEFT,
5218   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5219   EL_BD_WALL_SLOPED_DOWN_LEFT,
5220   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5221
5222   EL_BD_FLYING_ROCK,
5223   EL_BD_ROCK_GLUED,
5224   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5225   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5226
5227   EL_BD_WAITING_ROCK,
5228   EL_BD_CHASING_ROCK,
5229   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5230   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5231
5232   EL_BD_MEGA_ROCK,
5233   EL_BD_SWEET,
5234   EL_BD_INVISIBLE_EXIT_CLOSED,
5235   EL_BD_INVISIBLE_EXIT_OPEN,
5236
5237   EL_BD_STEELWALL_EXPLODABLE,
5238   EL_BD_STEELWALL_DIGGABLE,
5239   EL_BD_WALL_DIGGABLE,
5240   EL_BD_FALLING_WALL,
5241
5242   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5243   EL_BD_EXPANDABLE_WALL_VERTICAL,
5244   EL_BD_EXPANDABLE_WALL_ANY,
5245   EL_BD_EXPANDABLE_WALL_SWITCH,
5246
5247   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5248   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5249   EL_BD_EXPANDABLE_STEELWALL_ANY,
5250   EL_BD_CREATURE_SWITCH,
5251
5252   EL_BD_BLADDER,
5253   EL_BD_BLADDER_SPENDER,
5254   EL_BD_REPLICATOR,
5255   EL_BD_REPLICATOR_SWITCH,
5256
5257   EL_BD_CONVEYOR_LEFT,
5258   EL_BD_CONVEYOR_RIGHT,
5259   EL_BD_CONVEYOR_SWITCH,
5260   EL_BD_CONVEYOR_DIR_SWITCH,
5261
5262   EL_BD_CLOCK,
5263   EL_BD_TIME_PENALTY,
5264   EL_BD_GRAVESTONE,
5265   EL_BD_SKELETON,
5266
5267   EL_BD_WATER,
5268   EL_BD_ACID,
5269   EL_BD_LAVA,
5270   EL_BD_BOX,
5271
5272   EL_BD_GATE_1,
5273   EL_BD_GATE_2,
5274   EL_BD_GATE_3,
5275   EL_BD_TRAPPED_DIAMOND,
5276
5277   EL_BD_KEY_1,
5278   EL_BD_KEY_2,
5279   EL_BD_KEY_3,
5280   EL_BD_DIAMOND_KEY,
5281
5282   EL_BD_WALL_KEY_1,
5283   EL_BD_WALL_KEY_2,
5284   EL_BD_WALL_KEY_3,
5285   EL_BD_WALL_DIAMOND,
5286
5287   EL_BD_POT,
5288   EL_BD_GRAVITY_SWITCH,
5289   EL_BD_PNEUMATIC_HAMMER,
5290   EL_BD_TELEPORTER,
5291
5292   EL_BD_PLAYER,
5293   EL_BD_PLAYER_WITH_BOMB,
5294   EL_BD_PLAYER_WITH_ROCKET_LAUNCHER,
5295   EL_BD_ROCKET_LAUNCHER,
5296
5297   EL_BD_PLAYER_GLUED,
5298   EL_BD_PLAYER_STIRRING,
5299   EL_EMPTY,
5300   EL_EMPTY,
5301 };
5302 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5303 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5304 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5305 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5306
5307 static int editor_hl_boulderdash_effects[] =
5308 {
5309   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5310   EL_CHAR('B'),
5311   EL_CHAR('D'),
5312   EL_CHAR('E'),
5313 };
5314
5315 static int editor_el_boulderdash_effects[] =
5316 {
5317   EL_BD_DIAMOND_FALLING,
5318   EL_BD_ROCK_FALLING,
5319   EL_BD_MEGA_ROCK_FALLING,
5320   EL_BD_FLYING_DIAMOND_FLYING,
5321
5322   EL_BD_FALLING_WALL_FALLING,
5323   EL_BD_NITRO_PACK_FALLING,
5324   EL_BD_NUT_FALLING,
5325   EL_BD_FLYING_ROCK_FLYING,
5326
5327   EL_BD_PLAYER_GROWING_1,
5328   EL_BD_PLAYER_GROWING_2,
5329   EL_BD_PLAYER_GROWING_3,
5330   EL_BD_PLAYER,
5331
5332   EL_BD_PLAYER_WITH_BOMB,
5333   EL_BD_PLAYER_STIRRING,
5334   EL_BD_EXIT_OPEN,
5335   EL_BD_INVISIBLE_EXIT_OPEN,
5336
5337   EL_BD_BLADDER_1,
5338   EL_BD_BLADDER_2,
5339   EL_BD_BLADDER_3,
5340   EL_BD_BLADDER_4,
5341
5342   EL_BD_BLADDER_5,
5343   EL_BD_BLADDER_6,
5344   EL_BD_BLADDER_7,
5345   EL_BD_BLADDER_8,
5346
5347   EL_BD_SAND_2,
5348   EL_BD_COW_ENCLOSED_1,
5349   EL_BD_COW_ENCLOSED_2,
5350   EL_BD_COW_ENCLOSED_3,
5351
5352   EL_BD_COW_ENCLOSED_4,
5353   EL_BD_COW_ENCLOSED_5,
5354   EL_BD_COW_ENCLOSED_6,
5355   EL_BD_COW_ENCLOSED_7,
5356
5357   EL_BD_WATER_1,
5358   EL_BD_WATER_2,
5359   EL_BD_WATER_3,
5360   EL_BD_WATER_4,
5361
5362   EL_BD_WATER_5,
5363   EL_BD_WATER_6,
5364   EL_BD_WATER_7,
5365   EL_BD_WATER_8,
5366
5367   EL_BD_WATER_9,
5368   EL_BD_WATER_10,
5369   EL_BD_WATER_11,
5370   EL_BD_WATER_12,
5371
5372   EL_BD_WATER_13,
5373   EL_BD_WATER_14,
5374   EL_BD_WATER_15,
5375   EL_BD_WATER_16,
5376
5377   EL_BD_BOMB_TICKING_1,
5378   EL_BD_BOMB_TICKING_2,
5379   EL_BD_BOMB_TICKING_3,
5380   EL_BD_BOMB_TICKING_4,
5381
5382   EL_BD_BOMB_TICKING_5,
5383   EL_BD_BOMB_TICKING_6,
5384   EL_BD_BOMB_TICKING_7,
5385   EL_EMPTY,
5386
5387   EL_BD_BOMB_EXPLODING_1,
5388   EL_BD_BOMB_EXPLODING_2,
5389   EL_BD_BOMB_EXPLODING_3,
5390   EL_BD_BOMB_EXPLODING_4,
5391
5392   EL_BD_NUT_BREAKING_1,
5393   EL_BD_NUT_BREAKING_2,
5394   EL_BD_NUT_BREAKING_3,
5395   EL_BD_NUT_BREAKING_4,
5396
5397   EL_BD_EXPLODING_1,
5398   EL_BD_EXPLODING_2,
5399   EL_BD_EXPLODING_3,
5400   EL_BD_EXPLODING_4,
5401
5402   EL_BD_EXPLODING_5,
5403   EL_BD_TIME_PENALTY,
5404   EL_BD_DIAMOND_GROWING_1,
5405   EL_BD_DIAMOND_GROWING_2,
5406
5407   EL_BD_DIAMOND_GROWING_3,
5408   EL_BD_DIAMOND_GROWING_4,
5409   EL_BD_DIAMOND_GROWING_5,
5410   EL_BD_NITRO_PACK_EXPLODING,
5411
5412   EL_BD_NITRO_PACK_EXPLODING_1,
5413   EL_BD_NITRO_PACK_EXPLODING_2,
5414   EL_BD_NITRO_PACK_EXPLODING_3,
5415   EL_BD_NITRO_PACK_EXPLODING_4,
5416
5417   EL_BD_ROCK_GROWING_1,
5418   EL_BD_ROCK_GROWING_2,
5419   EL_BD_ROCK_GROWING_3,
5420   EL_BD_ROCK_GROWING_4,
5421
5422   EL_BD_STEELWALL_GROWING_1,
5423   EL_BD_STEELWALL_GROWING_2,
5424   EL_BD_STEELWALL_GROWING_3,
5425   EL_BD_STEELWALL_GROWING_4,
5426
5427   EL_BD_CLOCK_GROWING_1,
5428   EL_BD_CLOCK_GROWING_2,
5429   EL_BD_CLOCK_GROWING_3,
5430   EL_BD_CLOCK_GROWING_4,
5431
5432   EL_BD_GHOST_EXPLODING_1,
5433   EL_BD_GHOST_EXPLODING_2,
5434   EL_BD_GHOST_EXPLODING_3,
5435   EL_BD_GHOST_EXPLODING_4,
5436 };
5437 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5438 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5439 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5440 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5441
5442 static int editor_hl_emerald_mine[] =
5443 {
5444   EL_INTERNAL_CASCADE_EM_ACTIVE,
5445   EL_CHAR('E'),
5446   EL_CHAR('M'),
5447   EL_EMPTY,
5448 };
5449
5450 static int editor_el_emerald_mine[] =
5451 {
5452   EL_SAND,
5453   EL_ROCK,
5454   EL_QUICKSAND_EMPTY,
5455   EL_QUICKSAND_FULL,
5456
5457   EL_STEELWALL,
5458   EL_WALL,
5459   EL_WALL_SLIPPERY,
5460   EL_MAGIC_WALL,
5461
5462   EL_EMERALD,
5463   EL_DIAMOND,
5464   EL_NUT,
5465   EL_BOMB,
5466
5467   EL_EM_DYNAMITE,
5468   EL_EM_DYNAMITE_ACTIVE,
5469   EL_EM_EXIT_CLOSED,
5470   EL_EM_EXIT_OPEN,
5471
5472   EL_YAMYAM_UP,
5473   EL_BUG_UP,
5474   EL_SPACESHIP_UP,
5475   EL_ROBOT,
5476
5477   EL_BUG_LEFT,
5478   EL_SPACESHIP_LEFT,
5479   EL_BUG_RIGHT,
5480   EL_SPACESHIP_RIGHT,
5481
5482   EL_ROBOT_WHEEL,
5483   EL_BUG_DOWN,
5484   EL_SPACESHIP_DOWN,
5485   EL_INVISIBLE_WALL,
5486
5487   EL_ACID_POOL_TOPLEFT,
5488   EL_ACID,
5489   EL_ACID_POOL_TOPRIGHT,
5490   EL_AMOEBA_DROP,
5491
5492   EL_ACID_POOL_BOTTOMLEFT,
5493   EL_ACID_POOL_BOTTOM,
5494   EL_ACID_POOL_BOTTOMRIGHT,
5495   EL_AMOEBA_WET,
5496
5497   EL_EM_KEY_1,
5498   EL_EM_KEY_2,
5499   EL_EM_KEY_3,
5500   EL_EM_KEY_4,
5501
5502   EL_EM_GATE_1,
5503   EL_EM_GATE_2,
5504   EL_EM_GATE_3,
5505   EL_EM_GATE_4,
5506
5507   EL_EM_GATE_1_GRAY,
5508   EL_EM_GATE_2_GRAY,
5509   EL_EM_GATE_3_GRAY,
5510   EL_EM_GATE_4_GRAY,
5511 };
5512 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5513 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5514 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5515 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5516
5517 static int editor_hl_emerald_mine_club[] =
5518 {
5519   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5520   EL_CHAR('E'),
5521   EL_CHAR('M'),
5522   EL_CHAR('C'),
5523 };
5524
5525 static int editor_el_emerald_mine_club[] =
5526 {
5527   EL_EMC_KEY_5,
5528   EL_EMC_KEY_6,
5529   EL_EMC_KEY_7,
5530   EL_EMC_KEY_8,
5531
5532   EL_EMC_GATE_5,
5533   EL_EMC_GATE_6,
5534   EL_EMC_GATE_7,
5535   EL_EMC_GATE_8,
5536
5537   EL_EMC_GATE_5_GRAY,
5538   EL_EMC_GATE_6_GRAY,
5539   EL_EMC_GATE_7_GRAY,
5540   EL_EMC_GATE_8_GRAY,
5541
5542   EL_EMC_STEELWALL_1,
5543   EL_EMC_STEELWALL_2,
5544   EL_EMC_STEELWALL_3,
5545   EL_EMC_STEELWALL_4,
5546
5547   EL_EMC_WALL_13,
5548   EL_EMC_WALL_14,
5549   EL_EMC_WALL_15,
5550   EL_EMC_WALL_16,
5551
5552   EL_EMC_WALL_SLIPPERY_1,
5553   EL_EMC_WALL_SLIPPERY_2,
5554   EL_EMC_WALL_SLIPPERY_3,
5555   EL_EMC_WALL_SLIPPERY_4,
5556
5557   EL_EMC_WALL_1,
5558   EL_EMC_WALL_2,
5559   EL_EMC_WALL_3,
5560   EL_EMC_WALL_4,
5561
5562   EL_EMC_WALL_5,
5563   EL_EMC_WALL_6,
5564   EL_EMC_WALL_7,
5565   EL_EMC_WALL_8,
5566
5567   EL_EMC_WALL_9,
5568   EL_EMC_WALL_10,
5569   EL_EMC_WALL_11,
5570   EL_EMC_WALL_12,
5571
5572   EL_EMC_GRASS,
5573   EL_EMC_FAKE_GRASS,
5574   EL_EMC_PLANT,
5575   EL_EMC_DRIPPER,
5576
5577   EL_EMC_MAGIC_BALL,
5578   EL_EMC_MAGIC_BALL_SWITCH,
5579   EL_EMC_LENSES,
5580   EL_EMC_MAGNIFIER,
5581
5582   EL_SPRING_LEFT,
5583   EL_SPRING,
5584   EL_SPRING_RIGHT,
5585   EL_EMC_SPRING_BUMPER,
5586
5587   EL_BALLOON,
5588   EL_YAMYAM_UP,
5589   EL_BALLOON_SWITCH_UP,
5590   EL_BALLOON_SWITCH_ANY,
5591
5592   EL_YAMYAM_LEFT,
5593   EL_BALLOON_SWITCH_LEFT,
5594   EL_YAMYAM_RIGHT,
5595   EL_BALLOON_SWITCH_RIGHT,
5596
5597   EL_EMC_ANDROID,
5598   EL_YAMYAM_DOWN,
5599   EL_BALLOON_SWITCH_DOWN,
5600   EL_BALLOON_SWITCH_NONE,
5601 };
5602 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5603 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5604 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5605 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5606
5607 static int editor_hl_rnd[] =
5608 {
5609   EL_INTERNAL_CASCADE_RND_ACTIVE,
5610   EL_CHAR('R'),
5611   EL_CHAR('N'),
5612   EL_CHAR('D'),
5613 };
5614
5615 static int editor_el_rnd[] =
5616 {
5617   EL_DYNAMITE,                  // RND
5618   EL_DYNAMITE_ACTIVE,           // RND
5619   EL_EMPTY,
5620   EL_EMPTY,
5621
5622   EL_KEY_1,
5623   EL_KEY_2,
5624   EL_KEY_3,
5625   EL_KEY_4,
5626
5627   EL_GATE_1,
5628   EL_GATE_2,
5629   EL_GATE_3,
5630   EL_GATE_4,
5631
5632   EL_GATE_1_GRAY,
5633   EL_GATE_2_GRAY,
5634   EL_GATE_3_GRAY,
5635   EL_GATE_4_GRAY,
5636
5637   EL_ARROW_LEFT,
5638   EL_ARROW_RIGHT,
5639   EL_ARROW_UP,
5640   EL_ARROW_DOWN,
5641
5642   EL_AMOEBA_DEAD,
5643   EL_AMOEBA_DRY,
5644   EL_AMOEBA_FULL,
5645   EL_GAME_OF_LIFE,
5646
5647   EL_EMERALD_YELLOW,
5648   EL_EMERALD_RED,
5649   EL_EMERALD_PURPLE,
5650   EL_BIOMAZE,
5651
5652   EL_WALL_EMERALD_YELLOW,
5653   EL_WALL_EMERALD_RED,
5654   EL_WALL_EMERALD_PURPLE,
5655   EL_WALL_BD_DIAMOND,
5656
5657   EL_SPEED_PILL,
5658   EL_PACMAN_UP,
5659   EL_TIME_ORB_FULL,
5660   EL_TIME_ORB_EMPTY,
5661
5662   EL_PACMAN_LEFT,
5663   EL_DARK_YAMYAM,
5664   EL_PACMAN_RIGHT,
5665   EL_YAMYAM,                    // RND
5666
5667   EL_BLACK_ORB,
5668   EL_PACMAN_DOWN,
5669   EL_LAMP,
5670   EL_LAMP_ACTIVE,
5671
5672   EL_DYNABOMB_INCREASE_NUMBER,
5673   EL_DYNABOMB_INCREASE_SIZE,
5674   EL_DYNABOMB_INCREASE_POWER,
5675   EL_STONEBLOCK,
5676
5677   EL_MOLE,
5678   EL_PENGUIN,
5679   EL_PIG,
5680   EL_DRAGON,
5681
5682   EL_BUG,
5683   EL_MOLE_UP,
5684   EL_BD_BUTTERFLY,
5685   EL_BD_FIREFLY,
5686
5687   EL_MOLE_LEFT,
5688   EL_SATELLITE,
5689   EL_MOLE_RIGHT,
5690   EL_PACMAN,
5691
5692   EL_SPACESHIP,
5693   EL_MOLE_DOWN,
5694   EL_INVISIBLE_STEELWALL,
5695   EL_INVISIBLE_WALL,
5696
5697   EL_EXPANDABLE_WALL,
5698   EL_EXPANDABLE_WALL_HORIZONTAL,
5699   EL_EXPANDABLE_WALL_VERTICAL,
5700   EL_EXPANDABLE_WALL_ANY,
5701 };
5702 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5703 static int *editor_el_rnd_ptr = editor_el_rnd;
5704 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5705 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5706
5707 static int editor_hl_sokoban[] =
5708 {
5709   EL_INTERNAL_CASCADE_SB_ACTIVE,
5710   EL_CHAR('S'),
5711   EL_CHAR('B'),
5712   EL_EMPTY,
5713 };
5714
5715 static int editor_el_sokoban[] =
5716 {
5717   EL_SOKOBAN_OBJECT,
5718   EL_SOKOBAN_FIELD_EMPTY,
5719   EL_SOKOBAN_FIELD_FULL,
5720   EL_SOKOBAN_FIELD_PLAYER,
5721 };
5722 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5723 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5724 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5725 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5726
5727 static int editor_hl_supaplex[] =
5728 {
5729   EL_INTERNAL_CASCADE_SP_ACTIVE,
5730   EL_CHAR('S'),
5731   EL_CHAR('P'),
5732   EL_EMPTY,
5733 };
5734
5735 static int editor_el_supaplex[] =
5736 {
5737   EL_SP_MURPHY,
5738   EL_EMPTY,
5739   EL_SP_BASE,
5740   EL_SP_BUGGY_BASE,
5741
5742   EL_SP_INFOTRON,
5743   EL_SP_ZONK,
5744   EL_SP_SNIKSNAK,
5745   EL_SP_ELECTRON,
5746
5747   EL_SP_DISK_RED,
5748   EL_SP_DISK_ORANGE,
5749   EL_SP_DISK_YELLOW,
5750   EL_SP_TERMINAL,
5751
5752   EL_SP_EXIT_CLOSED,
5753   EL_SP_PORT_HORIZONTAL,
5754   EL_SP_PORT_VERTICAL,
5755   EL_SP_PORT_ANY,
5756
5757   EL_SP_PORT_LEFT,
5758   EL_SP_PORT_RIGHT,
5759   EL_SP_PORT_UP,
5760   EL_SP_PORT_DOWN,
5761
5762   EL_SP_GRAVITY_PORT_LEFT,
5763   EL_SP_GRAVITY_PORT_RIGHT,
5764   EL_SP_GRAVITY_PORT_UP,
5765   EL_SP_GRAVITY_PORT_DOWN,
5766
5767   EL_SP_GRAVITY_ON_PORT_LEFT,
5768   EL_SP_GRAVITY_ON_PORT_RIGHT,
5769   EL_SP_GRAVITY_ON_PORT_UP,
5770   EL_SP_GRAVITY_ON_PORT_DOWN,
5771
5772   EL_SP_GRAVITY_OFF_PORT_LEFT,
5773   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5774   EL_SP_GRAVITY_OFF_PORT_UP,
5775   EL_SP_GRAVITY_OFF_PORT_DOWN,
5776
5777   EL_SP_HARDWARE_GRAY,
5778   EL_SP_HARDWARE_GREEN,
5779   EL_SP_HARDWARE_BLUE,
5780   EL_SP_HARDWARE_RED,
5781
5782   EL_SP_HARDWARE_BASE_1,
5783   EL_SP_HARDWARE_BASE_2,
5784   EL_SP_HARDWARE_BASE_3,
5785   EL_SP_HARDWARE_BASE_4,
5786
5787   EL_SP_HARDWARE_BASE_5,
5788   EL_SP_HARDWARE_BASE_6,
5789   EL_SP_HARDWARE_YELLOW,
5790   EL_SP_CHIP_TOP,
5791
5792   EL_SP_CHIP_SINGLE,
5793   EL_SP_CHIP_LEFT,
5794   EL_SP_CHIP_RIGHT,
5795   EL_SP_CHIP_BOTTOM,
5796 };
5797 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5798 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5799 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5800 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5801
5802 static int editor_hl_diamond_caves[] =
5803 {
5804   EL_INTERNAL_CASCADE_DC_ACTIVE,
5805   EL_CHAR('D'),
5806   EL_CHAR('C'),
5807   EL_CHAR('2'),
5808 };
5809
5810 static int editor_el_diamond_caves[] =
5811 {
5812   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5813   EL_EM_STEEL_EXIT_OPEN,        // DC2
5814   EL_WALL_EMERALD,              // DC2
5815   EL_WALL_DIAMOND,              // DC2
5816
5817   EL_PEARL,
5818   EL_CRYSTAL,
5819   EL_WALL_PEARL,
5820   EL_WALL_CRYSTAL,
5821
5822   EL_CONVEYOR_BELT_1_LEFT,
5823   EL_CONVEYOR_BELT_1_MIDDLE,
5824   EL_CONVEYOR_BELT_1_RIGHT,
5825   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5826
5827   EL_CONVEYOR_BELT_2_LEFT,
5828   EL_CONVEYOR_BELT_2_MIDDLE,
5829   EL_CONVEYOR_BELT_2_RIGHT,
5830   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5831
5832   EL_CONVEYOR_BELT_3_LEFT,
5833   EL_CONVEYOR_BELT_3_MIDDLE,
5834   EL_CONVEYOR_BELT_3_RIGHT,
5835   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5836
5837   EL_CONVEYOR_BELT_4_LEFT,
5838   EL_CONVEYOR_BELT_4_MIDDLE,
5839   EL_CONVEYOR_BELT_4_RIGHT,
5840   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5841
5842   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5843   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5844   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5845   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5846
5847   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5848   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5849   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5850   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5851
5852   EL_TIMEGATE_CLOSED,
5853   EL_TIMEGATE_OPEN,
5854   EL_TIMEGATE_SWITCH,
5855   EL_DC_TIMEGATE_SWITCH,
5856
5857   EL_SWITCHGATE_CLOSED,
5858   EL_SWITCHGATE_OPEN,
5859   EL_SWITCHGATE_SWITCH_UP,
5860   EL_SWITCHGATE_SWITCH_DOWN,
5861
5862   EL_LIGHT_SWITCH,
5863   EL_LIGHT_SWITCH_ACTIVE,
5864   EL_DC_SWITCHGATE_SWITCH_UP,
5865   EL_DC_SWITCHGATE_SWITCH_DOWN,
5866
5867   EL_STEEL_EXIT_CLOSED,
5868   EL_STEEL_EXIT_OPEN,
5869   EL_STEELWALL_SLIPPERY,
5870   EL_INVISIBLE_SAND,
5871
5872   EL_QUICKSAND_FAST_EMPTY,
5873   EL_QUICKSAND_FAST_FULL,
5874   EL_LANDMINE,
5875   EL_DC_LANDMINE,
5876
5877   EL_SHIELD_NORMAL,
5878   EL_SHIELD_DEADLY,
5879   EL_EXTRA_TIME,
5880   EL_DC_MAGIC_WALL,
5881
5882   EL_ENVELOPE_1,
5883   EL_ENVELOPE_2,
5884   EL_ENVELOPE_3,
5885   EL_ENVELOPE_4,
5886
5887   EL_SIGN_RADIOACTIVITY,
5888   EL_SIGN_WHEELCHAIR,
5889   EL_SIGN_PARKING,
5890   EL_SIGN_NO_ENTRY,
5891
5892   EL_SIGN_GIVE_WAY,
5893   EL_SIGN_ENTRY_FORBIDDEN,
5894   EL_SIGN_EMERGENCY_EXIT,
5895   EL_SIGN_YIN_YANG,
5896
5897 #if 0
5898   EL_SIGN_SPERMS,
5899   EL_SIGN_BULLET,
5900   EL_SIGN_HEART,
5901   EL_SIGN_CROSS,
5902
5903   EL_SIGN_FRANKIE,
5904   EL_EMPTY,
5905   EL_EMPTY,
5906   EL_EMPTY,
5907
5908   EL_SPERMS,
5909   EL_BULLET,
5910   EL_HEART,
5911   EL_CROSS,
5912
5913   EL_FRANKIE,
5914   EL_EMPTY,
5915   EL_EMPTY,
5916   EL_EMPTY,
5917 #endif
5918
5919   EL_DC_STEELWALL_2_SINGLE,
5920   EL_DC_STEELWALL_2_TOP,
5921   EL_SIGN_EXCLAMATION,
5922   EL_SIGN_STOP,
5923
5924   EL_DC_STEELWALL_2_LEFT,
5925   EL_DC_STEELWALL_2_MIDDLE,
5926   EL_DC_STEELWALL_2_HORIZONTAL,
5927   EL_DC_STEELWALL_2_RIGHT,
5928
5929   EL_DC_STEELWALL_1_TOPLEFT,
5930   EL_DC_STEELWALL_2_VERTICAL,
5931   EL_DC_STEELWALL_1_TOPRIGHT,
5932   EL_DC_GATE_WHITE,
5933
5934   EL_DC_STEELWALL_1_VERTICAL,
5935   EL_DC_STEELWALL_2_BOTTOM,
5936   EL_DC_KEY_WHITE,
5937   EL_DC_GATE_WHITE_GRAY,
5938
5939   EL_DC_STEELWALL_1_BOTTOMLEFT,
5940   EL_DC_STEELWALL_1_HORIZONTAL,
5941   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5942   EL_DC_GATE_FAKE_GRAY,
5943
5944   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5945   EL_DC_STEELWALL_1_BOTTOM,
5946   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5947   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5948
5949   EL_DC_STEELWALL_1_RIGHT,
5950   EL_EMPTY,
5951   EL_DC_STEELWALL_1_LEFT,
5952   EL_EXPANDABLE_STEELWALL_VERTICAL,
5953
5954   EL_DC_STEELWALL_1_TOPRIGHT_2,
5955   EL_DC_STEELWALL_1_TOP,
5956   EL_DC_STEELWALL_1_TOPLEFT_2,
5957   EL_EXPANDABLE_STEELWALL_ANY,
5958 };
5959 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5960 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5961 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5962 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5963
5964 static int editor_hl_dx_boulderdash[] =
5965 {
5966   EL_INTERNAL_CASCADE_DX_ACTIVE,
5967   EL_CHAR('D'),
5968   EL_CHAR('X'),
5969   EL_EMPTY,
5970 };
5971
5972 static int editor_el_dx_boulderdash[] =
5973 {
5974   EL_EMPTY,
5975   EL_TUBE_RIGHT_DOWN,
5976   EL_TUBE_HORIZONTAL_DOWN,
5977   EL_TUBE_LEFT_DOWN,
5978
5979   EL_TUBE_HORIZONTAL,
5980   EL_TUBE_VERTICAL_RIGHT,
5981   EL_TUBE_ANY,
5982   EL_TUBE_VERTICAL_LEFT,
5983
5984   EL_TUBE_VERTICAL,
5985   EL_TUBE_RIGHT_UP,
5986   EL_TUBE_HORIZONTAL_UP,
5987   EL_TUBE_LEFT_UP,
5988
5989   EL_TRAP,
5990   EL_DX_SUPABOMB,
5991   EL_EMPTY,
5992   EL_EMPTY
5993 };
5994 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
5995 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
5996 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
5997 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
5998
5999 static int editor_hl_mirror_magic[] =
6000 {
6001   EL_INTERNAL_CASCADE_MM_ACTIVE,
6002   EL_CHAR('M'),
6003   EL_CHAR('M'),
6004   EL_EMPTY,
6005 };
6006
6007 static int editor_el_mirror_magic[] =
6008 {
6009   EL_MM_MCDUFFIN_RIGHT,
6010   EL_MM_MCDUFFIN_UP,
6011   EL_MM_MCDUFFIN_LEFT,
6012   EL_MM_MCDUFFIN_DOWN,
6013
6014   EL_MM_MIRROR_START,
6015   EL_MM_MIRROR_FIXED_START,
6016   EL_MM_POLARIZER_START,
6017   EL_MM_POLARIZER_CROSS_START,
6018
6019   EL_MM_TELEPORTER_RED_START,
6020   EL_MM_TELEPORTER_YELLOW_START,
6021   EL_MM_TELEPORTER_GREEN_START,
6022   EL_MM_TELEPORTER_BLUE_START,
6023
6024   EL_MM_PRISM,
6025   EL_MM_FUSE_ACTIVE,
6026   EL_MM_PACMAN_RIGHT,
6027   EL_MM_EXIT_CLOSED,
6028
6029   EL_MM_KETTLE,
6030   EL_MM_BOMB,
6031   EL_MM_KEY,
6032   EL_MM_FUEL_FULL,
6033
6034   EL_MM_LIGHTBULB,
6035   EL_MM_LIGHTBULB_ACTIVE,
6036   EL_MM_GRAY_BALL,
6037   EL_MM_LIGHTBALL,
6038
6039   EL_MM_STEEL_WALL,
6040   EL_MM_WOODEN_WALL,
6041   EL_MM_ICE_WALL,
6042   EL_MM_AMOEBA_WALL,
6043
6044   EL_MM_STEEL_LOCK,
6045   EL_MM_WOODEN_LOCK,
6046   EL_MM_STEEL_BLOCK,
6047   EL_MM_WOODEN_BLOCK,
6048
6049   EL_MM_STEEL_GRID_FIXED_1,
6050   EL_MM_STEEL_GRID_FIXED_2,
6051   EL_MM_STEEL_GRID_FIXED_3,
6052   EL_MM_STEEL_GRID_FIXED_4,
6053
6054   EL_MM_WOODEN_GRID_FIXED_1,
6055   EL_MM_WOODEN_GRID_FIXED_2,
6056   EL_MM_WOODEN_GRID_FIXED_3,
6057   EL_MM_WOODEN_GRID_FIXED_4,
6058
6059   EL_MM_ENVELOPE_1,
6060   EL_MM_ENVELOPE_2,
6061   EL_MM_ENVELOPE_3,
6062   EL_MM_ENVELOPE_4
6063 };
6064 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
6065 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
6066 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
6067 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
6068
6069 static int editor_hl_deflektor[] =
6070 {
6071   EL_INTERNAL_CASCADE_DF_ACTIVE,
6072   EL_CHAR('D'),
6073   EL_CHAR('F'),
6074   EL_EMPTY,
6075 };
6076
6077 static int editor_el_deflektor[] =
6078 {
6079   EL_DF_LASER_RIGHT,
6080   EL_DF_LASER_UP,
6081   EL_DF_LASER_LEFT,
6082   EL_DF_LASER_DOWN,
6083
6084   EL_DF_RECEIVER_RIGHT,
6085   EL_DF_RECEIVER_UP,
6086   EL_DF_RECEIVER_LEFT,
6087   EL_DF_RECEIVER_DOWN,
6088
6089   EL_DF_MIRROR_START,
6090   EL_DF_MIRROR_ROTATING_START,
6091   EL_DF_MIRROR_FIXED_START,
6092   EL_DF_CELL,
6093
6094   EL_DF_FIBRE_OPTIC_RED_1,
6095   EL_DF_FIBRE_OPTIC_YELLOW_1,
6096   EL_DF_FIBRE_OPTIC_GREEN_1,
6097   EL_DF_FIBRE_OPTIC_BLUE_1,
6098
6099   EL_DF_STEEL_GRID_FIXED_START,
6100   EL_DF_STEEL_GRID_ROTATING_START,
6101   EL_DF_WOODEN_GRID_FIXED_START,
6102   EL_DF_WOODEN_GRID_ROTATING_START,
6103
6104   EL_DF_STEEL_WALL,
6105   EL_DF_WOODEN_WALL,
6106   EL_DF_REFRACTOR,
6107   EL_DF_MINE,
6108
6109   EL_DF_SLOPE_1,
6110   EL_DF_SLOPE_2,
6111   EL_DF_SLOPE_3,
6112   EL_DF_SLOPE_4
6113 };
6114 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
6115 static int *editor_el_deflektor_ptr = editor_el_deflektor;
6116 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
6117 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
6118
6119 static int editor_hl_chars[] =
6120 {
6121   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
6122   EL_CHAR('T'),
6123   EL_CHAR('X'),
6124   EL_CHAR('T'),
6125 };
6126
6127 static int editor_el_chars[] =
6128 {
6129   EL_CHAR(' '),
6130   EL_CHAR('!'),
6131   EL_CHAR('"'),
6132   EL_CHAR('#'),
6133
6134   EL_CHAR('$'),
6135   EL_CHAR('%'),
6136   EL_CHAR('&'),
6137   EL_CHAR('\''),
6138
6139   EL_CHAR('('),
6140   EL_CHAR(')'),
6141   EL_CHAR('*'),
6142   EL_CHAR('+'),
6143
6144   EL_CHAR(','),
6145   EL_CHAR('-'),
6146   EL_CHAR('.'),
6147   EL_CHAR('/'),
6148
6149   EL_CHAR('0'),
6150   EL_CHAR('1'),
6151   EL_CHAR('2'),
6152   EL_CHAR('3'),
6153
6154   EL_CHAR('4'),
6155   EL_CHAR('5'),
6156   EL_CHAR('6'),
6157   EL_CHAR('7'),
6158
6159   EL_CHAR('8'),
6160   EL_CHAR('9'),
6161   EL_CHAR(':'),
6162   EL_CHAR(';'),
6163
6164   EL_CHAR('<'),
6165   EL_CHAR('='),
6166   EL_CHAR('>'),
6167   EL_CHAR('?'),
6168
6169   EL_CHAR('@'),
6170   EL_CHAR('A'),
6171   EL_CHAR('B'),
6172   EL_CHAR('C'),
6173
6174   EL_CHAR('D'),
6175   EL_CHAR('E'),
6176   EL_CHAR('F'),
6177   EL_CHAR('G'),
6178
6179   EL_CHAR('H'),
6180   EL_CHAR('I'),
6181   EL_CHAR('J'),
6182   EL_CHAR('K'),
6183
6184   EL_CHAR('L'),
6185   EL_CHAR('M'),
6186   EL_CHAR('N'),
6187   EL_CHAR('O'),
6188
6189   EL_CHAR('P'),
6190   EL_CHAR('Q'),
6191   EL_CHAR('R'),
6192   EL_CHAR('S'),
6193
6194   EL_CHAR('T'),
6195   EL_CHAR('U'),
6196   EL_CHAR('V'),
6197   EL_CHAR('W'),
6198
6199   EL_CHAR('X'),
6200   EL_CHAR('Y'),
6201   EL_CHAR('Z'),
6202   EL_CHAR('['),
6203
6204   EL_CHAR('\\'),
6205   EL_CHAR(']'),
6206   EL_CHAR('^'),
6207   EL_CHAR('_'),
6208
6209   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6210   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6211   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6212   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6213
6214   EL_CHAR(CHAR_BYTE_DEGREE),
6215   EL_CHAR(CHAR_BYTE_REGISTERED),
6216   EL_CHAR(FONT_ASCII_CURSOR),
6217   EL_CHAR(FONT_ASCII_BUTTON),
6218
6219   EL_CHAR(FONT_ASCII_UP),
6220   EL_CHAR(FONT_ASCII_DOWN),
6221   EL_CHAR(' '),
6222   EL_CHAR(' ')
6223 };
6224 static int *editor_hl_chars_ptr = editor_hl_chars;
6225 static int *editor_el_chars_ptr = editor_el_chars;
6226 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6227 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6228
6229 static int editor_hl_steel_chars[] =
6230 {
6231   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6232   EL_STEEL_CHAR('T'),
6233   EL_STEEL_CHAR('X'),
6234   EL_STEEL_CHAR('T'),
6235 };
6236
6237 static int editor_el_steel_chars[] =
6238 {
6239   EL_STEEL_CHAR(' '),
6240   EL_STEEL_CHAR('!'),
6241   EL_STEEL_CHAR('"'),
6242   EL_STEEL_CHAR('#'),
6243
6244   EL_STEEL_CHAR('$'),
6245   EL_STEEL_CHAR('%'),
6246   EL_STEEL_CHAR('&'),
6247   EL_STEEL_CHAR('\''),
6248
6249   EL_STEEL_CHAR('('),
6250   EL_STEEL_CHAR(')'),
6251   EL_STEEL_CHAR('*'),
6252   EL_STEEL_CHAR('+'),
6253
6254   EL_STEEL_CHAR(','),
6255   EL_STEEL_CHAR('-'),
6256   EL_STEEL_CHAR('.'),
6257   EL_STEEL_CHAR('/'),
6258
6259   EL_STEEL_CHAR('0'),
6260   EL_STEEL_CHAR('1'),
6261   EL_STEEL_CHAR('2'),
6262   EL_STEEL_CHAR('3'),
6263
6264   EL_STEEL_CHAR('4'),
6265   EL_STEEL_CHAR('5'),
6266   EL_STEEL_CHAR('6'),
6267   EL_STEEL_CHAR('7'),
6268
6269   EL_STEEL_CHAR('8'),
6270   EL_STEEL_CHAR('9'),
6271   EL_STEEL_CHAR(':'),
6272   EL_STEEL_CHAR(';'),
6273
6274   EL_STEEL_CHAR('<'),
6275   EL_STEEL_CHAR('='),
6276   EL_STEEL_CHAR('>'),
6277   EL_STEEL_CHAR('?'),
6278
6279   EL_STEEL_CHAR('@'),
6280   EL_STEEL_CHAR('A'),
6281   EL_STEEL_CHAR('B'),
6282   EL_STEEL_CHAR('C'),
6283
6284   EL_STEEL_CHAR('D'),
6285   EL_STEEL_CHAR('E'),
6286   EL_STEEL_CHAR('F'),
6287   EL_STEEL_CHAR('G'),
6288
6289   EL_STEEL_CHAR('H'),
6290   EL_STEEL_CHAR('I'),
6291   EL_STEEL_CHAR('J'),
6292   EL_STEEL_CHAR('K'),
6293
6294   EL_STEEL_CHAR('L'),
6295   EL_STEEL_CHAR('M'),
6296   EL_STEEL_CHAR('N'),
6297   EL_STEEL_CHAR('O'),
6298
6299   EL_STEEL_CHAR('P'),
6300   EL_STEEL_CHAR('Q'),
6301   EL_STEEL_CHAR('R'),
6302   EL_STEEL_CHAR('S'),
6303
6304   EL_STEEL_CHAR('T'),
6305   EL_STEEL_CHAR('U'),
6306   EL_STEEL_CHAR('V'),
6307   EL_STEEL_CHAR('W'),
6308
6309   EL_STEEL_CHAR('X'),
6310   EL_STEEL_CHAR('Y'),
6311   EL_STEEL_CHAR('Z'),
6312   EL_STEEL_CHAR('['),
6313
6314   EL_STEEL_CHAR('\\'),
6315   EL_STEEL_CHAR(']'),
6316   EL_STEEL_CHAR('^'),
6317   EL_STEEL_CHAR('_'),
6318
6319   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6320   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6321   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6322   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6323
6324   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6325   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6326   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6327   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6328
6329   EL_STEEL_CHAR(FONT_ASCII_UP),
6330   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6331   EL_STEEL_CHAR(' '),
6332   EL_STEEL_CHAR(' ')
6333 };
6334 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6335 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6336 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6337 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6338
6339 static int editor_hl_custom[] =
6340 {
6341   EL_INTERNAL_CASCADE_CE_ACTIVE,
6342   EL_CHAR('C'),
6343   EL_CHAR('E'),
6344   EL_EMPTY,
6345 };
6346
6347 static int editor_el_custom[] =
6348 {
6349   EL_CUSTOM_START + 0,
6350   EL_CUSTOM_START + 1,
6351   EL_CUSTOM_START + 2,
6352   EL_CUSTOM_START + 3,
6353
6354   EL_CUSTOM_START + 4,
6355   EL_CUSTOM_START + 5,
6356   EL_CUSTOM_START + 6,
6357   EL_CUSTOM_START + 7,
6358
6359   EL_CUSTOM_START + 8,
6360   EL_CUSTOM_START + 9,
6361   EL_CUSTOM_START + 10,
6362   EL_CUSTOM_START + 11,
6363
6364   EL_CUSTOM_START + 12,
6365   EL_CUSTOM_START + 13,
6366   EL_CUSTOM_START + 14,
6367   EL_CUSTOM_START + 15,
6368
6369   EL_CUSTOM_START + 16,
6370   EL_CUSTOM_START + 17,
6371   EL_CUSTOM_START + 18,
6372   EL_CUSTOM_START + 19,
6373
6374   EL_CUSTOM_START + 20,
6375   EL_CUSTOM_START + 21,
6376   EL_CUSTOM_START + 22,
6377   EL_CUSTOM_START + 23,
6378
6379   EL_CUSTOM_START + 24,
6380   EL_CUSTOM_START + 25,
6381   EL_CUSTOM_START + 26,
6382   EL_CUSTOM_START + 27,
6383
6384   EL_CUSTOM_START + 28,
6385   EL_CUSTOM_START + 29,
6386   EL_CUSTOM_START + 30,
6387   EL_CUSTOM_START + 31,
6388
6389   EL_CUSTOM_START + 32,
6390   EL_CUSTOM_START + 33,
6391   EL_CUSTOM_START + 34,
6392   EL_CUSTOM_START + 35,
6393
6394   EL_CUSTOM_START + 36,
6395   EL_CUSTOM_START + 37,
6396   EL_CUSTOM_START + 38,
6397   EL_CUSTOM_START + 39,
6398
6399   EL_CUSTOM_START + 40,
6400   EL_CUSTOM_START + 41,
6401   EL_CUSTOM_START + 42,
6402   EL_CUSTOM_START + 43,
6403
6404   EL_CUSTOM_START + 44,
6405   EL_CUSTOM_START + 45,
6406   EL_CUSTOM_START + 46,
6407   EL_CUSTOM_START + 47,
6408
6409   EL_CUSTOM_START + 48,
6410   EL_CUSTOM_START + 49,
6411   EL_CUSTOM_START + 50,
6412   EL_CUSTOM_START + 51,
6413
6414   EL_CUSTOM_START + 52,
6415   EL_CUSTOM_START + 53,
6416   EL_CUSTOM_START + 54,
6417   EL_CUSTOM_START + 55,
6418
6419   EL_CUSTOM_START + 56,
6420   EL_CUSTOM_START + 57,
6421   EL_CUSTOM_START + 58,
6422   EL_CUSTOM_START + 59,
6423
6424   EL_CUSTOM_START + 60,
6425   EL_CUSTOM_START + 61,
6426   EL_CUSTOM_START + 62,
6427   EL_CUSTOM_START + 63,
6428
6429   EL_CUSTOM_START + 64,
6430   EL_CUSTOM_START + 65,
6431   EL_CUSTOM_START + 66,
6432   EL_CUSTOM_START + 67,
6433
6434   EL_CUSTOM_START + 68,
6435   EL_CUSTOM_START + 69,
6436   EL_CUSTOM_START + 70,
6437   EL_CUSTOM_START + 71,
6438
6439   EL_CUSTOM_START + 72,
6440   EL_CUSTOM_START + 73,
6441   EL_CUSTOM_START + 74,
6442   EL_CUSTOM_START + 75,
6443
6444   EL_CUSTOM_START + 76,
6445   EL_CUSTOM_START + 77,
6446   EL_CUSTOM_START + 78,
6447   EL_CUSTOM_START + 79,
6448
6449   EL_CUSTOM_START + 80,
6450   EL_CUSTOM_START + 81,
6451   EL_CUSTOM_START + 82,
6452   EL_CUSTOM_START + 83,
6453
6454   EL_CUSTOM_START + 84,
6455   EL_CUSTOM_START + 85,
6456   EL_CUSTOM_START + 86,
6457   EL_CUSTOM_START + 87,
6458
6459   EL_CUSTOM_START + 88,
6460   EL_CUSTOM_START + 89,
6461   EL_CUSTOM_START + 90,
6462   EL_CUSTOM_START + 91,
6463
6464   EL_CUSTOM_START + 92,
6465   EL_CUSTOM_START + 93,
6466   EL_CUSTOM_START + 94,
6467   EL_CUSTOM_START + 95,
6468
6469   EL_CUSTOM_START + 96,
6470   EL_CUSTOM_START + 97,
6471   EL_CUSTOM_START + 98,
6472   EL_CUSTOM_START + 99,
6473
6474   EL_CUSTOM_START + 100,
6475   EL_CUSTOM_START + 101,
6476   EL_CUSTOM_START + 102,
6477   EL_CUSTOM_START + 103,
6478
6479   EL_CUSTOM_START + 104,
6480   EL_CUSTOM_START + 105,
6481   EL_CUSTOM_START + 106,
6482   EL_CUSTOM_START + 107,
6483
6484   EL_CUSTOM_START + 108,
6485   EL_CUSTOM_START + 109,
6486   EL_CUSTOM_START + 110,
6487   EL_CUSTOM_START + 111,
6488
6489   EL_CUSTOM_START + 112,
6490   EL_CUSTOM_START + 113,
6491   EL_CUSTOM_START + 114,
6492   EL_CUSTOM_START + 115,
6493
6494   EL_CUSTOM_START + 116,
6495   EL_CUSTOM_START + 117,
6496   EL_CUSTOM_START + 118,
6497   EL_CUSTOM_START + 119,
6498
6499   EL_CUSTOM_START + 120,
6500   EL_CUSTOM_START + 121,
6501   EL_CUSTOM_START + 122,
6502   EL_CUSTOM_START + 123,
6503
6504   EL_CUSTOM_START + 124,
6505   EL_CUSTOM_START + 125,
6506   EL_CUSTOM_START + 126,
6507   EL_CUSTOM_START + 127,
6508
6509   EL_CUSTOM_START + 128,
6510   EL_CUSTOM_START + 129,
6511   EL_CUSTOM_START + 130,
6512   EL_CUSTOM_START + 131,
6513
6514   EL_CUSTOM_START + 132,
6515   EL_CUSTOM_START + 133,
6516   EL_CUSTOM_START + 134,
6517   EL_CUSTOM_START + 135,
6518
6519   EL_CUSTOM_START + 136,
6520   EL_CUSTOM_START + 137,
6521   EL_CUSTOM_START + 138,
6522   EL_CUSTOM_START + 139,
6523
6524   EL_CUSTOM_START + 140,
6525   EL_CUSTOM_START + 141,
6526   EL_CUSTOM_START + 142,
6527   EL_CUSTOM_START + 143,
6528
6529   EL_CUSTOM_START + 144,
6530   EL_CUSTOM_START + 145,
6531   EL_CUSTOM_START + 146,
6532   EL_CUSTOM_START + 147,
6533
6534   EL_CUSTOM_START + 148,
6535   EL_CUSTOM_START + 149,
6536   EL_CUSTOM_START + 150,
6537   EL_CUSTOM_START + 151,
6538
6539   EL_CUSTOM_START + 152,
6540   EL_CUSTOM_START + 153,
6541   EL_CUSTOM_START + 154,
6542   EL_CUSTOM_START + 155,
6543
6544   EL_CUSTOM_START + 156,
6545   EL_CUSTOM_START + 157,
6546   EL_CUSTOM_START + 158,
6547   EL_CUSTOM_START + 159,
6548
6549   EL_CUSTOM_START + 160,
6550   EL_CUSTOM_START + 161,
6551   EL_CUSTOM_START + 162,
6552   EL_CUSTOM_START + 163,
6553
6554   EL_CUSTOM_START + 164,
6555   EL_CUSTOM_START + 165,
6556   EL_CUSTOM_START + 166,
6557   EL_CUSTOM_START + 167,
6558
6559   EL_CUSTOM_START + 168,
6560   EL_CUSTOM_START + 169,
6561   EL_CUSTOM_START + 170,
6562   EL_CUSTOM_START + 171,
6563
6564   EL_CUSTOM_START + 172,
6565   EL_CUSTOM_START + 173,
6566   EL_CUSTOM_START + 174,
6567   EL_CUSTOM_START + 175,
6568
6569   EL_CUSTOM_START + 176,
6570   EL_CUSTOM_START + 177,
6571   EL_CUSTOM_START + 178,
6572   EL_CUSTOM_START + 179,
6573
6574   EL_CUSTOM_START + 180,
6575   EL_CUSTOM_START + 181,
6576   EL_CUSTOM_START + 182,
6577   EL_CUSTOM_START + 183,
6578
6579   EL_CUSTOM_START + 184,
6580   EL_CUSTOM_START + 185,
6581   EL_CUSTOM_START + 186,
6582   EL_CUSTOM_START + 187,
6583
6584   EL_CUSTOM_START + 188,
6585   EL_CUSTOM_START + 189,
6586   EL_CUSTOM_START + 190,
6587   EL_CUSTOM_START + 191,
6588
6589   EL_CUSTOM_START + 192,
6590   EL_CUSTOM_START + 193,
6591   EL_CUSTOM_START + 194,
6592   EL_CUSTOM_START + 195,
6593
6594   EL_CUSTOM_START + 196,
6595   EL_CUSTOM_START + 197,
6596   EL_CUSTOM_START + 198,
6597   EL_CUSTOM_START + 199,
6598
6599   EL_CUSTOM_START + 200,
6600   EL_CUSTOM_START + 201,
6601   EL_CUSTOM_START + 202,
6602   EL_CUSTOM_START + 203,
6603
6604   EL_CUSTOM_START + 204,
6605   EL_CUSTOM_START + 205,
6606   EL_CUSTOM_START + 206,
6607   EL_CUSTOM_START + 207,
6608
6609   EL_CUSTOM_START + 208,
6610   EL_CUSTOM_START + 209,
6611   EL_CUSTOM_START + 210,
6612   EL_CUSTOM_START + 211,
6613
6614   EL_CUSTOM_START + 212,
6615   EL_CUSTOM_START + 213,
6616   EL_CUSTOM_START + 214,
6617   EL_CUSTOM_START + 215,
6618
6619   EL_CUSTOM_START + 216,
6620   EL_CUSTOM_START + 217,
6621   EL_CUSTOM_START + 218,
6622   EL_CUSTOM_START + 219,
6623
6624   EL_CUSTOM_START + 220,
6625   EL_CUSTOM_START + 221,
6626   EL_CUSTOM_START + 222,
6627   EL_CUSTOM_START + 223,
6628
6629   EL_CUSTOM_START + 224,
6630   EL_CUSTOM_START + 225,
6631   EL_CUSTOM_START + 226,
6632   EL_CUSTOM_START + 227,
6633
6634   EL_CUSTOM_START + 228,
6635   EL_CUSTOM_START + 229,
6636   EL_CUSTOM_START + 230,
6637   EL_CUSTOM_START + 231,
6638
6639   EL_CUSTOM_START + 232,
6640   EL_CUSTOM_START + 233,
6641   EL_CUSTOM_START + 234,
6642   EL_CUSTOM_START + 235,
6643
6644   EL_CUSTOM_START + 236,
6645   EL_CUSTOM_START + 237,
6646   EL_CUSTOM_START + 238,
6647   EL_CUSTOM_START + 239,
6648
6649   EL_CUSTOM_START + 240,
6650   EL_CUSTOM_START + 241,
6651   EL_CUSTOM_START + 242,
6652   EL_CUSTOM_START + 243,
6653
6654   EL_CUSTOM_START + 244,
6655   EL_CUSTOM_START + 245,
6656   EL_CUSTOM_START + 246,
6657   EL_CUSTOM_START + 247,
6658
6659   EL_CUSTOM_START + 248,
6660   EL_CUSTOM_START + 249,
6661   EL_CUSTOM_START + 250,
6662   EL_CUSTOM_START + 251,
6663
6664   EL_CUSTOM_START + 252,
6665   EL_CUSTOM_START + 253,
6666   EL_CUSTOM_START + 254,
6667   EL_CUSTOM_START + 255
6668 };
6669 static int *editor_hl_custom_ptr = editor_hl_custom;
6670 static int *editor_el_custom_ptr = editor_el_custom;
6671 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6672 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6673
6674 static int editor_hl_group[] =
6675 {
6676   EL_INTERNAL_CASCADE_GE_ACTIVE,
6677   EL_CHAR('G'),
6678   EL_CHAR('E'),
6679   EL_EMPTY,
6680 };
6681
6682 static int editor_el_group[] =
6683 {
6684   EL_GROUP_START + 0,
6685   EL_GROUP_START + 1,
6686   EL_GROUP_START + 2,
6687   EL_GROUP_START + 3,
6688
6689   EL_GROUP_START + 4,
6690   EL_GROUP_START + 5,
6691   EL_GROUP_START + 6,
6692   EL_GROUP_START + 7,
6693
6694   EL_GROUP_START + 8,
6695   EL_GROUP_START + 9,
6696   EL_GROUP_START + 10,
6697   EL_GROUP_START + 11,
6698
6699   EL_GROUP_START + 12,
6700   EL_GROUP_START + 13,
6701   EL_GROUP_START + 14,
6702   EL_GROUP_START + 15,
6703
6704   EL_GROUP_START + 16,
6705   EL_GROUP_START + 17,
6706   EL_GROUP_START + 18,
6707   EL_GROUP_START + 19,
6708
6709   EL_GROUP_START + 20,
6710   EL_GROUP_START + 21,
6711   EL_GROUP_START + 22,
6712   EL_GROUP_START + 23,
6713
6714   EL_GROUP_START + 24,
6715   EL_GROUP_START + 25,
6716   EL_GROUP_START + 26,
6717   EL_GROUP_START + 27,
6718
6719   EL_GROUP_START + 28,
6720   EL_GROUP_START + 29,
6721   EL_GROUP_START + 30,
6722   EL_GROUP_START + 31
6723 };
6724 static int *editor_hl_group_ptr = editor_hl_group;
6725 static int *editor_el_group_ptr = editor_el_group;
6726 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6727 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6728
6729 static int editor_hl_empty_space[] =
6730 {
6731   EL_INTERNAL_CASCADE_ES_ACTIVE,
6732   EL_CHAR('E'),
6733   EL_CHAR('S'),
6734   EL_EMPTY,
6735 };
6736
6737 static int editor_el_empty_space[] =
6738 {
6739   EL_EMPTY_SPACE_1,
6740   EL_EMPTY_SPACE_2,
6741   EL_EMPTY_SPACE_3,
6742   EL_EMPTY_SPACE_4,
6743
6744   EL_EMPTY_SPACE_5,
6745   EL_EMPTY_SPACE_6,
6746   EL_EMPTY_SPACE_7,
6747   EL_EMPTY_SPACE_8,
6748
6749   EL_EMPTY_SPACE_9,
6750   EL_EMPTY_SPACE_10,
6751   EL_EMPTY_SPACE_11,
6752   EL_EMPTY_SPACE_12,
6753
6754   EL_EMPTY_SPACE_13,
6755   EL_EMPTY_SPACE_14,
6756   EL_EMPTY_SPACE_15,
6757   EL_EMPTY_SPACE_16
6758 };
6759 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6760 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6761 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6762 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6763
6764 static int editor_hl_reference[] =
6765 {
6766   EL_INTERNAL_CASCADE_REF_ACTIVE,
6767   EL_CHAR('R'),
6768   EL_CHAR('E'),
6769   EL_CHAR('F')
6770 };
6771
6772 static int editor_el_reference[] =
6773 {
6774   EL_TRIGGER_PLAYER,
6775   EL_TRIGGER_ELEMENT,
6776   EL_TRIGGER_CE_VALUE,
6777   EL_TRIGGER_CE_SCORE,
6778
6779   EL_SELF,
6780   EL_ANY_ELEMENT,
6781   EL_CURRENT_CE_VALUE,
6782   EL_CURRENT_CE_SCORE,
6783
6784   EL_PREV_CE_8,
6785   EL_PREV_CE_7,
6786   EL_PREV_CE_6,
6787   EL_PREV_CE_5,
6788
6789   EL_PREV_CE_4,
6790   EL_PREV_CE_3,
6791   EL_PREV_CE_2,
6792   EL_PREV_CE_1,
6793
6794   EL_NEXT_CE_1,
6795   EL_NEXT_CE_2,
6796   EL_NEXT_CE_3,
6797   EL_NEXT_CE_4,
6798
6799   EL_NEXT_CE_5,
6800   EL_NEXT_CE_6,
6801   EL_NEXT_CE_7,
6802   EL_NEXT_CE_8,
6803 };
6804 static int *editor_hl_reference_ptr = editor_hl_reference;
6805 static int *editor_el_reference_ptr = editor_el_reference;
6806 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6807 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6808
6809 static int editor_hl_user_defined[] =
6810 {
6811   EL_INTERNAL_CASCADE_USER_ACTIVE,
6812   EL_CHAR('M'),
6813   EL_CHAR('Y'),
6814   EL_EMPTY,
6815 };
6816
6817 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6818 static int *editor_el_user_defined_ptr = NULL;
6819 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6820 static int num_editor_el_user_defined = 0;
6821
6822 static int editor_hl_dynamic[] =
6823 {
6824   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6825   EL_CHAR('U'),
6826   EL_CHAR('S'),
6827   EL_CHAR('E'),
6828 };
6829
6830 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6831 static int *editor_el_dynamic_ptr = NULL;
6832 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6833 static int num_editor_el_dynamic = 0;
6834
6835 static int editor_hl_empty[] = { EL_EMPTY };
6836 static int *editor_el_empty = NULL;     // dynamically allocated
6837
6838 static int *editor_hl_empty_ptr = editor_hl_empty;
6839 static int *editor_el_empty_ptr = NULL;
6840 static int num_editor_hl_empty = 0;
6841 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6842
6843 static boolean use_el_empty = FALSE;
6844
6845 static int *editor_elements = NULL;     // dynamically allocated
6846 static int num_editor_elements = 0;     // dynamically determined
6847
6848 static boolean setup_editor_cascade_never = FALSE;
6849
6850 static boolean setup_editor_el_players                  = TRUE;
6851 static boolean setup_editor_el_boulderdash              = TRUE;
6852 static boolean setup_editor_el_boulderdash_native       = TRUE;
6853 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6854 static boolean setup_editor_el_emerald_mine             = TRUE;
6855 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6856 static boolean setup_editor_el_more                     = TRUE;
6857 static boolean setup_editor_el_sokoban                  = TRUE;
6858 static boolean setup_editor_el_supaplex                 = TRUE;
6859 static boolean setup_editor_el_diamond_caves            = TRUE;
6860 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6861 static boolean setup_editor_el_mirror_magic             = TRUE;
6862 static boolean setup_editor_el_deflektor                = TRUE;
6863 static boolean setup_editor_el_chars                    = TRUE;
6864 static boolean setup_editor_el_steel_chars              = TRUE;
6865 static boolean setup_editor_el_custom                   = TRUE;
6866 static boolean setup_editor_el_user_defined             = TRUE;
6867 static boolean setup_editor_el_dynamic                  = TRUE;
6868
6869 static int editor_hl_unused[] = { EL_EMPTY };
6870 static int *editor_hl_unused_ptr = editor_hl_unused;
6871 static int num_editor_hl_unused = 0;
6872
6873 static struct
6874 {
6875   boolean *setup_value;
6876   boolean *setup_cascade_value;
6877
6878   int **headline_list;
6879   int *headline_list_size;
6880
6881   int **element_list;
6882   int *element_list_size;
6883
6884   boolean last_setup_value;
6885 }
6886 editor_elements_info[] =
6887 {
6888   {
6889     &setup_editor_el_players,
6890     &setup_editor_cascade_never,
6891     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6892     &editor_el_players_ptr,             &num_editor_el_players
6893   },
6894   {
6895     &setup_editor_el_boulderdash,
6896     &setup.editor_cascade.el_bd,
6897     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6898     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6899   },
6900   {
6901     &setup_editor_el_boulderdash_native,
6902     &setup.editor_cascade.el_bd_native,
6903     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6904     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6905   },
6906   {
6907     &setup_editor_el_boulderdash_effects,
6908     &setup.editor_cascade.el_bd_effects,
6909     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6910     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6911   },
6912   {
6913     &setup_editor_el_emerald_mine,
6914     &setup.editor_cascade.el_em,
6915     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6916     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6917   },
6918   {
6919     &setup_editor_el_emerald_mine_club,
6920     &setup.editor_cascade.el_emc,
6921     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6922     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6923   },
6924   {
6925     &setup_editor_el_more,
6926     &setup.editor_cascade.el_rnd,
6927     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6928     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6929   },
6930   {
6931     &setup_editor_el_sokoban,
6932     &setup.editor_cascade.el_sb,
6933     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6934     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6935   },
6936   {
6937     &setup_editor_el_supaplex,
6938     &setup.editor_cascade.el_sp,
6939     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6940     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6941   },
6942   {
6943     &setup_editor_el_diamond_caves,
6944     &setup.editor_cascade.el_dc,
6945     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6946     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6947   },
6948   {
6949     &setup_editor_el_dx_boulderdash,
6950     &setup.editor_cascade.el_dx,
6951     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6952     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6953   },
6954   {
6955     &setup_editor_el_mirror_magic,
6956     &setup.editor_cascade.el_mm,
6957     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6958     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6959   },
6960   {
6961     &setup_editor_el_deflektor,
6962     &setup.editor_cascade.el_df,
6963     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6964     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6965   },
6966   {
6967     &setup_editor_el_chars,
6968     &setup.editor_cascade.el_chars,
6969     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6970     &editor_el_chars_ptr,               &num_editor_el_chars
6971   },
6972   {
6973     &setup_editor_el_steel_chars,
6974     &setup.editor_cascade.el_steel_chars,
6975     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6976     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6977   },
6978   {
6979     &setup_editor_el_custom,
6980     &setup.editor_cascade.el_ce,
6981     &editor_hl_custom_ptr,              &num_editor_hl_custom,
6982     &editor_el_custom_ptr,              &num_editor_el_custom
6983   },
6984   {
6985     &setup_editor_el_custom,
6986     &setup.editor_cascade.el_ge,
6987     &editor_hl_group_ptr,               &num_editor_hl_group,
6988     &editor_el_group_ptr,               &num_editor_el_group
6989   },
6990   {
6991     &setup_editor_el_custom,
6992     &setup.editor_cascade.el_es,
6993     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
6994     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
6995   },
6996   {
6997     &setup_editor_el_custom,
6998     &setup.editor_cascade.el_ref,
6999     &editor_hl_reference_ptr,           &num_editor_hl_reference,
7000     &editor_el_reference_ptr,           &num_editor_el_reference
7001   },
7002   {
7003     &setup_editor_el_user_defined,
7004     &setup.editor_cascade.el_user,
7005     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
7006     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
7007   },
7008   {
7009     &setup_editor_el_dynamic,
7010     &setup.editor_cascade.el_dynamic,
7011     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
7012     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
7013   },
7014   {
7015     &use_el_empty,
7016     &use_el_empty,
7017     &editor_hl_empty_ptr,               &num_editor_hl_empty,
7018     &editor_el_empty_ptr,               &num_editor_el_empty,
7019   },
7020   {
7021     NULL,
7022     NULL,
7023     NULL,                               NULL,
7024     NULL,                               NULL
7025   }
7026 };
7027
7028 static struct XY xy_directions[] =
7029 {
7030   { -1,  0 },
7031   { +1,  0 },
7032   {  0, -1 },
7033   {  0, +1 }
7034 };
7035
7036
7037 // ----------------------------------------------------------------------------
7038 // functions
7039 // ----------------------------------------------------------------------------
7040
7041 static int getMaxInfoTextLength(void)
7042 {
7043   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
7044 }
7045
7046 static int getTextWidthForGadget(char *text)
7047 {
7048   if (text == NULL)
7049     return 0;
7050
7051   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
7052 }
7053
7054 static int getTextWidthForDrawingArea(char *text)
7055 {
7056   if (text == NULL)
7057     return 0;
7058
7059   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
7060 }
7061
7062 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
7063 {
7064   return (gi->x + gi->width + getTextWidthForGadget(text));
7065 }
7066
7067 static char *getElementInfoText(int element)
7068 {
7069   char *info_text = NULL;
7070
7071   if (element < MAX_NUM_ELEMENTS)
7072   {
7073     if (strlen(element_info[element].description) > 0)
7074       info_text = element_info[element].description;
7075     else if (element_info[element].custom_description != NULL)
7076       info_text = element_info[element].custom_description;
7077     else if (element_info[element].editor_description != NULL)
7078       info_text = element_info[element].editor_description;
7079   }
7080
7081   if (info_text == NULL)
7082     info_text = INFOTEXT_UNKNOWN_ELEMENT;
7083
7084   return info_text;
7085 }
7086
7087 static char *getElementDescriptionFilenameExt(char *basename)
7088 {
7089   char *elements_subdir = ELEMENTS_DIRECTORY;
7090   static char *elements_subdir2 = NULL;
7091   static char *filename = NULL;
7092
7093   if (elements_subdir2 == NULL)
7094     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
7095
7096   checked_free(filename);
7097
7098   // 1st try: look for element description in current level set directory
7099   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
7100   if (fileExists(filename))
7101     return filename;
7102
7103   free(filename);
7104
7105   // 2nd try: look for element description in the game's base directory
7106   filename = getPath3(options.docs_directory, elements_subdir, basename);
7107   if (fileExists(filename))
7108     return filename;
7109
7110   return NULL;
7111 }
7112
7113 static char *getElementDescriptionFilename(int element)
7114 {
7115   char basename[MAX_FILENAME_LEN];
7116   char *filename;
7117
7118   // 1st try: look for element description file for exactly this element
7119   sprintf(basename, "%s.txt", element_info[element].token_name);
7120   filename = getElementDescriptionFilenameExt(basename);
7121   if (filename != NULL)
7122     return filename;
7123
7124   // 2nd try: look for element description file for this element's class
7125   sprintf(basename, "%s.txt", element_info[element].class_name);
7126   filename = getElementDescriptionFilenameExt(basename);
7127   if (filename != NULL)
7128     return filename;
7129
7130   // 3rd try: look for generic fallback text file for any element
7131   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
7132   if (filename != NULL)
7133     return filename;
7134
7135   return NULL;
7136 }
7137
7138 static boolean suppressBorderElement(void)
7139 {
7140   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
7141           lev_fieldx <= MAX_ED_FIELDX &&
7142           lev_fieldy <= MAX_ED_FIELDY);
7143 }
7144
7145 static void InitDynamicEditorElementList(int **elements, int *num_elements)
7146 {
7147   boolean element_found[NUM_FILE_ELEMENTS];
7148   int i, x, y;
7149
7150   // initialize list of used elements to "not used"
7151   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7152     element_found[i] = FALSE;
7153
7154   // find all elements used in current level
7155   for (y = 0; y < lev_fieldy; y++)
7156   {
7157     for (x = 0; x < lev_fieldx; x++)
7158     {
7159       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
7160         continue;
7161
7162       if (IS_MM_WALL(Tile[x][y]))
7163         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
7164       else
7165         element_found[Tile[x][y]] = TRUE;
7166     }
7167   }
7168
7169   *num_elements = 0;
7170
7171   // count number of elements used in current level
7172   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7173     if (element_found[i])
7174       (*num_elements)++;
7175
7176   // add space for up to 3 more elements for padding that may be needed
7177   *num_elements += 3;
7178
7179   // free memory for old list of elements, if needed
7180   checked_free(*elements);
7181
7182   // allocate memory for new list of elements
7183   *elements = checked_malloc(*num_elements * sizeof(int));
7184
7185   *num_elements = 0;
7186
7187   // add all elements used in current level (non-custom/group/empty elements)
7188   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7189     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
7190                               IS_GROUP_ELEMENT(i) ||
7191                               IS_EMPTY_ELEMENT(i)))
7192       (*elements)[(*num_elements)++] = i;
7193
7194   // add all elements used in current level (custom/group/empty elements)
7195   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7196     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
7197                              IS_GROUP_ELEMENT(i) ||
7198                              IS_EMPTY_ELEMENT(i)))
7199       (*elements)[(*num_elements)++] = i;
7200
7201   while (*num_elements % 4)     // pad with empty elements, if needed
7202     (*elements)[(*num_elements)++] = EL_EMPTY;
7203 }
7204
7205 static void ReinitializeElementList_EnableSections(void)
7206 {
7207   // default: enable all element sections
7208
7209   setup_editor_el_players               = TRUE;
7210   setup_editor_el_boulderdash           = TRUE;
7211   setup_editor_el_boulderdash_native    = TRUE;
7212   setup_editor_el_boulderdash_effects   = TRUE;
7213   setup_editor_el_emerald_mine          = TRUE;
7214   setup_editor_el_emerald_mine_club     = TRUE;
7215   setup_editor_el_more                  = TRUE;
7216   setup_editor_el_sokoban               = TRUE;
7217   setup_editor_el_supaplex              = TRUE;
7218   setup_editor_el_diamond_caves         = TRUE;
7219   setup_editor_el_dx_boulderdash        = TRUE;
7220   setup_editor_el_mirror_magic          = TRUE;
7221   setup_editor_el_deflektor             = TRUE;
7222   setup_editor_el_chars                 = TRUE;
7223   setup_editor_el_steel_chars           = TRUE;
7224
7225   setup_editor_el_custom                = TRUE;
7226   setup_editor_el_user_defined          = TRUE;
7227   setup_editor_el_dynamic               = TRUE;
7228
7229   // now disable all element sections not to be displayed
7230
7231   if (!setup.editor.el_classic)
7232   {
7233     setup_editor_el_players             = FALSE;
7234     setup_editor_el_boulderdash         = FALSE;
7235     setup_editor_el_boulderdash_native  = FALSE;
7236     setup_editor_el_boulderdash_effects = FALSE;
7237     setup_editor_el_emerald_mine        = FALSE;
7238     setup_editor_el_emerald_mine_club   = FALSE;
7239     setup_editor_el_more                = FALSE;
7240     setup_editor_el_sokoban             = FALSE;
7241     setup_editor_el_supaplex            = FALSE;
7242     setup_editor_el_diamond_caves       = FALSE;
7243     setup_editor_el_dx_boulderdash      = FALSE;
7244     setup_editor_el_mirror_magic        = FALSE;
7245     setup_editor_el_deflektor           = FALSE;
7246     setup_editor_el_chars               = FALSE;
7247     setup_editor_el_steel_chars         = FALSE;
7248   }
7249
7250   if (!setup.editor.el_custom)
7251   {
7252     setup_editor_el_custom              = FALSE;
7253   }
7254
7255   if (!setup.editor.el_user_defined)
7256   {
7257     setup_editor_el_user_defined        = FALSE;
7258   }
7259
7260   if (!setup.editor.el_dynamic)
7261   {
7262     setup_editor_el_dynamic             = FALSE;
7263   }
7264
7265   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7266   {
7267     setup_editor_el_boulderdash_native  = FALSE;
7268     setup_editor_el_boulderdash_effects = FALSE;
7269     setup_editor_el_mirror_magic        = FALSE;
7270     setup_editor_el_deflektor           = FALSE;
7271   }
7272   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7273   {
7274     setup_editor_el_players             = FALSE;
7275     setup_editor_el_boulderdash         = FALSE;
7276     setup_editor_el_emerald_mine        = FALSE;
7277     setup_editor_el_emerald_mine_club   = FALSE;
7278     setup_editor_el_more                = FALSE;
7279     setup_editor_el_sokoban             = FALSE;
7280     setup_editor_el_supaplex            = FALSE;
7281     setup_editor_el_diamond_caves       = FALSE;
7282     setup_editor_el_dx_boulderdash      = FALSE;
7283     setup_editor_el_mirror_magic        = FALSE;
7284     setup_editor_el_deflektor           = FALSE;
7285     setup_editor_el_chars               = FALSE;
7286     setup_editor_el_steel_chars         = FALSE;
7287
7288     setup_editor_el_custom              = FALSE;
7289   }
7290   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7291   {
7292     setup_editor_el_boulderdash         = FALSE;
7293     setup_editor_el_boulderdash_native  = FALSE;
7294     setup_editor_el_boulderdash_effects = FALSE;
7295     setup_editor_el_more                = FALSE;
7296     setup_editor_el_sokoban             = FALSE;
7297     setup_editor_el_supaplex            = FALSE;
7298     setup_editor_el_diamond_caves       = FALSE;
7299     setup_editor_el_dx_boulderdash      = FALSE;
7300     setup_editor_el_mirror_magic        = FALSE;
7301     setup_editor_el_deflektor           = FALSE;
7302     setup_editor_el_steel_chars         = FALSE;
7303
7304     setup_editor_el_custom              = FALSE;
7305   }
7306   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7307   {
7308     setup_editor_el_players             = FALSE;
7309     setup_editor_el_boulderdash         = FALSE;
7310     setup_editor_el_boulderdash_native  = FALSE;
7311     setup_editor_el_boulderdash_effects = FALSE;
7312     setup_editor_el_emerald_mine        = FALSE;
7313     setup_editor_el_emerald_mine_club   = FALSE;
7314     setup_editor_el_more                = FALSE;
7315     setup_editor_el_sokoban             = FALSE;
7316     setup_editor_el_diamond_caves       = FALSE;
7317     setup_editor_el_dx_boulderdash      = FALSE;
7318     setup_editor_el_mirror_magic        = FALSE;
7319     setup_editor_el_deflektor           = FALSE;
7320     setup_editor_el_chars               = FALSE;
7321     setup_editor_el_steel_chars         = FALSE;
7322
7323     setup_editor_el_custom              = FALSE;
7324   }
7325   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7326   {
7327     setup_editor_el_players             = FALSE;
7328     setup_editor_el_boulderdash         = FALSE;
7329     setup_editor_el_boulderdash_native  = FALSE;
7330     setup_editor_el_boulderdash_effects = FALSE;
7331     setup_editor_el_emerald_mine        = FALSE;
7332     setup_editor_el_emerald_mine_club   = FALSE;
7333     setup_editor_el_more                = FALSE;
7334     setup_editor_el_sokoban             = FALSE;
7335     setup_editor_el_supaplex            = FALSE;
7336     setup_editor_el_diamond_caves       = FALSE;
7337     setup_editor_el_dx_boulderdash      = FALSE;
7338     setup_editor_el_steel_chars         = FALSE;
7339
7340     setup_editor_el_custom              = FALSE;
7341   }
7342 }
7343
7344 static void ReinitializeElementList(void)
7345 {
7346   static boolean initialization_needed = TRUE;
7347   int pos = 0;
7348   int i, j;
7349
7350   ReinitializeElementList_EnableSections();
7351
7352   if (initialization_needed)
7353   {
7354     LoadSetup_EditorCascade();          // load last editor cascade state
7355
7356     // initialize editor cascade element from saved cascade state
7357     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7358     {
7359       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7360       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7361
7362       if (IS_EDITOR_CASCADE(*cascade_element))
7363         *cascade_element =
7364           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7365            EL_CASCADE_INACTIVE(*cascade_element));
7366     }
7367
7368     initialization_needed = FALSE;
7369   }
7370
7371   checked_free(editor_elements);
7372
7373   // reload optional user defined element list for each invocation of editor
7374   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7375                                    &num_editor_el_user_defined);
7376
7377   // initialize dynamic level element list for each invocation of editor
7378   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7379                                &num_editor_el_dynamic);
7380
7381   // initialize list of empty elements (used for padding, if needed)
7382   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7383     editor_el_empty[i] = EL_EMPTY;
7384
7385   // do some sanity checks for each element from element list
7386   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7387   {
7388     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7389     {
7390       int element = (*editor_elements_info[i].element_list)[j];
7391
7392       if (element >= NUM_FILE_ELEMENTS)
7393         Warn("editor element %d is runtime element", element);
7394
7395       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7396         Warn("no element description text for element %d", element);
7397     }
7398   }
7399
7400   num_editor_elements = 0;
7401   use_el_empty = FALSE;
7402
7403   // determine size of element list
7404   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7405   {
7406     if (*editor_elements_info[i].setup_value)
7407     {
7408       boolean found_inactive_cascade = FALSE;
7409
7410       if (setup.editor.el_headlines)
7411       {
7412         // required for correct padding of palette headline buttons
7413         if (*editor_elements_info[i].headline_list_size > 0)
7414           num_editor_elements += ED_ELEMENTLIST_COLS;
7415
7416         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7417         {
7418           int element = (*editor_elements_info[i].headline_list)[j];
7419
7420           if (IS_EDITOR_CASCADE_INACTIVE(element))
7421             found_inactive_cascade = TRUE;
7422         }
7423       }
7424
7425       if (found_inactive_cascade)
7426         continue;
7427
7428       // required for correct padding of palette element buttons
7429       int element_list_size = *editor_elements_info[i].element_list_size;
7430       int element_rows =
7431         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7432       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7433
7434       num_editor_elements += element_buttons;
7435     }
7436   }
7437
7438   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7439   {
7440     // offer at least as many elements as element buttons exist
7441     use_el_empty = TRUE;
7442     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7443
7444     num_editor_elements += num_editor_el_empty;
7445   }
7446   else
7447   {
7448     num_editor_el_empty = 0;
7449   }
7450
7451   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7452
7453   // fill element list
7454   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7455   {
7456     boolean found_inactive_cascade = FALSE;
7457
7458     if (*editor_elements_info[i].setup_value)
7459     {
7460       if (setup.editor.el_headlines)
7461       {
7462         // required for correct padding of palette headline buttons
7463         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7464                              ED_ELEMENTLIST_COLS : 0);
7465
7466         for (j = 0; j < headline_size; j++)
7467         {
7468           // use empty elements for padding of palette headline buttons
7469           int element = (j < *editor_elements_info[i].headline_list_size ?
7470                          (*editor_elements_info[i].headline_list)[j] :
7471                          editor_el_empty[0]);
7472
7473           editor_elements[pos++] = element;
7474
7475           if (IS_EDITOR_CASCADE_INACTIVE(element))
7476             found_inactive_cascade = TRUE;
7477         }
7478       }
7479
7480       if (found_inactive_cascade)
7481         continue;
7482
7483       // required for correct padding of palette element buttons
7484       int element_list_size = *editor_elements_info[i].element_list_size;
7485       int element_rows =
7486         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7487       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7488
7489       // copy all elements from element list
7490       for (j = 0; j < element_list_size; j++)
7491         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7492
7493       // use empty elements for padding of palette element buttons
7494       for (j = 0; j < element_buttons - element_list_size; j++)
7495         editor_elements[pos++] = editor_el_empty[0];
7496     }
7497   }
7498
7499   // (this function is also called before editor gadgets are initialized!)
7500   AdjustElementListScrollbar();
7501 }
7502
7503 void PrintEditorElementList(void)
7504 {
7505   boolean *stop = &setup_editor_el_user_defined;
7506   int i, j;
7507
7508   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7509   {
7510     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7511
7512     if (IS_EDITOR_CASCADE(cascade_element))
7513     {
7514       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7515       char *headline = element_info[cascade_element_show].editor_description;
7516
7517       PrintLineWithPrefix("# ", "-", 77);
7518       Print("# %s\n", headline);
7519       PrintLineWithPrefix("# ", "-", 77);
7520     }
7521
7522     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7523     {
7524       int element = (*editor_elements_info[i].headline_list)[j];
7525
7526       if (IS_EDITOR_CASCADE(element))
7527         element = EL_CHAR_MINUS;
7528
7529       Print("# %s\n", element_info[element].token_name);
7530     }
7531
7532     if (j > 0)
7533       Print("#\n");
7534
7535     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7536     {
7537       int element = (*editor_elements_info[i].element_list)[j];
7538
7539       Print("# %s\n", element_info[element].token_name);
7540     }
7541
7542     if (j > 0)
7543       Print("#\n");
7544   }
7545 }
7546
7547 static void ReinitializeElementListButtons(void)
7548 {
7549   static boolean last_setup_value_headlines = FALSE;
7550   static boolean initialization_needed = TRUE;
7551   int i;
7552
7553   if (!initialization_needed)   // check if editor element setup has changed
7554   {
7555     if (last_setup_value_headlines != setup.editor.el_headlines)
7556       initialization_needed = TRUE;
7557
7558     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7559       if (editor_elements_info[i].last_setup_value !=
7560           *editor_elements_info[i].setup_value)
7561         initialization_needed = TRUE;
7562   }
7563
7564   if (!initialization_needed)
7565     return;
7566
7567   FreeLevelEditorGadgets();
7568   CreateLevelEditorGadgets();
7569
7570   // store current setup values for next invocation of this function
7571   last_setup_value_headlines = setup.editor.el_headlines;
7572   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7573     editor_elements_info[i].last_setup_value =
7574       *editor_elements_info[i].setup_value;
7575
7576   initialization_needed = FALSE;
7577 }
7578
7579 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7580                               boolean input)
7581 {
7582   int border_graphic =
7583     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7584   struct GraphicInfo *g = &graphic_info[border_graphic];
7585   Bitmap *src_bitmap = g->bitmap;
7586   int src_x = g->src_x;
7587   int src_y = g->src_y;
7588   int border_size = g->border_size;
7589   int border_xpos = g->width  - border_size;
7590   int border_ypos = g->height - border_size;
7591   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7592   int i;
7593
7594   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7595              border_size, border_size,
7596              dest_x - border_size, dest_y - border_size);
7597   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7598              border_size, border_size,
7599              dest_x + width, dest_y - border_size);
7600   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7601              border_size, border_size,
7602              dest_x - border_size, dest_y + height);
7603   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7604              border_size, border_size,
7605              dest_x + width, dest_y + height);
7606
7607   for (i = 0; i < width / tilesize; i++)
7608   {
7609     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7610                tilesize, border_size,
7611                dest_x + i * tilesize, dest_y - border_size);
7612     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7613                tilesize, border_size,
7614                dest_x + i * tilesize, dest_y + height);
7615   }
7616
7617   for (i = 0; i < height / tilesize; i++)
7618   {
7619     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7620                border_size, tilesize,
7621                dest_x - border_size, dest_y + i * tilesize);
7622     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7623                border_size, tilesize,
7624                dest_x + width, dest_y + i * tilesize);
7625   }
7626
7627   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7628 }
7629
7630 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7631 {
7632   int xsize_tile = MAX(ed_tilesize, xsize);
7633   int ysize_tile = MAX(ed_tilesize, ysize);
7634   int xsize_full = xsize + 1;
7635   int ysize_full = ysize + 1;
7636   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7637   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7638   Pixel line_color = getTabulatorBarColor();
7639
7640   if (line_color == BLACK_PIXEL)                // black => transparent
7641     return;
7642
7643   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7644   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7645   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7646 }
7647
7648 static void DrawEditorLevelBorderLinesIfNeeded(void)
7649 {
7650   int xsize = lev_fieldx * ed_tilesize;
7651   int ysize = lev_fieldy * ed_tilesize;
7652   int line_size = getTabulatorBarHeight();
7653
7654   if (!suppressBorderElement())
7655     return;
7656
7657   // draw little border line around editable level playfield
7658
7659   if (xsize < SXSIZE)
7660     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7661
7662   if (ysize < SYSIZE)
7663     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7664
7665   if (xsize < SXSIZE && ysize < SYSIZE)
7666     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7667 }
7668
7669 static void DrawEditorElement(int x, int y, int element)
7670 {
7671   DrawSizedElement(x, y, element, ed_tilesize);
7672 }
7673
7674 static void DrawEditorElementThruMask(int x, int y, int element)
7675 {
7676   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7677 }
7678
7679 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7680 {
7681   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7682 }
7683
7684 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7685 {
7686   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7687   DrawEditorLevelBorderLinesIfNeeded();
7688 }
7689
7690 static void DrawDrawingArea(int id)
7691 {
7692   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7693   int x, y;
7694
7695   int *value = drawingarea_info[id].value;
7696   int area_xsize = drawingarea_info[id].area_xsize;
7697   int area_ysize = drawingarea_info[id].area_ysize;
7698   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7699
7700   for (x = 0; x < area_xsize; x++)
7701   {
7702     for (y = 0; y < area_ysize; y++)
7703     {
7704       int element = value[x * area_ysize + y];
7705       int graphic;
7706       int frame;
7707
7708       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7709
7710       DrawSizedGraphicExt(drawto,
7711                           gi->x + x * tilesize,
7712                           gi->y + y * tilesize,
7713                           graphic, frame, tilesize);
7714     }
7715   }
7716 }
7717
7718 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7719 {
7720   int x, y;
7721   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7722   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7723
7724   BlitBitmap(drawto, drawto,
7725              SX + (dx == -1 ? ed_tilesize : 0),
7726              SY + (dy == -1 ? ed_tilesize : 0),
7727              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7728              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7729              SX + (dx == +1 ? ed_tilesize : 0),
7730              SY + (dy == +1 ? ed_tilesize : 0));
7731
7732   if (dx)
7733   {
7734     x = (dx == 1 ? 0 : ed_fieldx - 1);
7735     for (y = 0; y < ed_fieldy; y++)
7736       DrawEditorElementOrWall(x, y, from_x, from_y);
7737   }
7738   else if (dy)
7739   {
7740     y = (dy == 1 ? 0 : ed_fieldy - 1);
7741     for (x = 0; x < ed_fieldx; x++)
7742       DrawEditorElementOrWall(x, y, from_x, from_y);
7743   }
7744
7745   redraw_mask |= REDRAW_FIELD;
7746   BackToFront();
7747 }
7748
7749 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7750 {
7751   if (use_editor_gfx)
7752   {
7753     *graphic = el2edimg(element);
7754     *frame = 0;
7755   }
7756   else
7757   {
7758     *graphic = el2img(element);
7759     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7760               custom_element.ce_value_fixed_initial :
7761               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7762               custom_element.collect_score_initial : FrameCounter);
7763   }
7764
7765   if (*graphic == IMG_UNKNOWN)
7766   {
7767     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7768     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7769     int element_bd = map_element_RND_to_BD_cave(element);
7770
7771     if (element_bd != O_UNKNOWN)
7772     {
7773       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7774
7775       *graphic = g_bd->graphic;
7776       *frame   = g_bd->frame;
7777     }
7778   }
7779 }
7780
7781 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7782                                    int *x, int *y)
7783 {
7784   int graphic;
7785   int frame;
7786
7787   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7788
7789   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7790 }
7791
7792 static void CreateControlButtons(void)
7793 {
7794   struct GadgetInfo *gi;
7795   int i;
7796
7797   // create toolbox buttons
7798   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7799   {
7800     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7801     int id = controlbutton_info[i].gadget_id;
7802     int type = controlbutton_info[i].gadget_type;
7803     int graphic = controlbutton_info[i].graphic;
7804     struct XYTileSize *pos = controlbutton_info[i].pos;
7805     struct GraphicInfo *gd = &graphic_info[graphic];
7806     Bitmap *deco_bitmap = NULL;
7807     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7808     int tile_size = 0, deco_shift = 0;
7809     boolean deco_masked = FALSE;
7810     int gd_x1 = gd->src_x;
7811     int gd_y1 = gd->src_y;
7812     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7813     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7814     int gd_x1a = gd->src_x + gd->active_xoffset;
7815     int gd_y1a = gd->src_y + gd->active_yoffset;
7816     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7817     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7818     int x = pos->x;
7819     int y = pos->y;
7820     unsigned int event_mask;
7821     int radio_button_nr = RADIO_NR_NONE;
7822     boolean checked = FALSE;
7823
7824     if (type_id != i)
7825       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7826
7827     if (type == GD_TYPE_RADIO_BUTTON)
7828     {
7829       event_mask = GD_EVENT_PRESSED;
7830       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7831
7832       if (id == drawing_function)
7833         checked = TRUE;
7834     }
7835     else
7836     {
7837       if (id == GADGET_ID_WRAP_LEFT ||
7838           id == GADGET_ID_WRAP_RIGHT ||
7839           id == GADGET_ID_WRAP_UP ||
7840           id == GADGET_ID_WRAP_DOWN)
7841         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7842       else
7843         event_mask = GD_EVENT_RELEASED;
7844     }
7845
7846     if (id == GADGET_ID_PROPERTIES ||
7847         id == GADGET_ID_PALETTE)
7848     {
7849       x += DX;
7850       y += DY;
7851     }
7852     else if (id == GADGET_ID_ELEMENT_LEFT ||
7853              id == GADGET_ID_ELEMENT_MIDDLE ||
7854              id == GADGET_ID_ELEMENT_RIGHT)
7855     {
7856       x += DX;
7857       y += DY;
7858
7859       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7860                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7861                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7862
7863       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7864                                    editor.button.element_left.tile_size :
7865                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7866                                    editor.button.element_middle.tile_size :
7867                                    id == GADGET_ID_ELEMENT_RIGHT ?
7868                                    editor.button.element_right.tile_size : 0);
7869
7870       // make sure that decoration does not overlap gadget border
7871       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7872
7873       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7874
7875       deco_xpos = (gd->width  - tile_size) / 2;
7876       deco_ypos = (gd->height - tile_size) / 2;
7877       deco_shift = 1;
7878       deco_masked = gd->draw_masked;
7879     }
7880     else
7881     {
7882       x += EX;
7883       y += EY;
7884     }
7885
7886     gi = CreateGadget(GDI_CUSTOM_ID, id,
7887                       GDI_CUSTOM_TYPE_ID, type_id,
7888                       GDI_IMAGE_ID, graphic,
7889                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7890                       GDI_X, x,
7891                       GDI_Y, y,
7892                       GDI_WIDTH, gd->width,
7893                       GDI_HEIGHT, gd->height,
7894                       GDI_TYPE, type,
7895                       GDI_STATE, GD_BUTTON_UNPRESSED,
7896                       GDI_RADIO_NR, radio_button_nr,
7897                       GDI_CHECKED, checked,
7898                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7899                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7900                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7901                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7902                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7903                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7904                       GDI_DECORATION_SIZE, tile_size, tile_size,
7905                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7906                       GDI_DECORATION_MASKED, deco_masked,
7907                       GDI_EVENT_MASK, event_mask,
7908                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7909                       GDI_CALLBACK_ACTION, HandleControlButtons,
7910                       GDI_END);
7911
7912     if (gi == NULL)
7913       Fail("cannot create gadget");
7914
7915     level_editor_gadget[id] = gi;
7916   }
7917
7918   // these values are not constant, but can change at runtime
7919   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7920   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7921   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7922   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7923   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7924   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7925   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7926   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7927   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7928   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7929   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7930   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7931
7932   // create buttons for scrolling of drawing area and element list
7933   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7934   {
7935     int id = scrollbutton_info[i].gadget_id;
7936     int type_id = scrollbutton_info[i].gadget_type_id;
7937     int graphic = scrollbutton_info[i].graphic;
7938     struct GraphicInfo *gd = &graphic_info[graphic];
7939     Bitmap *gd_bitmap = gd->bitmap;
7940     int gd_x1 = gd->src_x;
7941     int gd_y1 = gd->src_y;
7942     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7943     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7944     int width  = gd->width;
7945     int height = gd->height;
7946     int x = scrollbutton_pos[i].x;
7947     int y = scrollbutton_pos[i].y;
7948     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7949
7950     if (type_id != i)
7951       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7952
7953     if (id == GADGET_ID_SCROLL_LIST_UP ||
7954         id == GADGET_ID_SCROLL_LIST_DOWN)
7955     {
7956       x += PX;
7957       y += PY;
7958     }
7959     else
7960     {
7961       x += SX;
7962       y += SY;
7963     }
7964
7965     gi = CreateGadget(GDI_CUSTOM_ID, id,
7966                       GDI_CUSTOM_TYPE_ID, type_id,
7967                       GDI_IMAGE_ID, graphic,
7968                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7969                       GDI_X, x,
7970                       GDI_Y, y,
7971                       GDI_WIDTH, width,
7972                       GDI_HEIGHT, height,
7973                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7974                       GDI_STATE, GD_BUTTON_UNPRESSED,
7975                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7976                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7977                       GDI_EVENT_MASK, event_mask,
7978                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7979                       GDI_CALLBACK_ACTION, HandleControlButtons,
7980                       GDI_END);
7981
7982     if (gi == NULL)
7983       Fail("cannot create gadget");
7984
7985     level_editor_gadget[id] = gi;
7986   }
7987
7988   // create buttons for element list
7989   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7990   {
7991     int type_id = i;
7992     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
7993     int graphic = IMG_EDITOR_PALETTE_BUTTON;
7994     struct GraphicInfo *gd = &graphic_info[graphic];
7995     Bitmap *gd_bitmap = gd->bitmap;
7996     Bitmap *deco_bitmap;
7997     int deco_x, deco_y, deco_xpos, deco_ypos;
7998     int gd_x1 = gd->src_x;
7999     int gd_y1 = gd->src_y;
8000     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8001     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8002     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
8003     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
8004     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
8005     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
8006     int element = editor_elements[i];
8007     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
8008     unsigned int event_mask = GD_EVENT_RELEASED;
8009
8010     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
8011
8012     deco_xpos = (gd->width  - tile_size) / 2;
8013     deco_ypos = (gd->height - tile_size) / 2;
8014
8015     gi = CreateGadget(GDI_CUSTOM_ID, id,
8016                       GDI_CUSTOM_TYPE_ID, type_id,
8017                       GDI_IMAGE_ID, graphic,
8018                       GDI_INFO_TEXT, getElementInfoText(element),
8019                       GDI_X, x,
8020                       GDI_Y, y,
8021                       GDI_WIDTH, gd->width,
8022                       GDI_HEIGHT, gd->height,
8023                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8024                       GDI_STATE, GD_BUTTON_UNPRESSED,
8025                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
8026                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
8027                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
8028                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
8029                       GDI_DECORATION_SIZE, tile_size, tile_size,
8030                       GDI_DECORATION_SHIFTING, 1, 1,
8031                       GDI_EVENT_MASK, event_mask,
8032                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8033                       GDI_CALLBACK_ACTION, HandleControlButtons,
8034                       GDI_END);
8035
8036     if (gi == NULL)
8037       Fail("cannot create gadget");
8038
8039     level_editor_gadget[id] = gi;
8040   }
8041 }
8042
8043 static void CreateCounterButtons(void)
8044 {
8045   int max_infotext_len = getMaxInfoTextLength();
8046   int i;
8047
8048   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
8049   {
8050     int type_id = counterbutton_info[i].gadget_type_id;
8051     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
8052     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
8053     int j;
8054
8055     if (type_id != i)
8056       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
8057
8058     // determine horizontal position to the right of specified gadget
8059     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8060       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
8061            ED_GADGET_TEXT_DISTANCE);
8062
8063     // determine horizontal offset for leading text
8064     if (counterbutton_info[i].text_left != NULL)
8065       x += getTextWidthForGadget(counterbutton_info[i].text_left);
8066
8067     for (j = 0; j < 2; j++)
8068     {
8069       struct GadgetInfo *gi;
8070       int id = (j == 0 ?
8071                 counterbutton_info[i].gadget_id_down :
8072                 counterbutton_info[i].gadget_id_up);
8073       int graphic;
8074       struct GraphicInfo *gd;
8075       int gd_x1, gd_x2, gd_y1, gd_y2;
8076       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
8077       char infotext[max_infotext_len + 1];
8078
8079       if (i == ED_COUNTER_ID_SELECT_LEVEL)
8080       {
8081         graphic = (j == 0 ?
8082                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
8083                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
8084
8085         event_mask |= GD_EVENT_RELEASED;
8086
8087         if (j == 0)
8088         {
8089           x = DX + editor.button.prev_level.x;
8090           y = DY + editor.button.prev_level.y;
8091         }
8092         else
8093         {
8094           x = DX + editor.button.next_level.x;
8095           y = DY + editor.button.next_level.y;
8096         }
8097       }
8098       else
8099       {
8100         graphic = (j == 0 ?
8101                    IMG_EDITOR_COUNTER_DOWN :
8102                    IMG_EDITOR_COUNTER_UP);
8103       }
8104
8105       gd = &graphic_info[graphic];
8106
8107       gd_x1 = gd->src_x;
8108       gd_y1 = gd->src_y;
8109       gd_x2 = gd->src_x + gd->pressed_xoffset;
8110       gd_y2 = gd->src_y + gd->pressed_yoffset;
8111
8112       sprintf(infotext, "%s counter value by 1, 5 or 10",
8113               (j == 0 ? "Decrease" : "Increase"));
8114
8115       gi = CreateGadget(GDI_CUSTOM_ID, id,
8116                         GDI_CUSTOM_TYPE_ID, type_id,
8117                         GDI_IMAGE_ID, graphic,
8118                         GDI_INFO_TEXT, infotext,
8119                         GDI_X, x,
8120                         GDI_Y, y,
8121                         GDI_WIDTH, gd->width,
8122                         GDI_HEIGHT, gd->height,
8123                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8124                         GDI_STATE, GD_BUTTON_UNPRESSED,
8125                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8126                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8127                         GDI_EVENT_MASK, event_mask,
8128                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8129                         GDI_CALLBACK_ACTION, HandleCounterButtons,
8130                         GDI_END);
8131
8132       if (gi == NULL)
8133         Fail("cannot create gadget");
8134
8135       level_editor_gadget[id] = gi;
8136       right_gadget_border[id] =
8137         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8138
8139       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
8140
8141       if (j == 0)
8142       {
8143         int font_type = FONT_INPUT_1;
8144         int font_type_active = FONT_INPUT_1_ACTIVE;
8145
8146         id = counterbutton_info[i].gadget_id_text;
8147
8148         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8149
8150         if (i == ED_COUNTER_ID_SELECT_LEVEL)
8151         {
8152           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
8153
8154           font_type = FONT_LEVEL_NUMBER;
8155           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
8156
8157           x = DX + editor.input.level_number.x;
8158           y = DY + editor.input.level_number.y;
8159         }
8160         else
8161         {
8162           graphic = IMG_EDITOR_COUNTER_INPUT;
8163         }
8164
8165         gd = &graphic_info[graphic];
8166
8167         gd_x1 = gd->src_x;
8168         gd_y1 = gd->src_y;
8169         gd_x2 = gd->src_x + gd->active_xoffset;
8170         gd_y2 = gd->src_y + gd->active_yoffset;
8171
8172         gi = CreateGadget(GDI_CUSTOM_ID, id,
8173                           GDI_CUSTOM_TYPE_ID, type_id,
8174                           GDI_IMAGE_ID, graphic,
8175                           GDI_INFO_TEXT, "Enter counter value",
8176                           GDI_X, x,
8177                           GDI_Y, y,
8178                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
8179                           GDI_NUMBER_VALUE, 0,
8180                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
8181                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
8182                           GDI_TEXT_SIZE, 3,     // minimal counter text size
8183                           GDI_TEXT_FONT, font_type,
8184                           GDI_TEXT_FONT_ACTIVE, font_type_active,
8185                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8186                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8187                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8188                           GDI_DESIGN_WIDTH, gd->width,
8189                           GDI_EVENT_MASK, event_mask,
8190                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8191                           GDI_CALLBACK_ACTION, HandleCounterButtons,
8192                           GDI_END);
8193
8194         if (gi == NULL)
8195           Fail("cannot create gadget");
8196
8197         level_editor_gadget[id] = gi;
8198         right_gadget_border[id] =
8199           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8200
8201         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
8202       }
8203     }
8204   }
8205 }
8206
8207 static void CreateDrawingAreas(void)
8208 {
8209   int i;
8210
8211   // these values are not constant, but can change at runtime
8212   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8213   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8214
8215   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8216   {
8217     struct GadgetInfo *gi;
8218     int id = drawingarea_info[i].gadget_id;
8219     int type_id = drawingarea_info[i].gadget_type_id;
8220     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8221     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8222     int area_xsize = drawingarea_info[i].area_xsize;
8223     int area_ysize = drawingarea_info[i].area_ysize;
8224     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8225                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8226     unsigned int event_mask =
8227       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8228       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8229
8230     if (type_id != i)
8231       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8232
8233     // determine horizontal position to the right of specified gadget
8234     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8235       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8236            ED_DRAWINGAREA_TEXT_DISTANCE);
8237
8238     // determine horizontal offset for leading text
8239     if (drawingarea_info[i].text_left != NULL)
8240       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8241
8242     gi = CreateGadget(GDI_CUSTOM_ID, id,
8243                       GDI_CUSTOM_TYPE_ID, type_id,
8244                       GDI_X, x,
8245                       GDI_Y, y,
8246                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8247                       GDI_AREA_SIZE, area_xsize, area_ysize,
8248                       GDI_ITEM_SIZE, item_size, item_size,
8249                       GDI_EVENT_MASK, event_mask,
8250                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8251                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8252                       GDI_END);
8253
8254     if (gi == NULL)
8255       Fail("cannot create gadget");
8256
8257     level_editor_gadget[id] = gi;
8258     right_gadget_border[id] =
8259       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8260   }
8261 }
8262
8263 static void CreateTextInputGadgets(void)
8264 {
8265   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8266   int max_infotext_len = getMaxInfoTextLength();
8267   int i;
8268
8269   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8270   {
8271     int gd_x1 = gd->src_x;
8272     int gd_y1 = gd->src_y;
8273     int gd_x2 = gd->src_x + gd->active_xoffset;
8274     int gd_y2 = gd->src_y + gd->active_yoffset;
8275     struct GadgetInfo *gi;
8276     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8277     char infotext[MAX_OUTPUT_LINESIZE + 1];
8278     int id = textinput_info[i].gadget_id;
8279     int type_id = textinput_info[i].gadget_type_id;
8280     int x, y;
8281
8282     if (type_id != i)
8283       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8284
8285     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8286     {
8287       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8288       int border_size = gd->border_size;
8289       int font_nr = FONT_INPUT_1;
8290       int font_height = getFontHeight(font_nr);
8291       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8292       int yoffset = element_border + (TILEY - font_height) / 2;
8293
8294       x = (editor.settings.element_name.x != -1 ?
8295            editor.settings.element_name.x :
8296            editor.settings.element_graphic.x + xoffset) - border_size;
8297       y = (editor.settings.element_name.y != -1 ?
8298            editor.settings.element_name.y :
8299            editor.settings.element_graphic.y + yoffset) - border_size;
8300     }
8301     else
8302     {
8303       x = ED_SETTINGS_X(textinput_info[i].x);
8304       y = ED_SETTINGS_Y(textinput_info[i].y);
8305     }
8306
8307     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8308     infotext[max_infotext_len] = '\0';
8309
8310     gi = CreateGadget(GDI_CUSTOM_ID, id,
8311                       GDI_CUSTOM_TYPE_ID, type_id,
8312                       GDI_INFO_TEXT, infotext,
8313                       GDI_X, SX + x,
8314                       GDI_Y, SY + y,
8315                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8316                       GDI_TEXT_VALUE, textinput_info[i].value,
8317                       GDI_TEXT_SIZE, textinput_info[i].size,
8318                       GDI_TEXT_FONT, FONT_INPUT_1,
8319                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8320                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8321                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8322                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8323                       GDI_DESIGN_WIDTH, gd->width,
8324                       GDI_EVENT_MASK, event_mask,
8325                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8326                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
8327                       GDI_END);
8328
8329     if (gi == NULL)
8330       Fail("cannot create gadget");
8331
8332     level_editor_gadget[id] = gi;
8333   }
8334 }
8335
8336 static void CreateTextAreaGadgets(void)
8337 {
8338   int max_infotext_len = getMaxInfoTextLength();
8339   int i;
8340
8341   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8342   {
8343     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8344     int gd_x1 = gd->src_x;
8345     int gd_y1 = gd->src_y;
8346     int gd_x2 = gd->src_x + gd->active_xoffset;
8347     int gd_y2 = gd->src_y + gd->active_yoffset;
8348     struct GadgetInfo *gi;
8349     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8350     char infotext[MAX_OUTPUT_LINESIZE + 1];
8351     int id = textarea_info[i].gadget_id;
8352     int type_id = textarea_info[i].gadget_type_id;
8353     int area_xsize = textarea_info[i].xsize;
8354     int area_ysize = textarea_info[i].ysize;
8355
8356     if (type_id != i)
8357       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8358
8359     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8360     infotext[max_infotext_len] = '\0';
8361
8362     gi = CreateGadget(GDI_CUSTOM_ID, id,
8363                       GDI_CUSTOM_TYPE_ID, type_id,
8364                       GDI_INFO_TEXT, infotext,
8365                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8366                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8367                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8368                       GDI_AREA_SIZE, area_xsize, area_ysize,
8369                       GDI_TEXT_FONT, FONT_INPUT_1,
8370                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8371                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8372                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8373                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8374                       GDI_DESIGN_WIDTH, gd->width,
8375                       GDI_EVENT_MASK, event_mask,
8376                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8377                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8378                       GDI_END);
8379
8380     if (gi == NULL)
8381       Fail("cannot create gadget");
8382
8383     level_editor_gadget[id] = gi;
8384   }
8385 }
8386
8387 static void CreateSelectboxGadgets(void)
8388 {
8389   int max_infotext_len = getMaxInfoTextLength();
8390
8391   int i, j;
8392
8393   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8394   {
8395     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8396     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8397     int gd_x1 = gd->src_x;
8398     int gd_y1 = gd->src_y;
8399     int gd_x2 = gd->src_x + gd->active_xoffset;
8400     int gd_y2 = gd->src_y + gd->active_yoffset;
8401     int selectbox_button_xsize = gd2->width;
8402     struct GadgetInfo *gi;
8403     char infotext[MAX_OUTPUT_LINESIZE + 1];
8404     int id = selectbox_info[i].gadget_id;
8405     int type_id = selectbox_info[i].gadget_type_id;
8406     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8407     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8408     unsigned int event_mask =
8409       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8410
8411     if (type_id != i)
8412       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8413
8414     if (selectbox_info[i].size == -1)   // dynamically determine size
8415     {
8416       // (we cannot use -1 for uninitialized values if we directly compare
8417       // with results from strlen(), because the '<' and '>' operation will
8418       // implicitely cast -1 to an unsigned integer value!)
8419       selectbox_info[i].size = 0;
8420
8421       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8422         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8423           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8424
8425       selectbox_info[i].size++;         // add one character empty space
8426     }
8427
8428     // determine horizontal position to the right of specified gadget
8429     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8430       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8431            ED_GADGET_TEXT_DISTANCE);
8432
8433     // determine horizontal offset for leading text
8434     if (selectbox_info[i].text_left != NULL)
8435       x += getTextWidthForGadget(selectbox_info[i].text_left);
8436
8437     sprintf(infotext, "%s", selectbox_info[i].infotext);
8438     infotext[max_infotext_len] = '\0';
8439
8440     gi = CreateGadget(GDI_CUSTOM_ID, id,
8441                       GDI_CUSTOM_TYPE_ID, type_id,
8442                       GDI_INFO_TEXT, infotext,
8443                       GDI_X, x,
8444                       GDI_Y, y,
8445                       GDI_TYPE, GD_TYPE_SELECTBOX,
8446                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8447                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8448                       GDI_TEXT_SIZE, selectbox_info[i].size,
8449                       GDI_TEXT_FONT, FONT_INPUT_1,
8450                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8451                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8452                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8453                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8454                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8455                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8456                       GDI_DESIGN_WIDTH, gd->width,
8457                       GDI_EVENT_MASK, event_mask,
8458                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8459                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8460                       GDI_END);
8461
8462     if (gi == NULL)
8463       Fail("cannot create gadget");
8464
8465     level_editor_gadget[id] = gi;
8466     right_gadget_border[id] =
8467       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8468   }
8469 }
8470
8471 static void CreateTextbuttonGadgets(void)
8472 {
8473   int max_infotext_len = getMaxInfoTextLength();
8474   int i;
8475
8476   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8477   {
8478     int id = textbutton_info[i].gadget_id;
8479     int type_id = textbutton_info[i].gadget_type_id;
8480     int is_tab_button =
8481       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8482        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8483     int graphic =
8484       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8485     int gadget_distance =
8486       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8487     struct GraphicInfo *gd = &graphic_info[graphic];
8488     int gd_x1 = gd->src_x;
8489     int gd_y1 = gd->src_y;
8490     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8491     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8492     int gd_x1a = gd->src_x + gd->active_xoffset;
8493     int gd_y1a = gd->src_y + gd->active_yoffset;
8494     int border_xsize = gd->border_size + gd->draw_xoffset;
8495     int border_ysize = gd->border_size;
8496     struct GadgetInfo *gi;
8497     unsigned int event_mask = GD_EVENT_RELEASED;
8498     char infotext[MAX_OUTPUT_LINESIZE + 1];
8499     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8500     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8501
8502     if (type_id != i)
8503       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8504
8505     if (textbutton_info[i].size == -1)  // dynamically determine size
8506       textbutton_info[i].size = strlen(textbutton_info[i].text);
8507
8508     sprintf(infotext, "%s", textbutton_info[i].infotext);
8509     infotext[max_infotext_len] = '\0';
8510
8511     // determine horizontal position to the right of specified gadget
8512     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8513     {
8514       int gadget_id_align = textbutton_info[i].gadget_id_align;
8515
8516       x = right_gadget_border[gadget_id_align] + gadget_distance;
8517
8518       if (textbutton_info[i].y == -1)
8519         y = level_editor_gadget[gadget_id_align]->y;
8520     }
8521
8522     // determine horizontal offset for leading text
8523     if (textbutton_info[i].text_left != NULL)
8524       x += getTextWidthForGadget(textbutton_info[i].text_left);
8525
8526     gi = CreateGadget(GDI_CUSTOM_ID, id,
8527                       GDI_CUSTOM_TYPE_ID, type_id,
8528                       GDI_IMAGE_ID, graphic,
8529                       GDI_INFO_TEXT, infotext,
8530                       GDI_X, x,
8531                       GDI_Y, y,
8532                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8533                       GDI_TEXT_VALUE, textbutton_info[i].text,
8534                       GDI_TEXT_SIZE, textbutton_info[i].size,
8535                       GDI_TEXT_FONT, FONT_INPUT_2,
8536                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8537                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8538                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8539                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8540                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8541                       GDI_DESIGN_WIDTH, gd->width,
8542                       GDI_DECORATION_SHIFTING, 1, 1,
8543                       GDI_EVENT_MASK, event_mask,
8544                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8545                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8546                       GDI_END);
8547
8548     if (gi == NULL)
8549       Fail("cannot create gadget");
8550
8551     level_editor_gadget[id] = gi;
8552     right_gadget_border[id] =
8553       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8554   }
8555 }
8556
8557 static void CreateGraphicbuttonGadgets(void)
8558 {
8559   struct GadgetInfo *gi;
8560   int i;
8561
8562   // create buttons for scrolling of drawing area and element list
8563   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8564   {
8565     int id = graphicbutton_info[i].gadget_id;
8566     int type_id = graphicbutton_info[i].gadget_type_id;
8567     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8568     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8569     int graphic = graphicbutton_info[i].graphic;
8570     struct GraphicInfo *gd = &graphic_info[graphic];
8571     int gd_x1 = gd->src_x;
8572     int gd_y1 = gd->src_y;
8573     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8574     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8575     unsigned int event_mask = GD_EVENT_RELEASED;
8576
8577     if (type_id != i)
8578       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8579
8580     // determine horizontal position to the right of specified gadget
8581     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8582       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8583            ED_GADGET_TEXT_DISTANCE);
8584
8585     // determine horizontal offset for leading text
8586     if (graphicbutton_info[i].text_left != NULL)
8587       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8588
8589     gi = CreateGadget(GDI_CUSTOM_ID, id,
8590                       GDI_CUSTOM_TYPE_ID, type_id,
8591                       GDI_IMAGE_ID, graphic,
8592                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8593                       GDI_X, x,
8594                       GDI_Y, y,
8595                       GDI_WIDTH, gd->width,
8596                       GDI_HEIGHT, gd->height,
8597                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8598                       GDI_STATE, GD_BUTTON_UNPRESSED,
8599                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8600                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8601                       GDI_EVENT_MASK, event_mask,
8602                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8603                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8604                       GDI_END);
8605
8606     if (gi == NULL)
8607       Fail("cannot create gadget");
8608
8609     level_editor_gadget[id] = gi;
8610     right_gadget_border[id] =
8611       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8612   }
8613 }
8614
8615 static void CreateScrollbarGadgets(void)
8616 {
8617   int i;
8618
8619   // these values are not constant, but can change at runtime
8620   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8621     SX + ED_SCROLL_HORIZONTAL_XPOS;
8622   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8623     SY + ED_SCROLL_HORIZONTAL_YPOS;
8624   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8625     ED_SCROLL_HORIZONTAL_XSIZE;
8626   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8627     ED_SCROLL_HORIZONTAL_YSIZE;
8628   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8629   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8630   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8631   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8632
8633   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8634     SX + ED_SCROLL_VERTICAL_XPOS;
8635   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8636     SY + ED_SCROLL_VERTICAL_YPOS;
8637   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8638     ED_SCROLL_VERTICAL_XSIZE;
8639   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8640     ED_SCROLL_VERTICAL_YSIZE;
8641   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8642   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8643   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8644   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8645
8646   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8647     PX + ED_SCROLL2_VERTICAL_XPOS;
8648   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8649     PY + ED_SCROLL2_VERTICAL_YPOS;
8650   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8651     ED_SCROLL2_VERTICAL_XSIZE;
8652   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8653     ED_SCROLL2_VERTICAL_YSIZE;
8654   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8655   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8656   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8657   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8658
8659   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8660   {
8661     int id = scrollbar_info[i].gadget_id;
8662     int type_id = scrollbar_info[i].gadget_type_id;
8663     int graphic = scrollbar_info[i].graphic;
8664     struct GraphicInfo *gd = &graphic_info[graphic];
8665     int gd_x1 = gd->src_x;
8666     int gd_y1 = gd->src_y;
8667     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8668     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8669     struct GadgetInfo *gi;
8670     int items_max, items_visible, item_position;
8671     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8672
8673     if (type_id != i)
8674       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8675
8676     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8677     {
8678       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8679       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8680       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8681     }
8682     else        // drawing area scrollbars
8683     {
8684       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8685       {
8686         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8687         items_visible = ed_fieldx;
8688         item_position = 0;
8689       }
8690       else
8691       {
8692         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8693         items_visible = ed_fieldy;
8694         item_position = 0;
8695       }
8696     }
8697
8698     gi = CreateGadget(GDI_CUSTOM_ID, id,
8699                       GDI_CUSTOM_TYPE_ID, type_id,
8700                       GDI_IMAGE_ID, graphic,
8701                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8702                       GDI_X, scrollbar_pos[i].x,
8703                       GDI_Y, scrollbar_pos[i].y,
8704                       GDI_WIDTH, scrollbar_pos[i].width,
8705                       GDI_HEIGHT, scrollbar_pos[i].height,
8706                       GDI_TYPE, scrollbar_info[i].type,
8707                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8708                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8709                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8710                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8711                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8712                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8713                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8714                       GDI_STATE, GD_BUTTON_UNPRESSED,
8715                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8716                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8717                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8718                       GDI_EVENT_MASK, event_mask,
8719                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8720                       GDI_CALLBACK_ACTION, HandleControlButtons,
8721                       GDI_END);
8722
8723     if (gi == NULL)
8724       Fail("cannot create gadget");
8725
8726     level_editor_gadget[id] = gi;
8727   }
8728 }
8729
8730 static void CreateCheckbuttonGadgets(void)
8731 {
8732   struct GadgetInfo *gi;
8733   int i;
8734
8735   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8736   {
8737     int id = checkbutton_info[i].gadget_id;
8738     int type_id = checkbutton_info[i].gadget_type_id;
8739     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8740                    IMG_EDITOR_CHECKBOX);
8741     struct GraphicInfo *gd = &graphic_info[graphic];
8742     int gd_x1 = gd->src_x;
8743     int gd_y1 = gd->src_y;
8744     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8745     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8746     int gd_x1a = gd->src_x + gd->active_xoffset;
8747     int gd_y1a = gd->src_y + gd->active_yoffset;
8748     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8749     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8750     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8751     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8752     unsigned int event_mask = GD_EVENT_PRESSED;
8753
8754     if (type_id != i)
8755       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8756
8757     // determine horizontal position to the right of specified gadget
8758     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8759       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8760            ED_GADGET_TEXT_DISTANCE);
8761
8762     // determine horizontal offset for leading text
8763     if (checkbutton_info[i].text_left != NULL)
8764       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8765
8766     gi = CreateGadget(GDI_CUSTOM_ID, id,
8767                       GDI_CUSTOM_TYPE_ID, type_id,
8768                       GDI_IMAGE_ID, graphic,
8769                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8770                       GDI_X, x,
8771                       GDI_Y, y,
8772                       GDI_WIDTH, gd->width,
8773                       GDI_HEIGHT, gd->height,
8774                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8775                       GDI_CHECKED, *checkbutton_info[i].value,
8776                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8777                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8778                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8779                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8780                       GDI_EVENT_MASK, event_mask,
8781                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8782                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8783                       GDI_END);
8784
8785     if (gi == NULL)
8786       Fail("cannot create gadget");
8787
8788     level_editor_gadget[id] = gi;
8789     right_gadget_border[id] =
8790       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8791   }
8792 }
8793
8794 static void CreateRadiobuttonGadgets(void)
8795 {
8796   int graphic = IMG_EDITOR_RADIOBUTTON;
8797   struct GraphicInfo *gd = &graphic_info[graphic];
8798   int gd_x1 = gd->src_x;
8799   int gd_y1 = gd->src_y;
8800   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8801   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8802   int gd_x1a = gd->src_x + gd->active_xoffset;
8803   int gd_y1a = gd->src_y + gd->active_yoffset;
8804   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8805   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8806   struct GadgetInfo *gi;
8807   int i;
8808
8809   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8810   {
8811     int id = radiobutton_info[i].gadget_id;
8812     int type_id = radiobutton_info[i].gadget_type_id;
8813     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8814     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8815     unsigned int event_mask = GD_EVENT_PRESSED;
8816
8817     if (type_id != i)
8818       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8819
8820     int checked =
8821       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8822
8823     // determine horizontal position to the right of specified gadget
8824     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8825       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8826            ED_GADGET_TEXT_DISTANCE);
8827
8828     // determine horizontal offset for leading text
8829     if (radiobutton_info[i].text_left != NULL)
8830       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8831
8832     gi = CreateGadget(GDI_CUSTOM_ID, id,
8833                       GDI_CUSTOM_TYPE_ID, type_id,
8834                       GDI_IMAGE_ID, graphic,
8835                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8836                       GDI_X, x,
8837                       GDI_Y, y,
8838                       GDI_WIDTH, gd->width,
8839                       GDI_HEIGHT, gd->height,
8840                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8841                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8842                       GDI_CHECKED, checked,
8843                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8844                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8845                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8846                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8847                       GDI_EVENT_MASK, event_mask,
8848                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8849                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8850                       GDI_END);
8851
8852     if (gi == NULL)
8853       Fail("cannot create gadget");
8854
8855     level_editor_gadget[id] = gi;
8856     right_gadget_border[id] =
8857       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8858   }
8859 }
8860
8861 void CreateLevelEditorGadgets(void)
8862 {
8863   // force EDITOR font inside level editor
8864   SetFontStatus(GAME_MODE_EDITOR);
8865
8866   // these values are not constant, but can change at runtime
8867   ed_fieldx = MAX_ED_FIELDX - 1;
8868   ed_fieldy = MAX_ED_FIELDY - 1;
8869
8870   num_editor_gadgets = NUM_EDITOR_GADGETS;
8871
8872   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8873
8874   level_editor_gadget =
8875     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8876   right_gadget_border =
8877     checked_calloc(num_editor_gadgets * sizeof(int));
8878
8879   // set number of empty (padding) element buttons to maximum number of buttons
8880   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8881
8882   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8883   editor_el_empty_ptr = editor_el_empty;
8884
8885   use_permanent_palette = !editor.palette.show_as_separate_screen;
8886
8887   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8888
8889   ReinitializeElementList();
8890
8891   CreateControlButtons();
8892   CreateScrollbarGadgets();
8893
8894   // order of function calls is important because of cross-references
8895   CreateCheckbuttonGadgets();
8896   CreateCounterButtons();
8897   CreateRadiobuttonGadgets();
8898   CreateTextInputGadgets();
8899   CreateTextAreaGadgets();
8900   CreateSelectboxGadgets();
8901   CreateGraphicbuttonGadgets();
8902   CreateTextbuttonGadgets();
8903   CreateDrawingAreas();
8904
8905   ResetFontStatus();
8906 }
8907
8908 void FreeLevelEditorGadgets(void)
8909 {
8910   int i;
8911
8912   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8913
8914   for (i = 0; i < num_editor_gadgets; i++)
8915   {
8916     FreeGadget(level_editor_gadget[i]);
8917
8918     level_editor_gadget[i] = NULL;
8919   }
8920
8921   checked_free(level_editor_gadget);
8922   checked_free(right_gadget_border);
8923
8924   checked_free(editor_el_empty);
8925 }
8926
8927 static void MapCounterButtons(int id)
8928 {
8929   int font_nr = FONT_TEXT_1;
8930   int font_height = getFontHeight(font_nr);
8931   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8932   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8933   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8934   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8935   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8936   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8937   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8938   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8939   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8940   int yoffset = (gi_down->height - font_height) / 2;
8941   int x_left = gi_down->x - xoffset_left;
8942   int x_right;  // set after gadget position was modified
8943   int y_above = gi_down->y - yoffset_above;
8944   int x = gi_down->x;
8945   int y;        // set after gadget position was modified
8946
8947   // counter limits must be changed first to prevent value truncation
8948   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8949                             counterbutton_info[id].max_value);
8950
8951   // right text position might have changed after setting position above
8952   x_right = gi_up->x + gi_up->width + xoffset_right;
8953
8954   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8955
8956   // set position for counter gadgets with dynamically determined position
8957   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8958   {
8959     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8960     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8961     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8962   }
8963
8964   // vertical position might have changed after setting position above
8965   y = gi_up->y + yoffset;
8966
8967   if (counterbutton_info[id].text_above)
8968     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8969
8970   if (counterbutton_info[id].text_left)
8971     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8972
8973   if (counterbutton_info[id].text_right)
8974     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8975
8976   MapGadget(gi_down);
8977   MapGadget(gi_text);
8978   MapGadget(gi_up);
8979 }
8980
8981 static void MapControlButtons(void)
8982 {
8983   int counter_id;
8984   int i;
8985
8986   // map toolbox buttons (excluding special CE toolbox buttons)
8987   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
8988     MapGadget(level_editor_gadget[i]);
8989
8990   // map toolbox buttons (element properties buttons)
8991   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
8992     MapGadget(level_editor_gadget[i]);
8993
8994   if (use_permanent_palette)
8995   {
8996     // map buttons to select elements
8997     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8998       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
8999     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
9000     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
9001     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
9002   }
9003
9004   // map buttons to select level
9005   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
9006   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
9007   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
9008   MapCounterButtons(counter_id);
9009 }
9010
9011 static void MapDrawingArea(int id)
9012 {
9013   int font_nr = FONT_TEXT_1;
9014   int font_height = getFontHeight(font_nr);
9015   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9016   int area_xsize = gi->drawing.area_xsize;
9017   int area_ysize = gi->drawing.area_ysize;
9018   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9019   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
9020   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
9021   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
9022   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
9023   int x_below = gi->x + (gi->width - xoffset_below) / 2;
9024   int y_side  = gi->y + (gi->height - font_height) / 2;
9025   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
9026   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
9027
9028   if (drawingarea_info[id].text_left)
9029     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
9030
9031   if (drawingarea_info[id].text_right)
9032     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
9033
9034   if (drawingarea_info[id].text_above)
9035     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
9036
9037   if (drawingarea_info[id].text_below)
9038     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
9039
9040   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
9041   {
9042     DrawElementBorder(gi->x, gi->y,
9043                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
9044                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
9045
9046     DrawDrawingArea(id);
9047   }
9048
9049   MapGadget(gi);
9050 }
9051
9052 static void MapTextInputGadget(int id)
9053 {
9054   int font_nr = FONT_TEXT_1;
9055   int font_height = getFontHeight(font_nr);
9056   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
9057   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9058   int x_above = ED_SETTINGS_X(textinput_info[id].x);
9059   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
9060
9061   if (textinput_info[id].text_above)
9062     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
9063
9064   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
9065
9066   MapGadget(gi);
9067 }
9068
9069 static void MapTextAreaGadget(int id)
9070 {
9071   int font_nr = FONT_TEXT_1;
9072   int font_height = getFontHeight(font_nr);
9073   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
9074   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9075   int x_above = ED_SETTINGS_X(textarea_info[id].x);
9076   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
9077   char *text_above = textarea_info[id].text_above;
9078
9079   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
9080     text_above = textarea_info[id].text_above_cropped;
9081
9082   if (text_above)
9083     DrawTextS(x_above, y_above, font_nr, text_above);
9084
9085   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
9086
9087   MapGadget(gi);
9088 }
9089
9090 static void MapSelectboxGadget(int id)
9091 {
9092   int font_nr = FONT_TEXT_1;
9093   int font_height = getFontHeight(font_nr);
9094   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
9095   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
9096   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9097   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9098   int yoffset = (gi->height - font_height) / 2;
9099   int x_left = gi->x - xoffset_left;
9100   int x_right = gi->x + gi->width + xoffset_right;
9101   int y_above = gi->y - yoffset_above;
9102   int x = gi->x;
9103   int y = gi->y + yoffset;
9104
9105   if (selectbox_info[id].text_above)
9106     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
9107
9108   if (selectbox_info[id].text_left)
9109     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
9110
9111   if (selectbox_info[id].text_right)
9112     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
9113
9114   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
9115
9116   MapGadget(gi);
9117 }
9118
9119 static void MapTextbuttonGadget(int id)
9120 {
9121   int font_nr = FONT_TEXT_1;
9122   int font_height = getFontHeight(font_nr);
9123   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
9124   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
9125   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9126   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9127   int yoffset = (gi->height - font_height) / 2;
9128   int x_left = gi->x - xoffset_left;
9129   int x_right = gi->x + gi->width + xoffset_right;
9130   int y_above = gi->y - yoffset_above;
9131   int x = gi->x;
9132   int y = gi->y + yoffset;
9133
9134   // only show button to delete change pages when more than minimum pages
9135   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
9136       custom_element.num_change_pages == MIN_CHANGE_PAGES)
9137     return;
9138
9139   if (textbutton_info[id].text_above)
9140     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
9141
9142   if (textbutton_info[id].text_left)
9143     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
9144
9145   if (textbutton_info[id].text_right)
9146     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
9147
9148   MapGadget(gi);
9149 }
9150
9151 static void MapGraphicbuttonGadget(int id)
9152 {
9153   int font_nr = FONT_TEXT_1;
9154   int font_height = getFontHeight(font_nr);
9155   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
9156   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
9157   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9158   int yoffset = (gi->height - font_height) / 2;
9159   int x_left = gi->x - xoffset_left;
9160   int x_right = gi->x + gi->width + xoffset_right;
9161   int y = gi->y + yoffset;
9162
9163   if (graphicbutton_info[id].text_left)
9164     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
9165
9166   if (graphicbutton_info[id].text_right)
9167     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
9168
9169   MapGadget(gi);
9170 }
9171
9172 static void MapRadiobuttonGadget(int id)
9173 {
9174   int font_nr = FONT_TEXT_1;
9175   int font_height = getFontHeight(font_nr);
9176   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
9177   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9178   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9179   int yoffset = (gi->height - font_height) / 2;
9180   int x_left = gi->x - xoffset_left;
9181   int x_right = gi->x + gi->width + xoffset_right;
9182   int y = gi->y + yoffset;
9183   boolean checked =
9184     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
9185
9186   if (radiobutton_info[id].text_left)
9187     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
9188
9189   if (radiobutton_info[id].text_right)
9190     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
9191
9192   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
9193
9194   MapGadget(gi);
9195 }
9196
9197 static void MapCheckbuttonGadget(int id)
9198 {
9199   int font_nr = FONT_TEXT_1;
9200   int font_height = getFontHeight(font_nr);
9201   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
9202   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9203   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9204   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9205   int yoffset = (gi->height - font_height) / 2;
9206   int y_above = gi->y - yoffset_above;
9207   int x = gi->x;
9208   int x_left, x_right, y;       // set after gadget position was modified
9209
9210   // set position for gadgets with dynamically determined position
9211   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9212     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9213   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9214
9215   x_left = gi->x - xoffset_left;
9216   x_right = gi->x + gi->width + xoffset_right;
9217   y = gi->y + yoffset;
9218
9219   if (checkbutton_info[id].text_above)
9220     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9221
9222   if (checkbutton_info[id].text_left)
9223     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9224
9225   if (checkbutton_info[id].text_right)
9226     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9227
9228   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9229
9230   MapGadget(gi);
9231 }
9232
9233 static void MapMainDrawingArea(void)
9234 {
9235   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9236   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9237   int i;
9238
9239   if (suppressBorderElement())
9240   {
9241     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9242     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9243   }
9244
9245   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9246   {
9247     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9248           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9249          no_horizontal_scrollbar) ||
9250         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9251           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9252          no_vertical_scrollbar))
9253       continue;
9254
9255     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9256   }
9257
9258   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9259   {
9260     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9261         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9262       continue;
9263
9264     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9265   }
9266
9267   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9268 }
9269
9270 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9271 {
9272   int i;
9273
9274   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9275   {
9276     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9277         i == GADGET_ID_CUSTOM_COPY_TO ||
9278         i == GADGET_ID_CUSTOM_EXCHANGE ||
9279         i == GADGET_ID_CUSTOM_COPY ||
9280         i == GADGET_ID_CUSTOM_PASTE)
9281     {
9282       if (map)
9283         MapGadget(level_editor_gadget[i]);
9284       else
9285         UnmapGadget(level_editor_gadget[i]);
9286     }
9287   }
9288 }
9289
9290 static void MapLevelEditorToolboxCustomGadgets(void)
9291 {
9292   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9293 }
9294
9295 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9296 {
9297   if (IS_CUSTOM_ELEMENT(properties_element) ||
9298       IS_GROUP_ELEMENT(properties_element) ||
9299       IS_EMPTY_ELEMENT(properties_element))
9300     MapLevelEditorToolboxCustomGadgets();
9301 }
9302
9303 static void UnmapLevelEditorToolboxCustomGadgets(void)
9304 {
9305   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9306 }
9307
9308 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9309 {
9310   int i;
9311
9312   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9313   {
9314     if (i != GADGET_ID_SINGLE_ITEMS &&
9315         i != GADGET_ID_PICK_ELEMENT)
9316     {
9317       struct GadgetInfo *gi = level_editor_gadget[i];
9318
9319       if (map)
9320       {
9321         MapGadget(gi);
9322       }
9323       else
9324       {
9325         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9326         struct GraphicInfo *gd = &graphic_info[graphic];
9327
9328         UnmapGadget(gi);
9329
9330         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9331                    gi->width, gi->height, gi->x, gi->y);
9332
9333         redraw_mask |= REDRAW_DOOR_3;
9334       }
9335     }
9336   }
9337 }
9338
9339 static void MapLevelEditorToolboxDrawingGadgets(void)
9340 {
9341   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9342 }
9343
9344 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9345 {
9346   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9347 }
9348
9349 static void UnmapDrawingArea(int id)
9350 {
9351   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9352 }
9353
9354 static void UnmapLevelEditorFieldGadgets(void)
9355 {
9356   int i;
9357
9358   for (i = 0; i < num_editor_gadgets; i++)
9359     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9360                           level_editor_gadget[i]->y))
9361       UnmapGadget(level_editor_gadget[i]);
9362 }
9363
9364 void UnmapLevelEditorGadgets(void)
9365 {
9366   int i;
9367
9368   for (i = 0; i < num_editor_gadgets; i++)
9369     UnmapGadget(level_editor_gadget[i]);
9370 }
9371
9372 static void ResetUndoBuffer(void)
9373 {
9374   undo_buffer_position = -1;
9375   undo_buffer_steps = -1;
9376   redo_buffer_steps = 0;
9377
9378   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9379
9380   level.changed = FALSE;
9381 }
9382
9383 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9384 {
9385   if (remap_toolbox_gadgets)
9386   {
9387     ModifyEditorElementList();
9388     RedrawDrawingElements();
9389   }
9390
9391   if (edit_mode == ED_MODE_LEVELCONFIG)
9392     DrawLevelConfigWindow();
9393   else if (edit_mode == ED_MODE_PROPERTIES)
9394     DrawPropertiesWindow();
9395   else if (edit_mode == ED_MODE_PALETTE)
9396     DrawPaletteWindow();
9397   else  // edit_mode == ED_MODE_DRAWING
9398     DrawDrawingWindowExt(remap_toolbox_gadgets);
9399 }
9400
9401 static void DrawEditModeWindow(void)
9402 {
9403   DrawEditModeWindowExt(TRUE);
9404 }
9405
9406 static void DrawEditModeWindow_PlayfieldOnly(void)
9407 {
9408   DrawEditModeWindowExt(FALSE);
9409 }
9410
9411 static void ChangeEditModeWindow(int new_edit_mode)
9412 {
9413   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9414
9415   DrawEditModeWindow();
9416 }
9417
9418 static boolean LevelChanged(void)
9419 {
9420   boolean field_changed = FALSE;
9421   int x, y;
9422
9423   for (y = 0; y < lev_fieldy; y++) 
9424     for (x = 0; x < lev_fieldx; x++)
9425       if (Tile[x][y] != level.field[x][y])
9426         field_changed = TRUE;
9427
9428   return (level.changed || field_changed);
9429 }
9430
9431 static boolean PrepareSavingIntoPersonalLevelSet(void)
9432 {
9433   static LevelDirTree *last_copied_leveldir = NULL;
9434   static LevelDirTree *last_written_leveldir = NULL;
9435   static int last_copied_level_nr = -1;
9436   static int last_written_level_nr = -1;
9437   LevelDirTree *leveldir_former = leveldir_current;
9438   int level_nr_former = level_nr;
9439   int new_level_nr;
9440
9441   // remember last mod/save so that for current session, we write
9442   // back to the same personal copy, asking only about overwrite.
9443   if (leveldir_current == last_copied_leveldir &&
9444       level_nr == last_copied_level_nr)
9445   {
9446     // "cd" to personal level set dir (as used when writing last copy)
9447     leveldir_current = last_written_leveldir;
9448     level_nr = last_written_level_nr;
9449
9450     return TRUE;
9451   }
9452
9453   if (!Request("This level is read-only! "
9454                "Save into personal level set?", REQ_ASK))
9455     return FALSE;
9456
9457   // "cd" to personal level set dir (for writing copy the first time)
9458   leveldir_current =
9459     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9460
9461   // this may happen if "setup.internal.create_user_levelset" is FALSE
9462   // or if file "levelinfo.conf" is missing in personal user level set
9463   if (leveldir_current == NULL)
9464   {
9465     Request("Cannot find personal level set?!", REQ_CONFIRM);
9466
9467     leveldir_current = leveldir_former;
9468
9469     return FALSE;
9470   }
9471
9472   // find unused level number
9473   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9474   {
9475     static char *level_filename = NULL;
9476
9477     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9478
9479     if (!fileExists(level_filename))
9480       break;
9481   }
9482
9483   last_copied_leveldir = leveldir_former;
9484   last_copied_level_nr = level_nr_former;
9485
9486   last_written_leveldir = leveldir_current;
9487   last_written_level_nr = level_nr = new_level_nr;
9488
9489   return TRUE;
9490 }
9491
9492 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9493 {
9494   static char *filename_levelinfo = NULL, *mod_name = NULL;
9495   FILE *file;
9496
9497   // annotate this copy-and-mod in personal levelinfo.conf
9498   setString(&filename_levelinfo,
9499             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9500
9501   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9502   {
9503     fprintf(file, "\n");
9504     fprintf(file, "# level %d was modified from:\n", level_nr);
9505     fprintf(file, "# - previous level set name:    %s\n",
9506             former_name);
9507     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9508             level.file_info.nr, level.name);
9509     fprintf(file, "# - previous author:            %s\n",
9510             level.author);
9511     fprintf(file, "# - previous save date:         ");
9512
9513     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9514     {
9515       fprintf(file, "%04d-%02d-%02d\n",
9516               level.creation_date.year,
9517               level.creation_date.month,
9518               level.creation_date.day);
9519     }
9520     else
9521     {
9522       fprintf(file, "not recorded\n");
9523     }
9524
9525     fclose(file);
9526   }
9527
9528   if (level_nr > leveldir_current->last_level)
9529     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9530
9531   // else: allow the save even if annotation failed
9532
9533   // now... spray graffiti on the old level vital statistics
9534   // user can change these; just trying to set a good baseline
9535
9536   // don't truncate names for fear of making offensive or silly:
9537   // long-named original author only recorded in levelinfo.conf.
9538   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9539   if (!strEqual(level.author, leveldir_current->author))
9540   {
9541     setString(&mod_name, getStringCat3(leveldir_current->author,
9542                                        " after ", level.author));
9543
9544     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9545       setString(&mod_name,
9546                 getStringCat2(leveldir_current->author, " (ed.)"));
9547
9548     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9549       setString(&mod_name, leveldir_current->author);
9550
9551     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9552
9553     // less worried about truncation here
9554     setString(&mod_name, getStringCat2("Mod: ", level.name));
9555     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9556   }
9557 }
9558
9559 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9560                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9561 {
9562   int x, y;
9563
9564   for (x = 0; x < lev_fieldx; x++)
9565     for (y = 0; y < lev_fieldy; y++) 
9566       dst[x][y] = src[x][y];
9567 }
9568
9569 static int setSelectboxValue(int selectbox_id, int new_value)
9570 {
9571   int new_index_value = 0;
9572   int i;
9573
9574   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9575     if (selectbox_info[selectbox_id].options[i].value == new_value)
9576       new_index_value = i;
9577
9578   *selectbox_info[selectbox_id].value =
9579     selectbox_info[selectbox_id].options[new_index_value].value;
9580
9581   return new_index_value;
9582 }
9583
9584 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9585 {
9586   int i;
9587
9588   // change action mode and arg variables according to action type variable
9589   for (i = 0; action_arg_options[i].value != -1; i++)
9590   {
9591     if (action_arg_options[i].value == custom_element_change.action_type)
9592     {
9593       int mode = action_arg_options[i].mode;
9594
9595       // only change if corresponding selectbox has changed
9596       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9597           action_arg_modes[mode])
9598         custom_element_change.action_mode = -1;
9599
9600       // only change if corresponding selectbox has changed
9601       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9602           action_arg_options[i].options)
9603         custom_element_change.action_arg = -1;
9604
9605       break;
9606     }
9607   }
9608 }
9609
9610 static void setSelectboxSpecialActionOptions(void)
9611 {
9612   int i;
9613
9614   // change action mode and arg selectbox according to action type selectbox
9615   for (i = 0; action_arg_options[i].value != -1; i++)
9616   {
9617     if (action_arg_options[i].value == custom_element_change.action_type)
9618     {
9619       int mode = action_arg_options[i].mode;
9620
9621       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9622                                    action_arg_modes[mode]);
9623       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9624                                  custom_element_change.action_mode);
9625
9626       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9627                                    action_arg_options[i].options);
9628       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9629                                  custom_element_change.action_arg);
9630       break;
9631     }
9632   }
9633 }
9634
9635 static void copy_custom_element_settings(int element_from, int element_to)
9636 {
9637   struct ElementInfo *ei_from = &element_info[element_from];
9638   struct ElementInfo *ei_to = &element_info[element_to];
9639
9640   copyElementInfo(ei_from, ei_to);
9641 }
9642
9643 static void replace_custom_element_in_settings(int element_from,
9644                                                int element_to)
9645 {
9646   int i, j, x, y;
9647
9648   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9649   {
9650     struct ElementInfo *ei = &element_info[i];
9651
9652     for (y = 0; y < 3; y++)
9653       for (x = 0; x < 3; x++)
9654         if (ei->content.e[x][y] == element_from)
9655           ei->content.e[x][y] = element_to;
9656
9657     for (j = 0; j < ei->num_change_pages; j++)
9658     {
9659       struct ElementChangeInfo *change = &ei->change_page[j];
9660
9661       if (change->target_element == element_from)
9662         change->target_element = element_to;
9663
9664       if (change->initial_trigger_element == element_from)
9665         change->initial_trigger_element = element_to;
9666
9667       if (change->action_element == element_from)
9668         change->action_element = element_to;
9669
9670       for (y = 0; y < 3; y++)
9671         for (x = 0; x < 3; x++)
9672           if (change->target_content.e[x][y] == element_from)
9673             change->target_content.e[x][y] = element_to;
9674     }
9675
9676     if (ei->group != NULL)                              // group or internal
9677       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9678         if (ei->group->element[j] == element_from)
9679           ei->group->element[j] = element_to;
9680   }
9681 }
9682
9683 static void replace_custom_element_in_playfield(int element_from,
9684                                                 int element_to)
9685 {
9686   int x, y;
9687
9688   for (x = 0; x < lev_fieldx; x++)
9689     for (y = 0; y < lev_fieldy; y++)
9690       if (Tile[x][y] == element_from)
9691         Tile[x][y] = element_to;
9692 }
9693
9694 static boolean CopyCustomElement(int element_old, int element_new,
9695                                  int copy_mode)
9696 {
9697   int copy_mode_orig = copy_mode;
9698
9699   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9700   {
9701     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9702                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9703     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9704   }
9705   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9706   {
9707     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9708                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9709     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9710
9711     level.changed = TRUE;
9712   }
9713   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9714   {
9715     Request("Please choose custom element!", REQ_CONFIRM);
9716
9717     return FALSE;
9718   }
9719   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9720   {
9721     Request("Please choose group element!", REQ_CONFIRM);
9722
9723     return FALSE;
9724   }
9725   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9726   {
9727     Request("Please choose empty element!", REQ_CONFIRM);
9728
9729     return FALSE;
9730   }
9731   else
9732   {
9733     level.changed = TRUE;
9734   }
9735
9736   // when modifying custom/group element, ask for copying level template
9737   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9738   {
9739     if (!AskToCopyAndModifyLevelTemplate())
9740       return FALSE;
9741   }
9742
9743   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9744   {
9745     copy_custom_element_settings(element_new, element_old);
9746   }
9747   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9748   {
9749     copy_custom_element_settings(element_old, element_new);
9750   }
9751   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9752   {
9753     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9754     copy_custom_element_settings(element_new, element_old);
9755     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9756
9757     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9758     replace_custom_element_in_settings(element_new, element_old);
9759     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9760
9761     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9762     replace_custom_element_in_playfield(element_new, element_old);
9763     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9764   }
9765
9766   UpdateCustomElementGraphicGadgets();
9767   DrawPropertiesWindow();
9768
9769   return TRUE;
9770 }
9771
9772 static void CopyCustomElementPropertiesToEditor(int element)
9773 {
9774   int i;
9775   int current_change_page = element_info[element].current_change_page;
9776
9777   // dynamically (re)build selectbox for selecting change page
9778   for (i = 0; i < element_info[element].num_change_pages; i++)
9779   {
9780     sprintf(options_change_page_strings[i], "%d", i + 1);
9781
9782     options_change_page[i].value = i;
9783     options_change_page[i].text = options_change_page_strings[i];
9784   }
9785
9786   options_change_page[i].value = -1;
9787   options_change_page[i].text = NULL;
9788
9789   // needed here to initialize combined element properties
9790   InitElementPropertiesEngine(level.game_version);
9791
9792   element_info[element].change =
9793     &element_info[element].change_page[current_change_page];
9794
9795   custom_element = element_info[element];
9796   custom_element_change = *element_info[element].change;
9797
9798   // needed to initially set selectbox options for special action options
9799   setSelectboxSpecialActionOptions();
9800
9801   // needed to initially set selectbox value variables to reliable defaults
9802   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9803     setSelectboxValue(i, *selectbox_info[i].value);
9804
9805   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9806     custom_element_properties[i] = HAS_PROPERTY(element, i);
9807
9808   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9809     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9810
9811   // ---------- element settings: configure (custom elements) -----------------
9812
9813   // set accessible layer selectbox help value
9814   custom_element.access_type =
9815     (IS_WALKABLE(element) ? EP_WALKABLE :
9816      IS_PASSABLE(element) ? EP_PASSABLE :
9817      custom_element.access_type);
9818   custom_element.access_layer =
9819     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9820      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9821      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9822      custom_element.access_layer);
9823   custom_element.access_protected =
9824     (IS_PROTECTED(element) ? 1 : 0);
9825   custom_element_properties[EP_ACCESSIBLE] =
9826     (IS_ACCESSIBLE_OVER(element) ||
9827      IS_ACCESSIBLE_INSIDE(element) ||
9828      IS_ACCESSIBLE_UNDER(element));
9829
9830   // set walk-to-object action selectbox help value
9831   custom_element.walk_to_action =
9832     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9833      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9834      IS_DROPPABLE(element) ? EP_DROPPABLE :
9835      IS_THROWABLE(element) ? EP_THROWABLE :
9836      IS_PUSHABLE(element) ? EP_PUSHABLE :
9837      custom_element.walk_to_action);
9838   custom_element_properties[EP_WALK_TO_OBJECT] =
9839     (IS_DIGGABLE(element) ||
9840      IS_COLLECTIBLE_ONLY(element) ||
9841      IS_DROPPABLE(element) ||
9842      IS_THROWABLE(element) ||
9843      IS_PUSHABLE(element));
9844
9845   // set smash targets selectbox help value
9846   custom_element.smash_targets =
9847     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9848      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9849      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9850      custom_element.smash_targets);
9851   custom_element_properties[EP_CAN_SMASH] =
9852     (CAN_SMASH_EVERYTHING(element) ||
9853      CAN_SMASH_ENEMIES(element) ||
9854      CAN_SMASH_PLAYER(element));
9855
9856   // set deadliness selectbox help value
9857   custom_element.deadliness =
9858     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9859      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9860      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9861      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9862      custom_element.deadliness);
9863   custom_element_properties[EP_DEADLY] =
9864     (DONT_TOUCH(element) ||
9865      DONT_GET_HIT_BY(element) ||
9866      DONT_COLLIDE_WITH(element) ||
9867      DONT_RUN_INTO(element));
9868
9869   // ---------- element settings: advanced (custom elements) ------------------
9870
9871   // set "change by direct action" selectbox help value
9872   custom_element_change.direct_action =
9873     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9874      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9875      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9876      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9877      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9878      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9879      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9880      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9881      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9882      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9883      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9884      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9885      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9886      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9887      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9888      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9889      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9890      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9891      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9892      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9893      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9894      custom_element_change.direct_action);
9895
9896   // set "change by other element action" selectbox help value
9897   custom_element_change.other_action =
9898     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9899      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9900      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9901      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9902      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9903      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9904      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9905      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9906      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9907      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9908      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9909      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9910      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9911      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9912      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9913      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9914      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9915      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9916      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9917      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9918      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9919      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9920      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9921      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9922      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9923      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9924      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9925      custom_element_change.other_action);
9926 }
9927
9928 static void CopyGroupElementPropertiesToEditor(int element)
9929 {
9930   group_element_info = *element_info[element].group;
9931   custom_element = element_info[element];       // needed for description
9932 }
9933
9934 static void CopyEmptyElementPropertiesToEditor(int element)
9935 {
9936   custom_element = element_info[element];
9937 }
9938
9939 static void CopyClassicElementPropertiesToEditor(int element)
9940 {
9941   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9942     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9943       getMoveIntoAcidProperty(&level, element);
9944
9945   if (MAYBE_DONT_COLLIDE_WITH(element))
9946     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9947       getDontCollideWithProperty(&level, element);
9948 }
9949
9950 static void CopyElementPropertiesToEditor(int element)
9951 {
9952   if (IS_CUSTOM_ELEMENT(element))
9953     CopyCustomElementPropertiesToEditor(element);
9954   else if (IS_GROUP_ELEMENT(element))
9955     CopyGroupElementPropertiesToEditor(element);
9956   else if (IS_EMPTY_ELEMENT(element))
9957     CopyEmptyElementPropertiesToEditor(element);
9958   else
9959     CopyClassicElementPropertiesToEditor(element);
9960 }
9961
9962 static boolean AskToCopyAndModifyLevelTemplate(void)
9963 {
9964   if (Request("Copy and modify settings from level template?", REQ_ASK))
9965   {
9966     level.use_custom_template = FALSE;
9967
9968     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9969                  GDI_CHECKED, FALSE, GDI_END);
9970     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9971                  GDI_CHECKED, FALSE, GDI_END);
9972
9973     return TRUE;
9974   }
9975   else
9976   {
9977     LoadLevelTemplate(-1);      // this resets all element modifications ...
9978
9979     DrawEditModeWindow();       // ... and copies them to 'custom_element'
9980
9981     return FALSE;
9982   }
9983 }
9984
9985 static void CopyCustomElementPropertiesToGame(int element)
9986 {
9987   int i;
9988   int access_type_and_layer;
9989
9990   // mark that this custom element has been modified
9991   custom_element.modified_settings = TRUE;
9992   level.changed = TRUE;
9993
9994   if (level.use_custom_template)
9995     AskToCopyAndModifyLevelTemplate();
9996
9997   element_info[element] = custom_element;
9998   *element_info[element].change = custom_element_change;
9999
10000   // ---------- element settings: configure (custom elements) -----------------
10001
10002   // set accessible property from checkbox and selectbox
10003   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
10004   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
10005   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
10006   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
10007   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
10008   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
10009   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
10010                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
10011                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
10012   custom_element_properties[access_type_and_layer] =
10013     custom_element_properties[EP_ACCESSIBLE];
10014   custom_element_properties[EP_PROTECTED] =
10015     (custom_element.access_protected != 0 &&
10016      custom_element_properties[EP_ACCESSIBLE]);
10017
10018   // set walk-to-object property from checkbox and selectbox
10019   custom_element_properties[EP_DIGGABLE] = FALSE;
10020   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
10021   custom_element_properties[EP_DROPPABLE] = FALSE;
10022   custom_element_properties[EP_THROWABLE] = FALSE;
10023   custom_element_properties[EP_PUSHABLE] = FALSE;
10024   custom_element_properties[custom_element.walk_to_action] =
10025     custom_element_properties[EP_WALK_TO_OBJECT];
10026
10027   // set smash property from checkbox and selectbox
10028   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
10029   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
10030   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
10031   custom_element_properties[custom_element.smash_targets] =
10032     custom_element_properties[EP_CAN_SMASH];
10033
10034   // set deadliness property from checkbox and selectbox
10035   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
10036   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
10037   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
10038   custom_element_properties[EP_DONT_TOUCH] = FALSE;
10039   custom_element_properties[custom_element.deadliness] =
10040     custom_element_properties[EP_DEADLY];
10041
10042   // ---------- element settings: advanced (custom elements) ------------------
10043
10044   // set player change event from checkbox and selectbox
10045   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
10046   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
10047   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
10048   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
10049   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
10050   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
10051   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
10052   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
10053   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
10054   custom_element_change_events[CE_SWITCHED] = FALSE;
10055   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
10056   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
10057   custom_element_change_events[CE_BLOCKED] = FALSE;
10058   custom_element_change_events[CE_IMPACT] = FALSE;
10059   custom_element_change_events[CE_SMASHED] = FALSE;
10060   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
10061   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
10062   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
10063   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
10064   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
10065   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
10066   custom_element_change_events[custom_element_change.direct_action] =
10067     custom_element_change_events[CE_BY_DIRECT_ACTION];
10068
10069   // set other element action change event from checkbox and selectbox
10070   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
10071   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
10072   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
10073   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
10074   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
10075   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
10076   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
10077   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
10078   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
10079   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
10080   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
10081   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
10082   custom_element_change_events[CE_TOUCHING_X] = FALSE;
10083   custom_element_change_events[CE_HITTING_X] = FALSE;
10084   custom_element_change_events[CE_DIGGING_X] = FALSE;
10085   custom_element_change_events[CE_HIT_BY_X] = FALSE;
10086   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
10087   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
10088   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
10089   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
10090   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
10091   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
10092   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
10093   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
10094   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
10095   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
10096   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
10097   custom_element_change_events[custom_element_change.other_action] =
10098     custom_element_change_events[CE_BY_OTHER_ACTION];
10099
10100   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
10101     SET_PROPERTY(element, i, custom_element_properties[i]);
10102
10103   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
10104     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
10105
10106   // copy change events also to special level editor variable
10107   custom_element = element_info[element];
10108   custom_element_change = *element_info[element].change;
10109
10110   // needed here to restore runtime value "element_info[element].gfx_element"
10111   InitElementPropertiesGfxElement();
10112 }
10113
10114 static void CopyGroupElementPropertiesToGame(int element)
10115 {
10116   // mark that this group element has been modified
10117   custom_element.modified_settings = TRUE;
10118   level.changed = TRUE;
10119
10120   if (level.use_custom_template)
10121     AskToCopyAndModifyLevelTemplate();
10122
10123   element_info[element] = custom_element;
10124   *element_info[element].group = group_element_info;
10125
10126   // needed here to restore runtime value "element_info[element].gfx_element"
10127   InitElementPropertiesGfxElement();
10128 }
10129
10130 static void CopyEmptyElementPropertiesToGame(int element)
10131 {
10132   // mark that this empty element has been modified
10133   custom_element.modified_settings = TRUE;
10134   level.changed = TRUE;
10135
10136   if (level.use_custom_template)
10137     AskToCopyAndModifyLevelTemplate();
10138
10139   element_info[element] = custom_element;
10140
10141   // needed here to restore runtime value "element_info[element].gfx_element"
10142   InitElementPropertiesGfxElement();
10143 }
10144
10145 static void CopyClassicElementPropertiesToGame(int element)
10146 {
10147   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
10148     setMoveIntoAcidProperty(&level, element,
10149                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
10150
10151   if (MAYBE_DONT_COLLIDE_WITH(element))
10152     setDontCollideWithProperty(&level, element,
10153                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
10154 }
10155
10156 static void CopyElementPropertiesToGame(int element)
10157 {
10158   if (IS_CUSTOM_ELEMENT(element))
10159     CopyCustomElementPropertiesToGame(element);
10160   else if (IS_GROUP_ELEMENT(element))
10161     CopyGroupElementPropertiesToGame(element);
10162   else if (IS_EMPTY_ELEMENT(element))
10163     CopyEmptyElementPropertiesToGame(element);
10164   else
10165     CopyClassicElementPropertiesToGame(element);
10166 }
10167
10168 #if DEBUG
10169 static void CheckElementDescriptions(void)
10170 {
10171   int i;
10172
10173   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10174     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
10175       Warn("no element description file for element '%s'", EL_NAME(i));
10176 }
10177 #endif
10178
10179 static int getMaxEdFieldX(boolean has_scrollbar)
10180 {
10181   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
10182   int sxsize = SXSIZE - scrollbar_width;
10183   int max_ed_fieldx = sxsize / ed_tilesize;
10184
10185   return max_ed_fieldx;
10186 }
10187
10188 static int getMaxEdFieldY(boolean has_scrollbar)
10189 {
10190   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
10191                          INFOTEXT_YSIZE_FULL : 0);
10192   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
10193   int sysize = SYSIZE - scrollbar_height - infotext_height;
10194   int max_ed_fieldy = sysize / ed_tilesize;
10195
10196   return max_ed_fieldy;
10197 }
10198
10199 static void InitZoomLevelSettings(int zoom_tilesize)
10200 {
10201   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
10202
10203   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
10204   {
10205     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10206     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10207
10208     // make sure that tile size is always a power of 2
10209     ed_tilesize = (1 << log_2(ed_tilesize));
10210
10211     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10212     {
10213       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10214       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10215     }
10216   }
10217
10218   last_game_engine_type = level.game_engine_type;
10219
10220   // limit zoom tilesize by upper and lower bound
10221   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10222
10223   // store zoom tilesize in auto setup file only if it was manually changed
10224   if (zoom_tilesize != -1)
10225     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10226
10227   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10228   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10229 }
10230
10231 static void InitDrawingElements(void)
10232 {
10233   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10234
10235   if (level.game_engine_type == game_engine_type_last)
10236     return;
10237
10238   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10239   {
10240     new_element1 = EL_BD_WALL;
10241     new_element2 = EL_EMPTY;
10242     new_element3 = EL_BD_SAND;
10243   }
10244   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10245   {
10246     new_element1 = EL_SP_CHIP_SINGLE;
10247     new_element2 = EL_EMPTY;
10248     new_element3 = EL_SP_BASE;
10249   }
10250   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10251   {
10252     new_element1 = EL_MM_MIRROR_START;
10253     new_element2 = EL_EMPTY;
10254     new_element3 = EL_MM_WOODEN_WALL;
10255   }
10256   else
10257   {
10258     new_element1 = EL_WALL;
10259     new_element2 = EL_EMPTY;
10260     new_element3 = EL_SAND;
10261   }
10262
10263   game_engine_type_last = level.game_engine_type;
10264 }
10265
10266 static void InitLevelSetInfo(void)
10267 {
10268   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10269            "%s", leveldir_current->name);
10270   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10271            "%s", leveldir_current->author);
10272
10273   levelset_num_levels = leveldir_current->levels;
10274
10275   levelset_use_levelset_artwork = FALSE;
10276   levelset_copy_level_template = FALSE;
10277
10278   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10279 }
10280
10281 static void ChangeEditorToLevelSet(char *levelset_subdir)
10282 {
10283   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10284
10285   // the previous level set might have used custom artwork
10286   ReloadCustomArtwork(0);
10287
10288   LoadLevelSetup_SeriesInfo();
10289
10290   SaveLevelSetup_LastSeries();
10291   SaveLevelSetup_SeriesInfo();
10292
10293   TapeErase();
10294
10295   LoadLevel(level_nr);
10296   LoadScore(level_nr);
10297
10298   DrawLevelEd();
10299 }
10300
10301 static boolean useEditorDoorAnimation(void)
10302 {
10303   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10304   boolean door_1_viewport_unchanged =
10305     (vp_door_1->x      == DX     &&
10306      vp_door_1->y      == DY     &&
10307      vp_door_1->width  == DXSIZE &&
10308      vp_door_1->height == DYSIZE);
10309   boolean door_1_contains_toolbox =
10310     (EX >= DX &&
10311      EY >= DY &&
10312      EX + EXSIZE <= DX + DXSIZE &&
10313      EY + EYSIZE <= DY + DYSIZE);
10314
10315   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10316 }
10317
10318 static void DrawEditorDoorBackground(int graphic, int x, int y,
10319                                      int width, int height)
10320 {
10321   struct GraphicInfo *g = &graphic_info[graphic];
10322
10323   if (g->bitmap != NULL)
10324     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10325                MIN(width, g->width), MIN(height, g->height), x, y);
10326   else
10327     ClearRectangle(drawto, x, y, width, height);
10328 }
10329
10330 static void DrawEditorDoorContent(void)
10331 {
10332   // needed for gadgets drawn on background (like palette scrollbar)
10333   SetDoorBackgroundImage(IMG_UNDEFINED);
10334
10335   // copy default editor door content to main double buffer
10336   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10337
10338   // draw bigger door
10339   DrawSpecialEditorDoor();
10340
10341   // draw new control window
10342   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10343
10344   // draw all toolbox gadgets to editor doors
10345   MapControlButtons();
10346
10347   // when returning from test game to properties page, redraw toolbox gadgets
10348   if (edit_mode == ED_MODE_PROPERTIES)
10349   {
10350     UnmapLevelEditorToolboxDrawingGadgets();
10351     UnmapLevelEditorToolboxCustomGadgets();
10352
10353     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10354   }
10355
10356   // draw all palette gadgets to editor doors
10357   ModifyEditorElementList();
10358   RedrawDrawingElements();
10359
10360   // copy actual editor door content to door double buffer for OpenDoor()
10361   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10362 }
10363
10364 void DrawLevelEd(void)
10365 {
10366   int fade_mask = REDRAW_FIELD;
10367
10368   FadeSoundsAndMusic();
10369
10370   if (CheckFadeAll())
10371     fade_mask = REDRAW_ALL;
10372
10373   FadeOut(fade_mask);
10374
10375   // needed if different viewport properties defined for editor
10376   ChangeViewportPropertiesIfNeeded();
10377
10378   ClearField();
10379
10380   InitZoomLevelSettings(-1);
10381   InitDrawingElements();
10382   InitLevelSetInfo();
10383
10384 #if DEBUG
10385   CheckElementDescriptions();
10386 #endif
10387
10388   if (level_editor_test_game)
10389   {
10390     CopyPlayfield(level.field, Tile);
10391     CopyPlayfield(TileBackup, level.field);
10392
10393     level_editor_test_game = FALSE;
10394   }
10395   else
10396   {
10397     edit_mode = ED_MODE_DRAWING;
10398     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10399     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10400
10401     ResetUndoBuffer();
10402
10403     level_xpos = -1;
10404     level_ypos = -1;
10405   }
10406
10407   // redraw_mask |= REDRAW_ALL;
10408
10409   FreeLevelEditorGadgets();
10410   CreateLevelEditorGadgets();
10411
10412   ReinitializeElementList();            // update dynamic level element list
10413   ReinitializeElementListButtons();     // custom element may look different
10414
10415   InitElementPropertiesGfxElement();
10416
10417   UnmapAllGadgets();
10418
10419   DrawEditModeWindow_PlayfieldOnly();
10420
10421   DrawMaskedBorder(fade_mask);
10422
10423   // use door animation if door 1 viewport is unchanged and contains toolbox
10424   if (useEditorDoorAnimation())
10425   {
10426     FadeIn(fade_mask);
10427
10428     DrawEditorDoorContent();
10429
10430     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10431   }
10432   else
10433   {
10434     DrawEditorDoorContent();
10435
10436     FadeIn(fade_mask);
10437   }
10438
10439   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10440 }
10441
10442 static void AdjustDrawingAreaGadgets(void)
10443 {
10444   int ed_xsize = lev_fieldx + 2;
10445   int ed_ysize = lev_fieldy + 2;
10446   int max_ed_fieldx = MAX_ED_FIELDX;
10447   int max_ed_fieldy = MAX_ED_FIELDY;
10448   boolean horizontal_scrollbar_needed;
10449   boolean vertical_scrollbar_needed;
10450   int x, y, width, height;
10451
10452   if (suppressBorderElement())
10453   {
10454     ed_xsize = lev_fieldx;
10455     ed_ysize = lev_fieldy;
10456   }
10457
10458   // check if we need any scrollbars
10459   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10460   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10461
10462   // check if we have a smaller editor field because of scrollbars
10463   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10464   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10465
10466   // check again if we now need more scrollbars because of less space
10467   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10468   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10469
10470   // check if editor field gets even smaller after adding new scrollbars
10471   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10472   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10473
10474   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10475   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10476
10477   x = SX + ed_fieldx * ed_tilesize;
10478   y = SY + ed_fieldy * ed_tilesize;
10479
10480   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10481   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10482
10483   // adjust drawing area gadget
10484   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10485                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10486                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10487                GDI_END);
10488
10489   // adjust horizontal scrollbar gadgets
10490   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10491                GDI_Y, y,
10492                GDI_END);
10493   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10494                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10495                GDI_Y, y,
10496                GDI_END);
10497   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10498                GDI_Y, y,
10499                GDI_WIDTH, width,
10500                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10501                GDI_END);
10502
10503   // adjust vertical scrollbar gadgets
10504   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10505                GDI_X, x,
10506                GDI_END);
10507   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10508                GDI_X, x,
10509                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10510                GDI_END);
10511   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10512                GDI_X, x,
10513                GDI_HEIGHT, height,
10514                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10515                GDI_END);
10516 }
10517
10518 static void AdjustLevelScrollPosition(void)
10519 {
10520   if (level_xpos < -1)
10521     level_xpos = -1;
10522   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10523     level_xpos = lev_fieldx - ed_fieldx + 1;
10524   if (lev_fieldx < ed_fieldx - 2)
10525     level_xpos = -1;
10526
10527   if (level_ypos < -1)
10528     level_ypos = -1;
10529   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10530     level_ypos = lev_fieldy - ed_fieldy + 1;
10531   if (lev_fieldy < ed_fieldy - 2)
10532     level_ypos = -1;
10533
10534   if (suppressBorderElement())
10535   {
10536     level_xpos = 0;
10537     level_ypos = 0;
10538   }
10539 }
10540
10541 static void AdjustEditorScrollbar(int id)
10542 {
10543   struct GadgetInfo *gi = level_editor_gadget[id];
10544   int items_max, items_visible, item_position;
10545
10546   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10547   {
10548     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10549     items_visible = ed_fieldx;
10550     item_position = level_xpos + 1;
10551   }
10552   else
10553   {
10554     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10555     items_visible = ed_fieldy;
10556     item_position = level_ypos + 1;
10557   }
10558
10559   if (item_position > items_max - items_visible)
10560     item_position = items_max - items_visible;
10561
10562   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10563                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10564 }
10565
10566 static void AdjustElementListScrollbar(void)
10567 {
10568   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10569   int items_max, items_visible, item_position;
10570
10571   // correct position of element list scrollbar
10572   if (element_shift < 0)
10573     element_shift = 0;
10574   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10575     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10576
10577   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10578   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10579   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10580
10581   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10582                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10583                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10584 }
10585
10586 static void ModifyEditorCounterValue(int counter_id, int new_value)
10587 {
10588   int *counter_value = counterbutton_info[counter_id].value;
10589   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10590   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10591
10592   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10593
10594   if (counter_value != NULL)
10595     *counter_value = gi->textinput.number_value;
10596 }
10597
10598 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10599 {
10600   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10601   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10602
10603   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10604
10605   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10606       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10607   {
10608     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10609     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10610
10611     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10612     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10613                  GDI_END);
10614   }
10615 }
10616
10617 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10618 {
10619   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10620   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10621   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10622
10623   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10624 }
10625
10626 static void ModifyEditorSelectboxOptions(int selectbox_id,
10627                                          struct ValueTextInfo *options)
10628 {
10629   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10630   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10631
10632   selectbox_info[selectbox_id].options = options;
10633
10634   // set index to zero -- list may be shorter now (correct later, if needed)
10635   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10636                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10637 }
10638
10639 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10640 {
10641   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10642   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10643
10644   drawingarea_info[drawingarea_id].area_xsize = xsize;
10645   drawingarea_info[drawingarea_id].area_ysize = ysize;
10646
10647   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10648 }
10649
10650 static void ModifyEditorElementList(void)
10651 {
10652   int i;
10653
10654   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10655     return;
10656
10657   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10658   {
10659     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10660     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10661     struct GadgetDesign *gd = &gi->deco.design;
10662     int element = editor_elements[element_shift + i];
10663     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10664
10665     UnmapGadget(gi);
10666
10667     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10668
10669     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10670
10671     MapGadget(gi);
10672   }
10673 }
10674
10675 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10676 {
10677   int graphic = el2edimg(element);
10678   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10679
10680   if (pos->x == -1 &&
10681       pos->y == -1)
10682     return;
10683
10684   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10685 }
10686
10687 static void ModifyDrawingElementButton(int element, int id)
10688 {
10689   struct GadgetInfo *gi = level_editor_gadget[id];
10690   Bitmap *deco_bitmap;
10691   int deco_x, deco_y;
10692   int tile_size = gi->deco.width;
10693
10694   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10695
10696   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10697 }
10698
10699 static void PickDrawingElement(int button, int element)
10700 {
10701   struct
10702   {
10703     int *new_element;
10704     struct XYTileSize *pos;
10705     int id;
10706   } de, drawing_elements[] =
10707   {
10708     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10709     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10710     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10711   };
10712
10713   if (button < 1 || button > 3)
10714     return;
10715
10716   if (IS_MM_WALL(element))
10717     element = map_mm_wall_element(element);
10718
10719   de = drawing_elements[button - 1];
10720
10721   *de.new_element = element;    // update global drawing element variable
10722
10723   DrawDrawingElementGraphic(element, de.pos);
10724   ModifyDrawingElementButton(element, de.id);
10725
10726   redraw_mask |= REDRAW_DOOR_1;
10727 }
10728
10729 static void RedrawDrawingElements(void)
10730 {
10731   PickDrawingElement(1, new_element1);
10732   PickDrawingElement(2, new_element2);
10733   PickDrawingElement(3, new_element3);
10734 }
10735
10736 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10737 {
10738   stick_element_properties_window = FALSE;
10739
10740   SetMainBackgroundImage(IMG_UNDEFINED);
10741   ClearField();
10742
10743   UnmapLevelEditorFieldGadgets();
10744
10745   AdjustDrawingAreaGadgets();
10746   AdjustLevelScrollPosition();
10747   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10748   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10749
10750   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10751
10752   MapMainDrawingArea();
10753
10754   if (remap_toolbox_gadgets)
10755   {
10756     UnmapLevelEditorToolboxCustomGadgets();
10757     MapLevelEditorToolboxDrawingGadgets();
10758   }
10759 }
10760
10761 static void DrawDrawingWindow(void)
10762 {
10763   DrawDrawingWindowExt(TRUE);
10764 }
10765
10766 static int getTabulatorBarWidth(void)
10767 {
10768   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10769   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10770
10771   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10772 }
10773
10774 static int getTabulatorBarHeight(void)
10775 {
10776   return ED_TAB_BAR_HEIGHT;
10777 }
10778
10779 static Pixel getTabulatorBarColor(void)
10780 {
10781   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10782   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10783   int gd_x = gd->x + gd_gi1->border.width / 2;
10784   int gd_y = gd->y + gd_gi1->height - 1;
10785
10786   return GetPixel(gd->bitmap, gd_x, gd_y);
10787 }
10788
10789 static void DrawLevelConfigTabulatorGadgets(void)
10790 {
10791   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10792   Pixel tab_color = getTabulatorBarColor();
10793   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10794   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10795   int i;
10796
10797   // draw additional "engine" tabulator when using native BD engine
10798   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10799     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10800
10801   for (i = id_first; i <= id_last; i++)
10802   {
10803     int gadget_id = textbutton_info[i].gadget_id;
10804     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10805     boolean active = (i != edit_mode_levelconfig);
10806
10807     // draw background line below tabulator button
10808     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10809
10810     // draw solid line below inactive tabulator buttons
10811     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10812       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10813                     ED_GADGET_TINY_DISTANCE, tab_color);
10814
10815     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10816     MapTextbuttonGadget(i);
10817   }
10818
10819   // draw little border line below tabulator buttons
10820   if (tab_color != BLACK_PIXEL)                 // black => transparent
10821     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10822                   ED_GADGET_TINY_DISTANCE,
10823                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10824 }
10825
10826 static void DrawPropertiesTabulatorGadgets(void)
10827 {
10828   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10829   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10830   int gd_x = gd->x + gd_gi1->border.width / 2;
10831   int gd_y = gd->y + gd_gi1->height - 1;
10832   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10833   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10834   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10835   int i;
10836
10837   // draw two config tabulators for player elements
10838   if (IS_PLAYER_ELEMENT(properties_element))
10839     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10840
10841   // draw two config and one "change" tabulator for custom elements
10842   if (IS_CUSTOM_ELEMENT(properties_element))
10843     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10844
10845   for (i = id_first; i <= id_last; i++)
10846   {
10847     int gadget_id = textbutton_info[i].gadget_id;
10848     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10849     boolean active = (i != edit_mode_properties);
10850
10851     // use "config 1" and "config 2" instead of "config" for players and CEs
10852     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10853         (IS_PLAYER_ELEMENT(properties_element) ||
10854          IS_CUSTOM_ELEMENT(properties_element)))
10855       continue;
10856
10857     // draw background line below tabulator button
10858     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10859
10860     // draw solid line below inactive tabulator buttons
10861     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10862       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10863                     ED_GADGET_TINY_DISTANCE, tab_color);
10864
10865     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10866     MapTextbuttonGadget(i);
10867   }
10868
10869   // draw little border line below tabulator buttons
10870   if (tab_color != BLACK_PIXEL)                 // black => transparent
10871     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10872                   ED_GADGET_TINY_DISTANCE,
10873                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10874 }
10875
10876 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10877 {
10878   DrawText(SX + xpos, SY + ypos, text, font_nr);
10879 }
10880
10881 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10882                                            int xpos, int ypos)
10883 {
10884   int font_width = getFontWidth(font_nr);
10885   int font_height = getFontHeight(font_nr);
10886   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10887   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10888
10889   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10890                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10891                       TRUE, FALSE, FALSE);
10892 }
10893
10894 static void DrawLevelConfigLevel(void)
10895 {
10896   int i;
10897
10898   // draw counter gadgets
10899   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10900     MapCounterButtons(i);
10901
10902   // draw checkbutton gadgets
10903   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10904     MapCheckbuttonGadget(i);
10905
10906   // draw selectbox gadgets
10907   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10908     MapSelectboxGadget(i);
10909
10910   // draw text input gadgets
10911   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10912     MapTextInputGadget(i);
10913 }
10914
10915 static char *getLevelSubdirFromSaveMode(int save_mode)
10916 {
10917   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10918     return getNewUserLevelSubdir();
10919
10920   return leveldir_current->subdir;
10921 }
10922
10923 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10924 {
10925   char *directory_text = "Level set directory:";
10926   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10927   int font1_nr = FONT_TEXT_1;
10928   int font2_nr = FONT_TEXT_2;
10929   int font1_height = getFontHeight(font1_nr);
10930   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10931   int x = ED_LEVEL_SETTINGS_X(0);
10932   int y = ED_LEVEL_SETTINGS_Y(6);
10933
10934   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10935   PrintInfoText(directory_name, font2_nr, x, y);
10936 }
10937
10938 static void DrawLevelConfigLevelSet(void)
10939 {
10940   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10941   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10942   int i;
10943
10944   // draw counter gadgets
10945   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10946     MapCounterButtons(i);
10947
10948   // draw checkbutton gadgets
10949   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10950   {
10951     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10952         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10953         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10954       continue;
10955
10956     MapCheckbuttonGadget(i);
10957   }
10958
10959   // draw selectbox gadgets
10960   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10961     MapSelectboxGadget(i);
10962
10963   // draw text input gadgets
10964   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10965     MapTextInputGadget(i);
10966
10967   // draw textbutton gadgets
10968   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10969
10970   // draw info text
10971   DrawLevelConfigLevelSet_DirectoryInfo();
10972 }
10973
10974 static void DrawLevelConfigEditor(void)
10975 {
10976   int i;
10977
10978   // draw counter gadgets
10979   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
10980     MapCounterButtons(i);
10981
10982   // draw checkbutton gadgets
10983   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
10984     MapCheckbuttonGadget(i);
10985
10986   // draw radiobutton gadgets
10987   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
10988     MapRadiobuttonGadget(i);
10989
10990   // draw drawing area
10991   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
10992
10993   // draw textbutton gadgets
10994   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
10995 }
10996
10997 static void DrawLevelConfigEngine(void)
10998 {
10999   int i;
11000
11001   // draw counter gadgets
11002   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
11003   {
11004     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
11005     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
11006   }
11007   else
11008   {
11009     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
11010     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
11011   }
11012
11013   // draw checkbutton gadgets
11014   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
11015     MapCheckbuttonGadget(i);
11016
11017   // draw selectbox gadgets
11018   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
11019     MapSelectboxGadget(i);
11020 }
11021
11022 static void DrawLevelConfigWindow(void)
11023 {
11024   char *text = "Global Settings";
11025   int font_nr = FONT_TITLE_1;
11026   struct MenuPosInfo *pos = &editor.settings.headline;
11027   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
11028   int sy = SY + pos->y;
11029
11030   stick_element_properties_window = FALSE;
11031
11032   SetAutomaticNumberOfGemsNeeded();
11033
11034   UnmapLevelEditorFieldGadgets();
11035
11036   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
11037   ClearField();
11038
11039   DrawText(sx, sy, text, font_nr);
11040
11041   DrawLevelConfigTabulatorGadgets();
11042
11043   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
11044     DrawLevelConfigLevel();
11045   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
11046     DrawLevelConfigLevelSet();
11047   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
11048     DrawLevelConfigEditor();
11049   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
11050     DrawLevelConfigEngine();
11051 }
11052
11053 static void DrawCustomContentArea(void)
11054 {
11055   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
11056   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11057   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
11058   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
11059   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
11060   int xoffset = ED_GADGET_SPACE_DISTANCE;
11061
11062   // add distance for potential left text (without drawing area border)
11063   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
11064
11065   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11066
11067   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
11068 }
11069
11070 static void DrawCustomChangeContentArea(void)
11071 {
11072   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
11073   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11074   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
11075   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
11076   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
11077   int xoffset = ED_GADGET_SPACE_DISTANCE;
11078
11079   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11080
11081   MapDrawingArea(id);
11082 }
11083
11084 static void RemoveElementContentArea(int id, int font_height)
11085 {
11086   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11087
11088   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
11089                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
11090                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11091                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
11092                  ED_GADGET_TEXT_DISTANCE + font_height);
11093 }
11094
11095 static void DrawYamYamContentAreas(void)
11096 {
11097   int font_nr = FONT_TEXT_1;
11098   int font_height = getFontHeight(font_nr);
11099   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11100   int yoffset = (tilesize - font_height) / 2;
11101   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
11102   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
11103   int i;
11104
11105   // display counter to choose number of element content areas
11106   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
11107
11108   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11109   {
11110     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
11111
11112     if (i < level.num_yamyam_contents)
11113     {
11114       MapDrawingArea(id);
11115     }
11116     else
11117     {
11118       UnmapDrawingArea(id);
11119
11120       // delete content areas in case of reducing number of them
11121       RemoveElementContentArea(id, font_height);
11122     }
11123   }
11124
11125   DrawText(x, y + 0 * tilesize, "content", font_nr);
11126   DrawText(x, y + 1 * tilesize, "when",    font_nr);
11127   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
11128 }
11129
11130 static void DrawMagicBallContentAreas(void)
11131 {
11132   int font_nr = FONT_TEXT_1;
11133   int font_height = getFontHeight(font_nr);
11134   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11135   int yoffset = (tilesize - font_height) / 2;
11136   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
11137   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
11138   int i;
11139
11140   // display counter to choose number of element content areas
11141   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
11142
11143   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11144   {
11145     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
11146
11147     if (i < level.num_ball_contents)
11148     {
11149       MapDrawingArea(id);
11150     }
11151     else
11152     {
11153       UnmapDrawingArea(id);
11154
11155       // delete content areas in case of reducing number of them
11156       RemoveElementContentArea(id, font_height);
11157     }
11158   }
11159
11160   DrawText(x, y + 0 * tilesize, "generated", font_nr);
11161   DrawText(x, y + 1 * tilesize, "when",      font_nr);
11162   DrawText(x, y + 2 * tilesize, "active",    font_nr);
11163 }
11164
11165 static void DrawAndroidElementArea(void)
11166 {
11167   int id = ED_DRAWING_ID_ANDROID_CONTENT;
11168   int num_elements = level.num_android_clone_elements;
11169   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11170   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11171   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11172   int xsize = MAX_ANDROID_ELEMENTS;
11173   int ysize = 1;
11174
11175   // display counter to choose number of element areas
11176   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
11177
11178   if (drawingarea_info[id].text_left != NULL)
11179     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11180
11181   UnmapDrawingArea(id);
11182
11183   ModifyEditorDrawingArea(id, num_elements, 1);
11184
11185   // delete content areas in case of reducing number of them
11186   DrawBackground(sx, sy,
11187                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11188                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11189
11190   MapDrawingArea(id);
11191 }
11192
11193 static void DrawGroupElementArea(void)
11194 {
11195   int id = ED_DRAWING_ID_GROUP_CONTENT;
11196   int num_elements = group_element_info.num_elements;
11197   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11198   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11199   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11200   int xsize = MAX_ELEMENTS_IN_GROUP;
11201   int ysize = 1;
11202
11203   if (drawingarea_info[id].text_left != NULL)
11204     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11205
11206   UnmapDrawingArea(id);
11207
11208   ModifyEditorDrawingArea(id, num_elements, 1);
11209
11210   // delete content areas in case of reducing number of them
11211   DrawBackground(sx, sy,
11212                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11213                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11214
11215   MapDrawingArea(id);
11216 }
11217
11218 static void DrawPlayerInitialInventoryArea(int element)
11219 {
11220   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11221   int player_nr = GET_PLAYER_NR(element);
11222   int num_elements = level.initial_inventory_size[player_nr];
11223   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11224   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11225   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11226   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11227   int ysize = 1;
11228
11229   // determine horizontal position to the right of specified gadget
11230   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11231     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11232           ED_DRAWINGAREA_TEXT_DISTANCE);
11233
11234   // determine horizontal offset for leading text
11235   if (drawingarea_info[id].text_left != NULL)
11236     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11237
11238   UnmapDrawingArea(id);
11239
11240   ModifyEditorDrawingArea(id, num_elements, 1);
11241
11242   // delete content areas in case of reducing number of them
11243   DrawBackground(sx, sy,
11244                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11245                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11246
11247   MapDrawingArea(id);
11248 }
11249
11250 static void DrawMMBallContentArea(void)
11251 {
11252   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11253   int num_elements = level.num_mm_ball_contents;
11254   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11255   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11256   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11257   int xsize = MAX_MM_BALL_CONTENTS;
11258   int ysize = 1;
11259
11260   if (drawingarea_info[id].text_left != NULL)
11261     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11262
11263   UnmapDrawingArea(id);
11264
11265   ModifyEditorDrawingArea(id, num_elements, 1);
11266
11267   // delete content areas in case of reducing number of them
11268   DrawBackground(sx, sy,
11269                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11270                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11271
11272   MapDrawingArea(id);
11273 }
11274
11275 static void DrawEnvelopeTextArea(int envelope_nr)
11276 {
11277   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11278   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11279
11280   UnmapGadget(gi);
11281
11282   DrawBackground(gi->x, gi->y,
11283                  gi->textarea.crop_width, gi->textarea.crop_height);
11284
11285   if (envelope_nr != -1)
11286     textarea_info[id].value = level.envelope[envelope_nr].text;
11287
11288   ModifyGadget(gi, GDI_AREA_SIZE,
11289                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11290                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11291                GDI_END);
11292
11293   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11294 }
11295
11296 static void DrawPropertiesInfo(void)
11297 {
11298   static struct
11299   {
11300     int value;
11301     char *text;
11302   }
11303   properties[] =
11304   {
11305     // configurable properties
11306
11307     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11308     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11309     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11310     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11311     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11312     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11313     { EP_PROTECTED,             "- player is protected by it"           },
11314
11315     { EP_DIGGABLE,              "- can be digged away"                  },
11316     { EP_COLLECTIBLE,           "- can be collected"                    },
11317     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11318     { EP_THROWABLE,             "- can be thrown after collecting"      },
11319     { EP_PUSHABLE,              "- can be pushed"                       },
11320
11321     { EP_CAN_FALL,              "- can fall"                            },
11322     { EP_CAN_MOVE,              "- can move"                            },
11323
11324     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11325 #if 0
11326     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11327 #endif
11328     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11329
11330     { EP_SLIPPERY,              "- slippery for falling elements"       },
11331     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11332
11333     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11334     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11335     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11336     { EP_DONT_TOUCH,            "- deadly when touching"                },
11337
11338     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11339
11340     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11341     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11342     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11343
11344     { EP_CAN_CHANGE,            "- can change to other element"         },
11345
11346     // pre-defined properties
11347     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11348     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11349     { EP_SWITCHABLE,            "- can be switched"                     },
11350 #if 0
11351     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11352 #endif
11353
11354     { -1,                       NULL                                    }
11355   };
11356   char *filename = getElementDescriptionFilename(properties_element);
11357   char *num_elements_text = "In this level: ";
11358   char *num_similar_text = "Similar tiles: ";
11359   char *properties_text = "Standard properties: ";
11360   char *description_text = "Description:";
11361   char *no_description_text = "No description available.";
11362   char *none_text = "None";
11363   float percentage;
11364   int num_elements_in_level = 0;
11365   int num_similar_in_level = 0;
11366   int num_hires_tiles_in_level = 0;
11367   int num_standard_properties = 0;
11368   int font1_nr = FONT_TEXT_1;
11369   int font2_nr = FONT_TEXT_2;
11370   int font1_width = getFontWidth(font1_nr);
11371   int font1_height = getFontHeight(font1_nr);
11372   int font2_height = getFontHeight(font2_nr);
11373   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11374   int font2_yoffset = (font1_height - font2_height) / 2;
11375   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11376   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11377   int properties_text_len = strlen(properties_text) * font1_width;
11378   int xpos = ED_ELEMENT_SETTINGS_X(0);
11379   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11380   int i, x, y;
11381
11382   if (setup.editor.show_element_token)
11383   {
11384     int font3_nr = FONT_TEXT_3;
11385     int font3_height = getFontHeight(font3_nr);
11386
11387     DrawTextF(xpos, ypos, font3_nr,
11388               "[%s]", element_info[properties_element].token_name);
11389
11390     ypos += 2 * font3_height;
11391   }
11392
11393   // ----- print number of elements / percentage of this element in level
11394
11395   for (y = 0; y < lev_fieldy; y++)
11396   {
11397     for (x = 0; x < lev_fieldx; x++)
11398     {
11399       if (Tile[x][y] == properties_element)
11400       {
11401         num_elements_in_level++;
11402       }
11403       else if (IS_MM_WALL(Tile[x][y]) &&
11404                map_mm_wall_element(Tile[x][y]) == properties_element)
11405       {
11406         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11407       }
11408     }
11409   }
11410
11411   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11412
11413   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11414
11415   if (num_hires_tiles_in_level > 0)
11416     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11417               "%d wall tiles", num_hires_tiles_in_level);
11418   else if (num_elements_in_level > 0)
11419     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11420               "%d (%.2f %%)", num_elements_in_level, percentage);
11421   else
11422     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11423               none_text);
11424
11425   // ----- print number of similar elements / percentage of them in level
11426
11427   for (y = 0; y < lev_fieldy; y++)
11428   {
11429     for (x = 0; x < lev_fieldx; x++)
11430     {
11431       if (strEqual(element_info[Tile[x][y]].class_name,
11432                    element_info[properties_element].class_name))
11433       {
11434         num_similar_in_level++;
11435       }
11436     }
11437   }
11438
11439   if (num_similar_in_level != num_elements_in_level)
11440   {
11441     ypos += 1 * MAX(font1_height, font2_height);
11442
11443     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11444
11445     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11446
11447     if (num_similar_in_level > 0)
11448       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11449                 "%d (%.2f %%)", num_similar_in_level, percentage);
11450     else
11451       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11452                 none_text);
11453   }
11454
11455   ypos += 2 * MAX(font1_height, font2_height);
11456
11457   // ----- print standard properties of this element
11458
11459   DrawTextS(xpos, ypos, font1_nr, properties_text);
11460
11461   ypos += line1_height;
11462
11463   for (i = 0; properties[i].value != -1; i++)
11464   {
11465     if (!HAS_PROPERTY(properties_element, properties[i].value))
11466       continue;
11467
11468     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11469
11470     ypos += font2_height;
11471
11472     num_standard_properties++;
11473   }
11474
11475   if (num_standard_properties == 0)
11476   {
11477     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11478               font2_nr, none_text);
11479
11480     ypos -= (line1_height - font1_height);
11481   }
11482
11483   ypos += MAX(font1_height, font2_height);
11484
11485   // ----- print special description of this element
11486
11487   PrintInfoText(description_text, font1_nr, xpos, ypos);
11488
11489   ypos += line1_height;
11490
11491   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11492     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11493 }
11494
11495 #define TEXT_COLLECTING                 "Score for collecting"
11496 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11497 #define TEXT_SMASHING                   "Score for smashing"
11498 #define TEXT_SLURPING                   "Score for slurping robot"
11499 #define TEXT_CRACKING                   "Score for cracking"
11500 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11501 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11502 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11503 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11504 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11505 #define TEXT_DURATION                   "Duration when activated"
11506 #define TEXT_DELAY_ON                   "Delay before activating"
11507 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11508 #define TEXT_DELAY_CHANGING             "Delay before changing"
11509 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11510 #define TEXT_DELAY_MOVING               "Delay before moving"
11511 #define TEXT_BALL_DELAY                 "Element generation delay"
11512 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11513 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11514 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11515 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11516 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11517 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11518 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11519 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11520 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11521 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11522 #define TEXT_RANDOM_SEED                "slime random number seed"
11523 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11524 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11525 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11526 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11527 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11528 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11529 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11530 #define TEXT_AUTO_TURN_DELAY            "Creatures auto turn delay"
11531 #define TEXT_GRAVITY_DELAY              "Gravity switch change delay"
11532
11533 static struct
11534 {
11535   int element;
11536   int *value;
11537   char *text;
11538   int min_value;
11539   int max_value;
11540 } elements_with_counter[] =
11541 {
11542   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11543   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11544   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11545   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11546   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11547   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11548   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11549   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11550   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11551   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11552   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11553   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11554   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11555   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11556   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11557   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11558   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11559   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11560   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11561   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11562   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11563   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11564   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11565   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11566   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11567   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11568   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11569   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11570   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11571   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11572   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11573   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11574   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11575   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11576   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11577   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11578   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11579   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11580   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11581   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11582   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11583   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11584   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11585   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11586   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11587   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11588   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11589   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11590   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11591   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11592   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11593   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11594   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11595   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11596   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11597   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11598   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11599   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11600   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11601   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11602   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11603   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11604   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11605   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11606   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11607   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11608   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11609   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11610   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11611   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11612   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11613   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11614   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11615   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11616   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11617   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11618   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11619   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11620   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11621   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11622   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11623   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11624   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11625                                 0, 100                                                          },
11626   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11627                                 0, 100                                                          },
11628   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11629   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11630   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11631                                 0, 100                                                          },
11632   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11633                                 0, 100                                                          },
11634   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11635   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11636   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11637   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11638   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11639   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11640   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11641   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11642   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11643   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11644   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11645                                 -100, 100                                                       },
11646   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11647                                 0, 100                                                          },
11648   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11649                                 0, 100                                                          },
11650   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11651                                 0, 255                                                          },
11652   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11653                                 -1, 65535                                                       },
11654   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11655                                 0, 100                                                          },
11656   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11657                                 0, 3                                                            },
11658   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11659                                 0, 3                                                            },
11660   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11661                                 0, 3                                                            },
11662   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11663                                 0, 3                                                            },
11664   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11665                                 0, 3                                                            },
11666   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11667                                 0, 100                                                          },
11668   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11669                                 1, 100                                                          },
11670   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11671                                 1, 200                                                          },
11672   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11673                                 0, 50                                                           },
11674   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11675                                 0, 50                                                           },
11676   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11677                                 0, 10                                                           },
11678   { EL_BD_CREATURE_SWITCH,      &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
11679   { EL_BD_GRAVITY_SWITCH,       &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
11680                                 1, 60                                                           },
11681   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11682   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11683   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11684   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11685   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11686   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11687   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11688   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11689   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11690   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11691   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11692   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11693   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11694   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11695   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11696   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11697   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11698   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11699   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11700   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11701   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11702   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11703   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11704   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11705   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11706
11707   { -1,                         NULL,                                   NULL                    }
11708 };
11709
11710 static boolean checkPropertiesConfig(int element)
11711 {
11712   int i;
11713
11714   // special case: empty space customization only available in R'n'D game engine
11715   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11716     return FALSE;
11717
11718   // special case: BD style rock customization only available in BD game engine
11719   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11720     return FALSE;
11721
11722   if (IS_GEM(element) ||
11723       IS_CUSTOM_ELEMENT(element) ||
11724       IS_GROUP_ELEMENT(element) ||
11725       IS_EMPTY_ELEMENT(element) ||
11726       IS_BALLOON_ELEMENT(element) ||
11727       IS_ENVELOPE(element) ||
11728       IS_MM_ENVELOPE(element) ||
11729       IS_MM_MCDUFFIN(element) ||
11730       IS_DF_LASER(element) ||
11731       IS_PLAYER_ELEMENT(element) ||
11732       IS_BD_PLAYER_ELEMENT(element) ||
11733       IS_BD_FIREFLY(properties_element) ||
11734       IS_BD_FIREFLY_2(properties_element) ||
11735       IS_BD_BUTTERFLY(properties_element) ||
11736       IS_BD_BUTTERFLY_2(properties_element) ||
11737       IS_BD_STONEFLY(properties_element) ||
11738       IS_BD_DRAGONFLY(properties_element) ||
11739       IS_BD_EXPANDABLE_WALL(properties_element) ||
11740       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11741       IS_BD_CONVEYOR_BELT(properties_element) ||
11742       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11743       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11744       HAS_EDITOR_CONTENT(element) ||
11745       CAN_GROW(element) ||
11746       COULD_MOVE_INTO_ACID(element) ||
11747       MAYBE_DONT_COLLIDE_WITH(element) ||
11748       element == EL_BD_SAND ||
11749       element == EL_BD_ROCK ||
11750       element == EL_BD_MEGA_ROCK ||
11751       element == EL_BD_BOMB ||
11752       element == EL_BD_ROCKET_LAUNCHER ||
11753       element == EL_BD_NITRO_PACK ||
11754       element == EL_BD_SWEET ||
11755       element == EL_BD_VOODOO_DOLL ||
11756       element == EL_BD_WATER ||
11757       element == EL_BD_GRAVITY_SWITCH)
11758   {
11759     return TRUE;
11760   }
11761   else
11762   {
11763     for (i = 0; elements_with_counter[i].element != -1; i++)
11764       if (elements_with_counter[i].element == element)
11765         return TRUE;
11766   }
11767
11768   return FALSE;
11769 }
11770
11771 static void SetAutomaticNumberOfGemsNeeded(void)
11772 {
11773   int x, y;
11774
11775   if (!level.auto_count_gems)
11776     return;
11777
11778   level.gems_needed = 0;
11779
11780   for (x = 0; x < lev_fieldx; x++)
11781   {
11782     for (y = 0; y < lev_fieldy; y++)
11783     {
11784       int element = Tile[x][y];
11785
11786       switch (element)
11787       {
11788         case EL_EMERALD:
11789         case EL_EMERALD_YELLOW:
11790         case EL_EMERALD_RED:
11791         case EL_EMERALD_PURPLE:
11792         case EL_BD_DIAMOND:
11793         case EL_WALL_EMERALD:
11794         case EL_WALL_EMERALD_YELLOW:
11795         case EL_WALL_EMERALD_RED:
11796         case EL_WALL_EMERALD_PURPLE:
11797         case EL_WALL_BD_DIAMOND:
11798         case EL_NUT:
11799         case EL_SP_INFOTRON:
11800         case EL_MM_KETTLE:
11801         case EL_DF_CELL:
11802           level.gems_needed++;
11803           break;
11804
11805         case EL_DIAMOND:
11806         case EL_WALL_DIAMOND:
11807           level.gems_needed += 3;
11808           break;
11809
11810         case EL_PEARL:
11811         case EL_WALL_PEARL:
11812           level.gems_needed += 5;
11813           break;
11814
11815         case EL_CRYSTAL:
11816         case EL_WALL_CRYSTAL:
11817           level.gems_needed += 8;
11818           break;
11819
11820         default:
11821           break;
11822       }
11823     }
11824   }
11825
11826   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11827 }
11828
11829 static void DrawPropertiesConfig(void)
11830 {
11831   boolean draw_footer_line = FALSE;
11832   int max_num_element_counters = 4;
11833   int num_element_counters = 0;
11834   int i;
11835
11836   if (!checkPropertiesConfig(properties_element))
11837   {
11838     int xpos = ED_ELEMENT_SETTINGS_X(0);
11839     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11840
11841     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11842
11843     return;
11844   }
11845
11846   // check if there are elements where a value can be chosen for
11847   for (i = 0; elements_with_counter[i].element != -1; i++)
11848   {
11849     if (elements_with_counter[i].element != properties_element)
11850       continue;
11851
11852     // special case: score for extra diamonds only available in BD game engine
11853     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11854         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11855         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11856       continue;
11857
11858     // special case: some amoeba counters only available in BD game engine
11859     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11860         elements_with_counter[i].value != &level.amoeba_speed &&
11861         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11862       continue;
11863
11864     // special case: score for smashing only available in R'n'D game engine
11865     if ((IS_BD_FIREFLY(elements_with_counter[i].element) ||
11866          IS_BD_BUTTERFLY(elements_with_counter[i].element)) &&
11867         (elements_with_counter[i].value == &level.score[SC_BUG] ||
11868          elements_with_counter[i].value == &level.score[SC_SPACESHIP]) &&
11869         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11870       continue;
11871
11872     // special case: some amoeba counters only available in R'n'D game engine
11873     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11874         elements_with_counter[i].value == &level.amoeba_speed &&
11875         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11876       continue;
11877
11878     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11879
11880     counterbutton_info[counter_id].y =
11881       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11882                                (CAN_GROW(properties_element)                ? 1 : 0) +
11883                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11884                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11885                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11886                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11887                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11888                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11889                                (properties_element == EL_BD_CREATURE_SWITCH ? 1 : 0) +
11890                                (properties_element == EL_BD_GRAVITY_SWITCH  ? 2 : 0) +
11891                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11892                                num_element_counters);
11893
11894     // special case: set magic wall counter for BD game engine separately
11895     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11896       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11897
11898     // special case: set amoeba counters for BD game engine separately
11899     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11900         (properties_element == EL_BD_AMOEBA_2))
11901       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11902
11903     // special case: set position for delay counter for reappearing hammered walls
11904     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11905       counterbutton_info[counter_id].y += 1;
11906
11907     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11908     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11909     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11910     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11911
11912     // default: counter values between 0 and 999
11913     if (counterbutton_info[counter_id].max_value == 0)
11914       counterbutton_info[counter_id].max_value = 999;
11915
11916     MapCounterButtons(counter_id);
11917
11918     num_element_counters++;
11919     if (num_element_counters >= max_num_element_counters)
11920       break;
11921   }
11922
11923   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11924   {
11925     // draw stickybutton gadget
11926     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11927
11928     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11929     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11930
11931     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11932     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11933     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11934     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11935     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11936     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11937     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11938   }
11939
11940   if (HAS_EDITOR_CONTENT(properties_element))
11941   {
11942     // draw stickybutton gadget
11943     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11944
11945     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11946     {
11947       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11948       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11949
11950       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11951       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11952     }
11953     else if (properties_element == EL_BD_AMOEBA_2)
11954     {
11955       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11956       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11957       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11958
11959       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11960       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11961       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11962       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11963     }
11964     else if (IS_AMOEBOID(properties_element))
11965     {
11966       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11967     }
11968     else if (properties_element == EL_BD_ACID)
11969     {
11970       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11971       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11972     }
11973     else if (IS_BD_BITER(properties_element))
11974     {
11975       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11976     }
11977     else if (properties_element == EL_BD_BLADDER)
11978     {
11979       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11980     }
11981     else if (properties_element == EL_YAMYAM ||
11982              properties_element == EL_YAMYAM_LEFT ||
11983              properties_element == EL_YAMYAM_RIGHT ||
11984              properties_element == EL_YAMYAM_UP ||
11985              properties_element == EL_YAMYAM_DOWN)
11986     {
11987       DrawYamYamContentAreas();
11988     }
11989     else if (properties_element == EL_EMC_MAGIC_BALL)
11990     {
11991       DrawMagicBallContentAreas();
11992
11993       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
11994       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
11995     }
11996     else if (properties_element == EL_EMC_ANDROID)
11997     {
11998       DrawAndroidElementArea();
11999     }
12000     else if (properties_element == EL_MM_GRAY_BALL)
12001     {
12002       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
12003       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
12004       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
12005       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
12006
12007       DrawMMBallContentArea();
12008     }
12009   }
12010
12011   if (IS_PLAYER_ELEMENT(properties_element))
12012   {
12013     int player_nr = GET_PLAYER_NR(properties_element);
12014
12015     // these properties can be set for every player individually
12016
12017     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12018     {
12019       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
12020         &level.start_element[player_nr];
12021       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
12022         &level.artwork_element[player_nr];
12023       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
12024         &level.explosion_element[player_nr];
12025
12026       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
12027         &level.use_start_element[player_nr];
12028       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
12029         &level.use_artwork_element[player_nr];
12030       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
12031         &level.use_explosion_element[player_nr];
12032       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
12033         &level.initial_player_gravity[player_nr];
12034
12035       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
12036         &level.initial_player_stepsize[player_nr];
12037
12038       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
12039       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
12040                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
12041                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
12042       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
12043       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
12044       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
12045       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
12046       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
12047       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
12048       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
12049       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
12050       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
12051       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
12052       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
12053
12054       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
12055       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
12056       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
12057
12058       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
12059     }
12060     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12061     {
12062       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
12063         &level.initial_inventory_content[player_nr][0];
12064
12065       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
12066         &level.initial_inventory_size[player_nr];
12067
12068       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
12069         &level.use_initial_inventory[player_nr];
12070
12071       // draw checkbutton gadgets
12072       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
12073       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
12074       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
12075
12076       // draw counter gadgets
12077       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
12078
12079       // draw drawing area gadgets
12080       DrawPlayerInitialInventoryArea(properties_element);
12081     }
12082   }
12083
12084   if (IS_BD_PLAYER_ELEMENT(properties_element))
12085   {
12086     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12087       ED_ELEMENT_SETTINGS_YPOS(2);
12088     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12089       ED_ELEMENT_SETTINGS_YPOS(3);
12090     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12091       ED_ELEMENT_SETTINGS_YPOS(4);
12092
12093     // draw checkbutton gadgets
12094     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
12095     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
12096     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12097
12098     // draw counter gadgets
12099     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12100     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12101
12102     // draw drawing area gadgets
12103     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
12104   }
12105
12106   if (properties_element == EL_BD_SAND)
12107   {
12108     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
12109   }
12110
12111   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12112   {
12113     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12114       ED_ELEMENT_SETTINGS_YPOS(0);
12115     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12116       ED_ELEMENT_SETTINGS_YPOS(1);
12117
12118     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12119     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12120
12121     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
12122     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
12123   }
12124
12125   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12126   {
12127     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
12128     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
12129   }
12130
12131   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
12132   {
12133     if (IS_BD_FIREFLY(properties_element))
12134     {
12135       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO);
12136       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12137     }
12138     else if (IS_BD_FIREFLY_2(properties_element))
12139     {
12140       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
12141       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12142     }
12143     else if (IS_BD_BUTTERFLY(properties_element))
12144     {
12145       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO);
12146       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12147     }
12148     else if (IS_BD_BUTTERFLY_2(properties_element))
12149     {
12150       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
12151       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12152     }
12153     else if (IS_BD_STONEFLY(properties_element))
12154     {
12155       MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
12156     }
12157     else if (IS_BD_DRAGONFLY(properties_element))
12158     {
12159       MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
12160       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12161     }
12162     else if (properties_element == EL_BD_BOMB)
12163     {
12164       MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
12165     }
12166     else if (properties_element == EL_BD_NITRO_PACK)
12167     {
12168       MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
12169     }
12170   }
12171
12172   if (properties_element == EL_BD_MEGA_ROCK ||
12173       properties_element == EL_BD_SWEET)
12174   {
12175     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12176       ED_ELEMENT_SETTINGS_YPOS(0);
12177     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12178       ED_ELEMENT_SETTINGS_YPOS(1);
12179
12180     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12181     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12182   }
12183
12184   if (properties_element == EL_BD_VOODOO_DOLL)
12185   {
12186     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12187     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12188     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12189     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12190   }
12191
12192   if (properties_element == EL_BD_SLIME)
12193   {
12194     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12195
12196     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12197     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12198     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12199     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12200     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12201     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12202   }
12203
12204   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12205       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12206   {
12207     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12208
12209     if (IS_BD_EXPANDABLE_WALL(properties_element))
12210       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12211   }
12212
12213   if (properties_element == EL_BD_REPLICATOR)
12214   {
12215     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12216   }
12217
12218   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12219       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12220   {
12221     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12222     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12223   }
12224
12225   if (properties_element == EL_BD_WATER)
12226   {
12227     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12228   }
12229
12230   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12231   {
12232     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12233   }
12234
12235   if (properties_element == EL_BD_ROCKET_LAUNCHER)
12236   {
12237     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS);
12238   }
12239
12240   if (properties_element == EL_BD_CREATURE_SWITCH)
12241   {
12242     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12243     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12244   }
12245
12246   if (properties_element == EL_BD_GRAVITY_SWITCH)
12247   {
12248     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12249
12250     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12251     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12252   }
12253
12254   if (properties_element == EL_BD_NUT)
12255   {
12256     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12257   }
12258
12259   // special case: slippery walls option for gems only available in R'n'D game engine
12260   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12261     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12262
12263   if (properties_element == EL_EM_DYNAMITE)
12264     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12265
12266   if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
12267       COULD_MOVE_INTO_ACID(properties_element) &&
12268       !IS_PLAYER_ELEMENT(properties_element) &&
12269       (!IS_CUSTOM_ELEMENT(properties_element) ||
12270        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12271   {
12272     // set position for checkbutton for "can move into acid"
12273     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12274       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12275     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12276       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12277                                IS_BALLOON_ELEMENT(properties_element) ||
12278                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12279
12280     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12281   }
12282
12283   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12284     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12285
12286   if (properties_element == EL_SPRING ||
12287       properties_element == EL_SPRING_LEFT ||
12288       properties_element == EL_SPRING_RIGHT)
12289     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12290
12291   if (properties_element == EL_TIME_ORB_FULL)
12292     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12293
12294   if (properties_element == EL_GAME_OF_LIFE ||
12295       properties_element == EL_BIOMAZE)
12296     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12297
12298   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12299   {
12300     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12301       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12302
12303     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12304   }
12305
12306   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12307     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12308
12309   if (properties_element == EL_SOKOBAN_OBJECT)
12310     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12311
12312   if (properties_element == EL_SOKOBAN_OBJECT ||
12313       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12314       properties_element == EL_SOKOBAN_FIELD_FULL)
12315   {
12316     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12317       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12318                                0 : 1);
12319
12320     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12321   }
12322
12323   if (IS_BALLOON_ELEMENT(properties_element))
12324     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12325
12326   if (IS_ENVELOPE(properties_element) ||
12327       IS_MM_ENVELOPE(properties_element))
12328   {
12329     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12330     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12331     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12332     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12333     int envelope_nr = ENVELOPE_NR(properties_element);
12334
12335     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12336     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12337
12338     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12339     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12340
12341     // display counter to choose size of envelope text area
12342     MapCounterButtons(counter1_id);
12343     MapCounterButtons(counter2_id);
12344
12345     // display checkbuttons to choose auto-wrap and alignment properties
12346     MapCheckbuttonGadget(button1_id);
12347     MapCheckbuttonGadget(button2_id);
12348
12349     DrawEnvelopeTextArea(envelope_nr);
12350   }
12351
12352   if (IS_MM_MCDUFFIN(properties_element))
12353   {
12354     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12355     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12356     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12357   }
12358
12359   if (IS_DF_LASER(properties_element))
12360   {
12361     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12362     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12363     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12364   }
12365
12366   if (IS_CUSTOM_ELEMENT(properties_element))
12367   {
12368     // draw stickybutton gadget
12369     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12370
12371     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12372     {
12373       // draw checkbutton gadgets
12374       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12375            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12376         MapCheckbuttonGadget(i);
12377
12378       // draw counter gadgets
12379       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12380            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12381         MapCounterButtons(i);
12382
12383       // draw selectbox gadgets
12384       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12385            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12386         MapSelectboxGadget(i);
12387
12388       // draw textbutton gadgets
12389       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12390
12391       // draw text input gadgets
12392       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12393
12394       // draw drawing area gadgets
12395       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12396
12397       draw_footer_line = TRUE;
12398     }
12399     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12400     {
12401       // draw checkbutton gadgets
12402       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12403            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12404         MapCheckbuttonGadget(i);
12405
12406       // draw counter gadgets
12407       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12408            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12409         MapCounterButtons(i);
12410
12411       // draw selectbox gadgets
12412       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12413            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12414         MapSelectboxGadget(i);
12415
12416       // draw drawing area gadgets
12417       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12418       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12419       DrawCustomContentArea();
12420     }
12421   }
12422   else if (IS_GROUP_ELEMENT(properties_element))
12423   {
12424     // draw stickybutton gadget
12425     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12426
12427     // draw checkbutton gadgets
12428     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12429     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12430
12431     // draw counter gadgets
12432     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12433
12434     // draw selectbox gadgets
12435     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12436
12437     // draw textbutton gadgets
12438     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12439
12440     // draw drawing area gadgets
12441     DrawGroupElementArea();
12442
12443     // draw text input gadgets
12444     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12445
12446     // draw drawing area gadgets
12447     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12448
12449     draw_footer_line = TRUE;
12450   }
12451   else if (IS_EMPTY_ELEMENT(properties_element))
12452   {
12453     // draw stickybutton gadget
12454     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12455
12456     // draw checkbutton gadgets
12457     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12458     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12459
12460     // draw textbutton gadgets
12461     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12462
12463     // draw drawing area gadgets
12464     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12465
12466     draw_footer_line = TRUE;
12467   }
12468
12469   // draw little footer border line above CE/GE use/save template gadgets
12470   if (draw_footer_line)
12471   {
12472     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12473     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12474     int gd_x = gd->x + gd_gi1->border.width / 2;
12475     int gd_y = gd->y + gd_gi1->height - 1;
12476     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12477
12478     if (tab_color != BLACK_PIXEL)               // black => transparent
12479       FillRectangle(drawto,
12480                     SX + ED_ELEMENT_SETTINGS_X(0),
12481                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12482                     ED_TAB_BAR_HEIGHT,
12483                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12484   }
12485 }
12486
12487 static void DrawPropertiesChangeDrawingAreas(void)
12488 {
12489   if (IS_CUSTOM_ELEMENT(properties_element))
12490   {
12491     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12492     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12493     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12494
12495     DrawCustomChangeContentArea();
12496   }
12497
12498   redraw_mask |= REDRAW_FIELD;
12499 }
12500
12501 static void DrawPropertiesChange(void)
12502 {
12503   int i;
12504
12505   // needed to initially set selectbox options for special action options
12506   setSelectboxSpecialActionOptions();
12507
12508   // draw stickybutton gadget
12509   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12510
12511   // draw checkbutton gadgets
12512   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12513        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12514     MapCheckbuttonGadget(i);
12515
12516   // draw counter gadgets
12517   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12518        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12519     MapCounterButtons(i);
12520
12521   // draw selectbox gadgets
12522   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12523        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12524     MapSelectboxGadget(i);
12525
12526   // draw textbutton gadgets
12527   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12528        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12529     MapTextbuttonGadget(i);
12530
12531   // draw graphicbutton gadgets
12532   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12533        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12534     MapGraphicbuttonGadget(i);
12535
12536   // draw drawing area gadgets
12537   DrawPropertiesChangeDrawingAreas();
12538 }
12539
12540 static void DrawEditorElementAnimation(int x, int y)
12541 {
12542   int graphic;
12543   int frame;
12544
12545   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12546
12547   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12548 }
12549
12550 static void DrawEditorElementName(int x, int y, int font_nr)
12551 {
12552   char *element_name = getElementInfoText(properties_element);
12553   int font_width = getFontWidth(font_nr);
12554   int font_height = getFontHeight(font_nr);
12555   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12556   int max_chars_per_line = max_text_width / font_width;
12557
12558   if (strlen(element_name) <= max_chars_per_line)
12559     DrawTextS(x, y, font_nr, element_name);
12560   else
12561   {
12562     char buffer[max_chars_per_line + 1];
12563     int next_pos = max_chars_per_line;
12564
12565     strncpy(buffer, element_name, max_chars_per_line);
12566     buffer[max_chars_per_line] = '\0';
12567
12568     if (element_name[max_chars_per_line] == ' ')
12569       next_pos++;
12570     else
12571     {
12572       int i;
12573
12574       for (i = max_chars_per_line - 1; i >= 0; i--)
12575         if (buffer[i] == ' ')
12576           break;
12577
12578       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12579       {
12580         buffer[i] = '\0';
12581         next_pos = i + 1;
12582       }
12583     }
12584
12585     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12586
12587     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12588     buffer[max_chars_per_line] = '\0';
12589
12590     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12591   }
12592 }
12593
12594 static void DrawPropertiesWindow(void)
12595 {
12596   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12597   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12598   int border_size = gd->border_size;
12599   int font_nr = FONT_TEXT_1;
12600   int font_height = getFontHeight(font_nr);
12601   int xoffset = TILEX + element_border + 3 * border_size;
12602   int yoffset = (TILEY - font_height) / 2;
12603   int x1 = editor.settings.element_graphic.x + element_border;
12604   int y1 = editor.settings.element_graphic.y + element_border;
12605   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12606             editor.settings.element_name.x);
12607   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12608             editor.settings.element_name.y);
12609   char *text = "Element Settings";
12610   int font2_nr = FONT_TITLE_1;
12611   struct MenuPosInfo *pos = &editor.settings.headline;
12612   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12613   int sy = SY + pos->y;
12614
12615   stick_element_properties_window = FALSE;
12616
12617   // make sure that previous properties edit mode exists for this element
12618   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12619       !IS_CUSTOM_ELEMENT(properties_element))
12620     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12621
12622   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12623       !IS_PLAYER_ELEMENT(properties_element) &&
12624       !IS_CUSTOM_ELEMENT(properties_element))
12625     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12626
12627   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12628       (IS_PLAYER_ELEMENT(properties_element) ||
12629        IS_CUSTOM_ELEMENT(properties_element)))
12630     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12631
12632   CopyElementPropertiesToEditor(properties_element);
12633
12634   UnmapLevelEditorFieldGadgets();
12635   UnmapLevelEditorToolboxDrawingGadgets();
12636   UnmapLevelEditorToolboxCustomGadgets();
12637
12638   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12639
12640   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12641   ClearField();
12642
12643   DrawText(sx, sy, text, font2_nr);
12644
12645   FrameCounter = 0;     // restart animation frame counter
12646
12647   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12648   DrawEditorElementAnimation(SX + x1, SY + y1);
12649   DrawEditorElementName(x2, y2, font_nr);
12650
12651   DrawPropertiesTabulatorGadgets();
12652
12653   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12654     DrawPropertiesInfo();
12655   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12656     DrawPropertiesChange();
12657   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12658     DrawPropertiesConfig();
12659 }
12660
12661 static void DrawPaletteWindow(void)
12662 {
12663   int i;
12664
12665   UnmapLevelEditorFieldGadgets();
12666
12667   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12668   ClearField();
12669
12670   // map buttons to select elements
12671   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12672     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12673   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12674   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12675   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12676 }
12677
12678 static void UpdateCustomElementGraphicGadgets(void)
12679 {
12680   int i;
12681
12682   InitElementPropertiesGfxElement();
12683
12684   ModifyEditorElementList();
12685   RedrawDrawingElements();
12686
12687   // force redraw of all mapped drawing area gadgets
12688   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12689   {
12690     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12691
12692     if (gi->mapped)
12693       MapDrawingArea(i);
12694   }
12695 }
12696
12697 static int getOpenDirectionFromTube(int element)
12698 {
12699   switch (element)
12700   {
12701     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12702     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12703     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12704     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12705     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12706     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12707     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12708     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12709     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12710     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12711     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12712   }
12713
12714   return MV_NONE;
12715 }
12716
12717 static int getTubeFromOpenDirection(int direction)
12718 {
12719   switch (direction)
12720   {
12721     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12722     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12723     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12724     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12725     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12726     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12727     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12728     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12729     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12730     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12731     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12732
12733     // if only one direction, fall back to simple tube with that direction
12734     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12735     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12736     case (MV_UP):                       return EL_TUBE_VERTICAL;
12737     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12738   }
12739
12740   return EL_EMPTY;
12741 }
12742
12743 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12744 {
12745   int element_new = getTubeFromOpenDirection(direction);
12746
12747   return (element_new != EL_EMPTY ? element_new : element_old);
12748 }
12749
12750 static int getOpenDirectionFromBelt(int element)
12751 {
12752   int belt_dir = getBeltDirFromBeltElement(element);
12753
12754   return (belt_dir == MV_LEFT ? MV_RIGHT :
12755           belt_dir == MV_RIGHT ? MV_LEFT :
12756           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12757 }
12758
12759 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12760 {
12761   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12762                   direction == MV_RIGHT ? MV_LEFT :
12763                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12764
12765   if (direction == MV_NONE)
12766     return EL_EMPTY;
12767
12768   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12769 }
12770
12771 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12772                                                  int element_old)
12773 {
12774   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12775
12776   return (element_new != EL_EMPTY ? element_new : element_old);
12777 }
12778
12779 static int getOpenDirectionFromPool(int element)
12780 {
12781   switch (element)
12782   {
12783     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12784     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12785     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12786     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12787     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12788     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12789   }
12790
12791   return MV_NONE;
12792 }
12793
12794 static int getPoolFromOpenDirection(int direction)
12795 {
12796   switch (direction)
12797   {
12798     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12799     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12800     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12801     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12802     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12803     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12804   }
12805
12806   return EL_EMPTY;
12807 }
12808
12809 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12810 {
12811   int element = getPoolFromOpenDirection(direction);
12812   int help_direction = getOpenDirectionFromPool(help_element);
12813
12814   if (element == EL_EMPTY)
12815   {
12816     int help_direction_vertical = help_direction & MV_VERTICAL;
12817
12818     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12819   }
12820
12821   if (element == EL_EMPTY)
12822   {
12823     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12824
12825     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12826   }
12827
12828   return element;
12829 }
12830
12831 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12832 {
12833   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12834
12835   return (element_new != EL_EMPTY ? element_new : element_old);
12836 }
12837
12838 static int getOpenDirectionFromPillar(int element)
12839 {
12840   switch (element)
12841   {
12842     case EL_EMC_WALL_1:                 return (MV_DOWN);
12843     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12844     case EL_EMC_WALL_3:                 return (MV_UP);
12845   }
12846
12847   return MV_NONE;
12848 }
12849
12850 static int getPillarFromOpenDirection(int direction)
12851 {
12852   switch (direction)
12853   {
12854     case (MV_DOWN):                     return EL_EMC_WALL_1;
12855     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12856     case (MV_UP):                       return EL_EMC_WALL_3;
12857   }
12858
12859   return EL_EMPTY;
12860 }
12861
12862 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12863 {
12864   int element_new = getPillarFromOpenDirection(direction);
12865
12866   return (element_new != EL_EMPTY ? element_new : element_old);
12867 }
12868
12869 static int getOpenDirectionFromSteel2(int element)
12870 {
12871   switch (element)
12872   {
12873     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12874     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12875     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12876     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12877     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12878     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12879     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12880     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12881   }
12882
12883   return MV_NONE;
12884 }
12885
12886 static int getSteel2FromOpenDirection(int direction)
12887 {
12888   switch (direction)
12889   {
12890     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12891     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12892     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12893     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12894     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12895     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12896     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12897     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12898   }
12899
12900   return EL_EMPTY;
12901 }
12902
12903 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12904 {
12905   int element_new = getSteel2FromOpenDirection(direction);
12906
12907   return (element_new != EL_EMPTY ? element_new : element_old);
12908 }
12909
12910 static int getOpenDirectionFromChip(int element)
12911 {
12912   switch (element)
12913   {
12914     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12915     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12916     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12917     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12918     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12919   }
12920
12921   return MV_NONE;
12922 }
12923
12924 static int getChipFromOpenDirection(int direction)
12925 {
12926   switch (direction)
12927   {
12928     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12929     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12930     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12931     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12932     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12933   }
12934
12935   return EL_EMPTY;
12936 }
12937
12938 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12939 {
12940   int element_new = getChipFromOpenDirection(direction);
12941
12942   return (element_new != EL_EMPTY ? element_new : element_old);
12943 }
12944
12945 static int getClosedTube(int x, int y)
12946 {
12947   struct XY *xy = xy_directions;
12948   int element_old = IntelliDrawBuffer[x][y];
12949   int direction_old = getOpenDirectionFromTube(element_old);
12950   int direction_new = MV_NONE;
12951   int i;
12952
12953   for (i = 0; i < NUM_DIRECTIONS; i++)
12954   {
12955     int xx = x + xy[i].x;
12956     int yy = y + xy[i].y;
12957     int dir = MV_DIR_FROM_BIT(i);
12958     int dir_opposite = MV_DIR_OPPOSITE(dir);
12959
12960     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12961         (direction_old & dir) &&
12962         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12963       direction_new |= dir;
12964   }
12965
12966   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12967 }
12968
12969 static int getClosedBelt(int x, int y)
12970 {
12971   struct XY *xy = xy_directions;
12972   int element_old = IntelliDrawBuffer[x][y];
12973   int nr = getBeltNrFromBeltElement(element_old);
12974   int direction_old = getOpenDirectionFromBelt(element_old);
12975   int direction_new = MV_NONE;
12976   int i;
12977
12978   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12979   {
12980     int xx = x + xy[i].x;
12981     int yy = y + xy[i].y;
12982     int dir = MV_DIR_FROM_BIT(i);
12983     int dir_opposite = MV_DIR_OPPOSITE(dir);
12984
12985     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12986         (direction_old & dir) &&
12987         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12988       direction_new |= dir;
12989   }
12990
12991   return getBeltFromNrAndOpenDirection(nr, direction_new);
12992 }
12993
12994 static int getClosedPool(int x, int y)
12995 {
12996   struct XY *xy = xy_directions;
12997   int element_old = IntelliDrawBuffer[x][y];
12998   int direction_old = getOpenDirectionFromPool(element_old);
12999   int direction_new = MV_NONE;
13000   int i;
13001
13002   for (i = 0; i < NUM_DIRECTIONS; i++)
13003   {
13004     int xx = x + xy[i].x;
13005     int yy = y + xy[i].y;
13006     int dir = MV_DIR_FROM_BIT(i);
13007     int dir_opposite = MV_DIR_OPPOSITE(dir);
13008
13009     if (IN_LEV_FIELD(xx, yy) &&
13010         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
13011         (direction_old & dir) &&
13012         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13013       direction_new |= dir;
13014   }
13015
13016   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
13017 }
13018
13019 static int getClosedPillar(int x, int y)
13020 {
13021   struct XY *xy = xy_directions;
13022   int element_old = IntelliDrawBuffer[x][y];
13023   int direction_old = getOpenDirectionFromPillar(element_old);
13024   int direction_new = MV_NONE;
13025   int i;
13026
13027   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13028   {
13029     int xx = x + xy[i].x;
13030     int yy = y + xy[i].y;
13031     int dir = MV_DIR_FROM_BIT(i);
13032     int dir_opposite = MV_DIR_OPPOSITE(dir);
13033
13034     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
13035         (direction_old & dir) &&
13036         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13037       direction_new |= dir;
13038   }
13039
13040   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
13041 }
13042
13043 static int getClosedSteel2(int x, int y)
13044 {
13045   struct XY *xy = xy_directions;
13046   int element_old = IntelliDrawBuffer[x][y];
13047   int direction_old = getOpenDirectionFromSteel2(element_old);
13048   int direction_new = MV_NONE;
13049   int i;
13050
13051   for (i = 0; i < NUM_DIRECTIONS; i++)
13052   {
13053     int xx = x + xy[i].x;
13054     int yy = y + xy[i].y;
13055     int dir = MV_DIR_FROM_BIT(i);
13056     int dir_opposite = MV_DIR_OPPOSITE(dir);
13057
13058     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
13059         (direction_old & dir) &&
13060         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13061       direction_new |= dir;
13062   }
13063
13064   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
13065 }
13066
13067 static int getClosedChip(int x, int y)
13068 {
13069   struct XY *xy = xy_directions;
13070   int element_old = IntelliDrawBuffer[x][y];
13071   int direction_old = getOpenDirectionFromChip(element_old);
13072   int direction_new = MV_NONE;
13073   int i;
13074
13075   for (i = 0; i < NUM_DIRECTIONS; i++)
13076   {
13077     int xx = x + xy[i].x;
13078     int yy = y + xy[i].y;
13079     int dir = MV_DIR_FROM_BIT(i);
13080     int dir_opposite = MV_DIR_OPPOSITE(dir);
13081
13082     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
13083         (direction_old & dir) &&
13084         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13085       direction_new |= dir;
13086   }
13087
13088   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
13089 }
13090
13091 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
13092                                 boolean change_level)
13093 {
13094   int sx = x - level_xpos;
13095   int sy = y - level_ypos;
13096   int old_element = Tile[x][y];
13097   int new_element = element;
13098   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
13099   boolean draw_masked = FALSE;
13100
13101   if (IS_MM_WALL_EDITOR(element))
13102   {
13103     element = map_mm_wall_element_editor(element) | new_bitmask;
13104
13105     if (IS_MM_WALL(old_element))
13106       element |= MM_WALL_BITS(old_element);
13107
13108     if (!change_level)
13109       draw_masked = TRUE;
13110   }
13111   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
13112   {
13113     int element_changed = old_element & ~new_bitmask;
13114
13115     if (MM_WALL_BITS(element_changed) != 0)
13116       element = element_changed;
13117   }
13118
13119   IntelliDrawBuffer[x][y] = element;
13120
13121   if (change_level)
13122     Tile[x][y] = element;
13123
13124   if (IN_ED_FIELD(sx, sy))
13125   {
13126     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
13127       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
13128     else if (draw_masked)
13129       DrawEditorElementThruMask(sx, sy, element);
13130     else
13131       DrawEditorElement(sx, sy, element);
13132   }
13133 }
13134
13135 static void SetElementSimple(int x, int y, int element, boolean change_level)
13136 {
13137   SetElementSimpleExt(x, y, 0, 0, element, change_level);
13138 }
13139
13140 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
13141                                            int x2, int y2, int *element2,
13142                                            int (*close_function)(int, int),
13143                                            boolean change_level)
13144 {
13145   // set neighbour elements to newly determined connections
13146   SetElementSimple(x1, y1, *element1, change_level);
13147   SetElementSimple(x2, y2, *element2, change_level);
13148
13149   // remove all open connections of neighbour elements
13150   *element1 = close_function(x1, y1);
13151   *element2 = close_function(x2, y2);
13152
13153   // set neighbour elements to new, minimized connections
13154   SetElementSimple(x1, y1, *element1, change_level);
13155   SetElementSimple(x2, y2, *element2, change_level);
13156 }
13157
13158 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
13159                                   boolean change_level, int button)
13160 {
13161   struct XY *xy = xy_directions;
13162   static int last_x = -1;
13163   static int last_y = -1;
13164
13165   if (new_element == EL_UNDEFINED)
13166   {
13167     last_x = -1;
13168     last_y = -1;
13169
13170     return;
13171   }
13172
13173   int old_element = IntelliDrawBuffer[x][y];
13174
13175   if (IS_TUBE(new_element))
13176   {
13177     int last_element_new = EL_UNDEFINED;
13178     int direction = MV_NONE;
13179     int i;
13180
13181     // if old element is of same kind, keep all existing directions
13182     if (IS_TUBE(old_element))
13183       direction |= getOpenDirectionFromTube(old_element);
13184
13185     for (i = 0; i < NUM_DIRECTIONS; i++)
13186     {
13187       int xx = x + xy[i].x;
13188       int yy = y + xy[i].y;
13189
13190       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13191           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13192       {
13193         int dir = MV_DIR_FROM_BIT(i);
13194         int dir_opposite = MV_DIR_OPPOSITE(dir);
13195         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13196         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13197         int last_direction_new = last_direction_old | dir_opposite;
13198
13199         last_element_new = getTubeFromOpenDirection(last_direction_new);
13200
13201         direction |= dir;
13202       }
13203     }
13204
13205     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13206
13207     if (last_element_new != EL_UNDEFINED)
13208       MergeAndCloseNeighbourElements(x, y, &new_element,
13209                                      last_x, last_y, &last_element_new,
13210                                      getClosedTube, change_level);
13211   }
13212   else if (IS_BELT(new_element))
13213   {
13214     int belt_nr = getBeltNrFromBeltElement(new_element);
13215     int last_element_new = EL_UNDEFINED;
13216     int direction = MV_NONE;
13217     int i;
13218
13219     // if old element is of same kind, keep all existing directions
13220     if (IS_BELT(old_element))
13221       direction |= getOpenDirectionFromBelt(old_element);
13222
13223     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13224     {
13225       int xx = x + xy[i].x;
13226       int yy = y + xy[i].y;
13227
13228       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13229           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
13230       {
13231         int dir = MV_DIR_FROM_BIT(i);
13232         int dir_opposite = MV_DIR_OPPOSITE(dir);
13233         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13234         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
13235         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13236         int last_direction_new = last_direction_old | dir_opposite;
13237
13238         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13239                                                          last_direction_new);
13240         direction |= dir;
13241       }
13242     }
13243
13244     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13245                                                         new_element);
13246     if (last_element_new != EL_UNDEFINED)
13247       MergeAndCloseNeighbourElements(x, y, &new_element,
13248                                      last_x, last_y, &last_element_new,
13249                                      getClosedBelt, change_level);
13250   }
13251   else if (IS_ACID_POOL_OR_ACID(new_element))
13252   {
13253     int last_element_new = EL_UNDEFINED;
13254     int direction = MV_NONE;
13255     int i;
13256
13257     // if old element is of same kind, keep all existing directions
13258     if (IS_ACID_POOL_OR_ACID(old_element))
13259       direction |= getOpenDirectionFromPool(old_element);
13260
13261     for (i = 0; i < NUM_DIRECTIONS; i++)
13262     {
13263       int xx = x + xy[i].x;
13264       int yy = y + xy[i].y;
13265
13266       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13267           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
13268       {
13269         int dir = MV_DIR_FROM_BIT(i);
13270         int dir_opposite = MV_DIR_OPPOSITE(dir);
13271         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13272         int last_direction_old = getOpenDirectionFromPool(last_element_old);
13273         int last_direction_new = last_direction_old | dir_opposite;
13274
13275         last_element_new = getPoolFromOpenDirection(last_direction_new);
13276
13277         direction |= dir;
13278       }
13279     }
13280
13281     // special corrections needed for intuitively correct acid pool drawing
13282     if (last_element_new == EL_EMPTY)
13283       last_element_new = new_element;
13284     else if (last_element_new != EL_UNDEFINED)
13285       new_element = last_element_new;
13286
13287     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13288
13289     if (last_element_new != EL_UNDEFINED)
13290       MergeAndCloseNeighbourElements(x, y, &new_element,
13291                                      last_x, last_y, &last_element_new,
13292                                      getClosedPool, change_level);
13293   }
13294   else if (IS_EMC_PILLAR(new_element))
13295   {
13296     int last_element_new = EL_UNDEFINED;
13297     int direction = MV_NONE;
13298     int i;
13299
13300     // if old element is of same kind, keep all existing directions
13301     if (IS_EMC_PILLAR(old_element))
13302       direction |= getOpenDirectionFromPillar(old_element);
13303
13304     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13305     {
13306       int xx = x + xy[i].x;
13307       int yy = y + xy[i].y;
13308
13309       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13310           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13311       {
13312         int dir = MV_DIR_FROM_BIT(i);
13313         int dir_opposite = MV_DIR_OPPOSITE(dir);
13314         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13315         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13316         int last_direction_new = last_direction_old | dir_opposite;
13317
13318         last_element_new = getPillarFromOpenDirection(last_direction_new);
13319
13320         direction |= dir;
13321       }
13322     }
13323
13324     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13325
13326     if (last_element_new != EL_UNDEFINED)
13327       MergeAndCloseNeighbourElements(x, y, &new_element,
13328                                      last_x, last_y, &last_element_new,
13329                                      getClosedPillar, change_level);
13330   }
13331   else if (IS_DC_STEELWALL_2(new_element))
13332   {
13333     int last_element_new = EL_UNDEFINED;
13334     int direction = MV_NONE;
13335     int i;
13336
13337     // if old element is of same kind, keep all existing directions
13338     if (IS_DC_STEELWALL_2(old_element))
13339       direction |= getOpenDirectionFromSteel2(old_element);
13340
13341     for (i = 0; i < NUM_DIRECTIONS; i++)
13342     {
13343       int xx = x + xy[i].x;
13344       int yy = y + xy[i].y;
13345
13346       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13347           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13348       {
13349         int dir = MV_DIR_FROM_BIT(i);
13350         int dir_opposite = MV_DIR_OPPOSITE(dir);
13351         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13352         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13353         int last_direction_new = last_direction_old | dir_opposite;
13354
13355         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13356
13357         direction |= dir;
13358       }
13359     }
13360
13361     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13362
13363     if (last_element_new != EL_UNDEFINED)
13364       MergeAndCloseNeighbourElements(x, y, &new_element,
13365                                      last_x, last_y, &last_element_new,
13366                                      getClosedSteel2, change_level);
13367   }
13368   else if (IS_SP_CHIP(new_element))
13369   {
13370     int last_element_new = EL_UNDEFINED;
13371     int direction = MV_NONE;
13372     int i;
13373
13374     // (do not keep existing directions, regardless of kind of old element)
13375
13376     for (i = 0; i < NUM_DIRECTIONS; i++)
13377     {
13378       int xx = x + xy[i].x;
13379       int yy = y + xy[i].y;
13380
13381       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13382           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13383       {
13384         int dir = MV_DIR_FROM_BIT(i);
13385         int dir_opposite = MV_DIR_OPPOSITE(dir);
13386         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13387         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13388         int last_direction_new = last_direction_old | dir_opposite;
13389
13390         if (last_direction_old == MV_NONE)
13391         {
13392           last_element_new = getChipFromOpenDirection(last_direction_new);
13393           direction |= dir;
13394         }
13395         else if (last_direction_old & (dir | dir_opposite))
13396         {
13397           direction |= MV_DIR_OPPOSITE(last_direction_old);
13398         }
13399         else
13400         {
13401           direction |= MV_DIR_OPPOSITE(dir);
13402         }
13403       }
13404     }
13405
13406     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13407
13408     if (last_element_new != EL_UNDEFINED)
13409       MergeAndCloseNeighbourElements(x, y, &new_element,
13410                                      last_x, last_y, &last_element_new,
13411                                      getClosedChip, change_level);
13412   }
13413   else if (IS_SP_HARDWARE_BASE(new_element))
13414   {
13415     int nr = GetSimpleRandom(6);
13416
13417     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13418                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13419                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13420                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13421                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13422   }
13423   else if (new_element == EL_SP_HARDWARE_GREEN ||
13424            new_element == EL_SP_HARDWARE_BLUE ||
13425            new_element == EL_SP_HARDWARE_RED)
13426   {
13427     int nr = GetSimpleRandom(3);
13428
13429     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13430                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13431   }
13432   else if (IS_GROUP_ELEMENT(new_element))
13433   {
13434     boolean connected_drawing = FALSE;
13435     int i;
13436
13437     for (i = 0; i < NUM_DIRECTIONS; i++)
13438     {
13439       int xx = x + xy[i].x;
13440       int yy = y + xy[i].y;
13441
13442       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13443           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13444         connected_drawing = TRUE;
13445     }
13446
13447     if (!connected_drawing)
13448       ResolveGroupElement(new_element);
13449
13450     new_element = GetElementFromGroupElement(new_element);
13451   }
13452   else if (IS_BELT_SWITCH(old_element))
13453   {
13454     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13455     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13456
13457     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13458                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13459
13460     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13461   }
13462   else
13463   {
13464     static int swappable_elements[][2] =
13465     {
13466       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13467       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13468       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13469       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13470       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13471       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13472       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13473       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13474       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13475       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13476       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13477       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13478       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13479       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13480       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13481       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13482       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13483       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13484       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13485       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13486       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13487       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13488       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13489       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13490       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13491       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13492       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13493       { EL_PEARL,                       EL_WALL_PEARL                   },
13494       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13495       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13496       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13497       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13498       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13499       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13500       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13501       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13502       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13503       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13504       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13505       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13506       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13507       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13508       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13509       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13510
13511       { -1,                             -1                              },
13512     };
13513     static int rotatable_elements_4[][4] =
13514     {
13515       {
13516         EL_BUG_UP,
13517         EL_BUG_RIGHT,
13518         EL_BUG_DOWN,
13519         EL_BUG_LEFT
13520       },
13521       {
13522         EL_SPACESHIP_UP,
13523         EL_SPACESHIP_RIGHT,
13524         EL_SPACESHIP_DOWN,
13525         EL_SPACESHIP_LEFT
13526       },
13527       {
13528         EL_BD_BUTTERFLY_UP,
13529         EL_BD_BUTTERFLY_RIGHT,
13530         EL_BD_BUTTERFLY_DOWN,
13531         EL_BD_BUTTERFLY_LEFT
13532       },
13533       {
13534         EL_BD_FIREFLY_UP,
13535         EL_BD_FIREFLY_RIGHT,
13536         EL_BD_FIREFLY_DOWN,
13537         EL_BD_FIREFLY_LEFT
13538       },
13539       {
13540         EL_PACMAN_UP,
13541         EL_PACMAN_RIGHT,
13542         EL_PACMAN_DOWN,
13543         EL_PACMAN_LEFT
13544       },
13545       {
13546         EL_YAMYAM_UP,
13547         EL_YAMYAM_RIGHT,
13548         EL_YAMYAM_DOWN,
13549         EL_YAMYAM_LEFT
13550       },
13551       {
13552         EL_ARROW_UP,
13553         EL_ARROW_RIGHT,
13554         EL_ARROW_DOWN,
13555         EL_ARROW_LEFT
13556       },
13557       {
13558         EL_SP_PORT_UP,
13559         EL_SP_PORT_RIGHT,
13560         EL_SP_PORT_DOWN,
13561         EL_SP_PORT_LEFT
13562       },
13563       {
13564         EL_SP_GRAVITY_PORT_UP,
13565         EL_SP_GRAVITY_PORT_RIGHT,
13566         EL_SP_GRAVITY_PORT_DOWN,
13567         EL_SP_GRAVITY_PORT_LEFT
13568       },
13569       {
13570         EL_SP_GRAVITY_ON_PORT_UP,
13571         EL_SP_GRAVITY_ON_PORT_RIGHT,
13572         EL_SP_GRAVITY_ON_PORT_DOWN,
13573         EL_SP_GRAVITY_ON_PORT_LEFT
13574       },
13575       {
13576         EL_SP_GRAVITY_OFF_PORT_UP,
13577         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13578         EL_SP_GRAVITY_OFF_PORT_DOWN,
13579         EL_SP_GRAVITY_OFF_PORT_LEFT
13580       },
13581       {
13582         EL_MOLE_UP,
13583         EL_MOLE_RIGHT,
13584         EL_MOLE_DOWN,
13585         EL_MOLE_LEFT
13586       },
13587       {
13588         EL_BALLOON_SWITCH_UP,
13589         EL_BALLOON_SWITCH_RIGHT,
13590         EL_BALLOON_SWITCH_DOWN,
13591         EL_BALLOON_SWITCH_LEFT
13592       },
13593       {
13594         EL_MM_MCDUFFIN_UP,
13595         EL_MM_MCDUFFIN_RIGHT,
13596         EL_MM_MCDUFFIN_DOWN,
13597         EL_MM_MCDUFFIN_LEFT
13598       },
13599       {
13600         EL_MM_MIRROR_FIXED_1,
13601         EL_MM_MIRROR_FIXED_4,
13602         EL_MM_MIRROR_FIXED_3,
13603         EL_MM_MIRROR_FIXED_2
13604       },
13605       {
13606         EL_MM_STEEL_GRID_FIXED_1,
13607         EL_MM_STEEL_GRID_FIXED_4,
13608         EL_MM_STEEL_GRID_FIXED_2,
13609         EL_MM_STEEL_GRID_FIXED_3
13610       },
13611       {
13612         EL_MM_WOODEN_GRID_FIXED_1,
13613         EL_MM_WOODEN_GRID_FIXED_4,
13614         EL_MM_WOODEN_GRID_FIXED_2,
13615         EL_MM_WOODEN_GRID_FIXED_3
13616       },
13617       {
13618         EL_MM_POLARIZER_CROSS_1,
13619         EL_MM_POLARIZER_CROSS_4,
13620         EL_MM_POLARIZER_CROSS_3,
13621         EL_MM_POLARIZER_CROSS_2
13622       },
13623       {
13624         EL_MM_PACMAN_UP,
13625         EL_MM_PACMAN_RIGHT,
13626         EL_MM_PACMAN_DOWN,
13627         EL_MM_PACMAN_LEFT
13628       },
13629       {
13630         EL_DF_LASER_UP,
13631         EL_DF_LASER_RIGHT,
13632         EL_DF_LASER_DOWN,
13633         EL_DF_LASER_LEFT
13634       },
13635       {
13636         EL_DF_RECEIVER_UP,
13637         EL_DF_RECEIVER_RIGHT,
13638         EL_DF_RECEIVER_DOWN,
13639         EL_DF_RECEIVER_LEFT
13640       },
13641       {
13642         EL_DF_SLOPE_1,
13643         EL_DF_SLOPE_4,
13644         EL_DF_SLOPE_3,
13645         EL_DF_SLOPE_2
13646       },
13647
13648       {
13649         -1,
13650       },
13651     };
13652     static int rotatable_elements_8[][8] =
13653     {
13654       {
13655         EL_DF_STEEL_GRID_FIXED_1,
13656         EL_DF_STEEL_GRID_FIXED_8,
13657         EL_DF_STEEL_GRID_FIXED_7,
13658         EL_DF_STEEL_GRID_FIXED_6,
13659         EL_DF_STEEL_GRID_FIXED_5,
13660         EL_DF_STEEL_GRID_FIXED_4,
13661         EL_DF_STEEL_GRID_FIXED_3,
13662         EL_DF_STEEL_GRID_FIXED_2
13663       },
13664       {
13665         EL_DF_WOODEN_GRID_FIXED_1,
13666         EL_DF_WOODEN_GRID_FIXED_8,
13667         EL_DF_WOODEN_GRID_FIXED_7,
13668         EL_DF_WOODEN_GRID_FIXED_6,
13669         EL_DF_WOODEN_GRID_FIXED_5,
13670         EL_DF_WOODEN_GRID_FIXED_4,
13671         EL_DF_WOODEN_GRID_FIXED_3,
13672         EL_DF_WOODEN_GRID_FIXED_2
13673       },
13674       {
13675         EL_DF_STEEL_GRID_ROTATING_1,
13676         EL_DF_STEEL_GRID_ROTATING_8,
13677         EL_DF_STEEL_GRID_ROTATING_7,
13678         EL_DF_STEEL_GRID_ROTATING_6,
13679         EL_DF_STEEL_GRID_ROTATING_5,
13680         EL_DF_STEEL_GRID_ROTATING_4,
13681         EL_DF_STEEL_GRID_ROTATING_3,
13682         EL_DF_STEEL_GRID_ROTATING_2
13683       },
13684       {
13685         EL_DF_WOODEN_GRID_ROTATING_1,
13686         EL_DF_WOODEN_GRID_ROTATING_8,
13687         EL_DF_WOODEN_GRID_ROTATING_7,
13688         EL_DF_WOODEN_GRID_ROTATING_6,
13689         EL_DF_WOODEN_GRID_ROTATING_5,
13690         EL_DF_WOODEN_GRID_ROTATING_4,
13691         EL_DF_WOODEN_GRID_ROTATING_3,
13692         EL_DF_WOODEN_GRID_ROTATING_2
13693       },
13694
13695       {
13696         -1,
13697       },
13698     };
13699     static int rotatable_elements_16[][16] =
13700     {
13701       {
13702         EL_MM_MIRROR_1,
13703         EL_MM_MIRROR_16,
13704         EL_MM_MIRROR_15,
13705         EL_MM_MIRROR_14,
13706         EL_MM_MIRROR_13,
13707         EL_MM_MIRROR_12,
13708         EL_MM_MIRROR_11,
13709         EL_MM_MIRROR_10,
13710         EL_MM_MIRROR_9,
13711         EL_MM_MIRROR_8,
13712         EL_MM_MIRROR_7,
13713         EL_MM_MIRROR_6,
13714         EL_MM_MIRROR_5,
13715         EL_MM_MIRROR_4,
13716         EL_MM_MIRROR_3,
13717         EL_MM_MIRROR_2
13718       },
13719       {
13720         EL_MM_TELEPORTER_5,
13721         EL_MM_TELEPORTER_4,
13722         EL_MM_TELEPORTER_3,
13723         EL_MM_TELEPORTER_2,
13724         EL_MM_TELEPORTER_1,
13725         EL_MM_TELEPORTER_16,
13726         EL_MM_TELEPORTER_15,
13727         EL_MM_TELEPORTER_14,
13728         EL_MM_TELEPORTER_13,
13729         EL_MM_TELEPORTER_12,
13730         EL_MM_TELEPORTER_11,
13731         EL_MM_TELEPORTER_10,
13732         EL_MM_TELEPORTER_9,
13733         EL_MM_TELEPORTER_8,
13734         EL_MM_TELEPORTER_7,
13735         EL_MM_TELEPORTER_6
13736       },
13737       {
13738         EL_MM_TELEPORTER_RED_5,
13739         EL_MM_TELEPORTER_RED_4,
13740         EL_MM_TELEPORTER_RED_3,
13741         EL_MM_TELEPORTER_RED_2,
13742         EL_MM_TELEPORTER_RED_1,
13743         EL_MM_TELEPORTER_RED_16,
13744         EL_MM_TELEPORTER_RED_15,
13745         EL_MM_TELEPORTER_RED_14,
13746         EL_MM_TELEPORTER_RED_13,
13747         EL_MM_TELEPORTER_RED_12,
13748         EL_MM_TELEPORTER_RED_11,
13749         EL_MM_TELEPORTER_RED_10,
13750         EL_MM_TELEPORTER_RED_9,
13751         EL_MM_TELEPORTER_RED_8,
13752         EL_MM_TELEPORTER_RED_7,
13753         EL_MM_TELEPORTER_RED_6
13754       },
13755       {
13756         EL_MM_TELEPORTER_YELLOW_5,
13757         EL_MM_TELEPORTER_YELLOW_4,
13758         EL_MM_TELEPORTER_YELLOW_3,
13759         EL_MM_TELEPORTER_YELLOW_2,
13760         EL_MM_TELEPORTER_YELLOW_1,
13761         EL_MM_TELEPORTER_YELLOW_16,
13762         EL_MM_TELEPORTER_YELLOW_15,
13763         EL_MM_TELEPORTER_YELLOW_14,
13764         EL_MM_TELEPORTER_YELLOW_13,
13765         EL_MM_TELEPORTER_YELLOW_12,
13766         EL_MM_TELEPORTER_YELLOW_11,
13767         EL_MM_TELEPORTER_YELLOW_10,
13768         EL_MM_TELEPORTER_YELLOW_9,
13769         EL_MM_TELEPORTER_YELLOW_8,
13770         EL_MM_TELEPORTER_YELLOW_7,
13771         EL_MM_TELEPORTER_YELLOW_6
13772       },
13773       {
13774         EL_MM_TELEPORTER_GREEN_5,
13775         EL_MM_TELEPORTER_GREEN_4,
13776         EL_MM_TELEPORTER_GREEN_3,
13777         EL_MM_TELEPORTER_GREEN_2,
13778         EL_MM_TELEPORTER_GREEN_1,
13779         EL_MM_TELEPORTER_GREEN_16,
13780         EL_MM_TELEPORTER_GREEN_15,
13781         EL_MM_TELEPORTER_GREEN_14,
13782         EL_MM_TELEPORTER_GREEN_13,
13783         EL_MM_TELEPORTER_GREEN_12,
13784         EL_MM_TELEPORTER_GREEN_11,
13785         EL_MM_TELEPORTER_GREEN_10,
13786         EL_MM_TELEPORTER_GREEN_9,
13787         EL_MM_TELEPORTER_GREEN_8,
13788         EL_MM_TELEPORTER_GREEN_7,
13789         EL_MM_TELEPORTER_GREEN_6
13790       },
13791       {
13792         EL_MM_TELEPORTER_BLUE_5,
13793         EL_MM_TELEPORTER_BLUE_4,
13794         EL_MM_TELEPORTER_BLUE_3,
13795         EL_MM_TELEPORTER_BLUE_2,
13796         EL_MM_TELEPORTER_BLUE_1,
13797         EL_MM_TELEPORTER_BLUE_16,
13798         EL_MM_TELEPORTER_BLUE_15,
13799         EL_MM_TELEPORTER_BLUE_14,
13800         EL_MM_TELEPORTER_BLUE_13,
13801         EL_MM_TELEPORTER_BLUE_12,
13802         EL_MM_TELEPORTER_BLUE_11,
13803         EL_MM_TELEPORTER_BLUE_10,
13804         EL_MM_TELEPORTER_BLUE_9,
13805         EL_MM_TELEPORTER_BLUE_8,
13806         EL_MM_TELEPORTER_BLUE_7,
13807         EL_MM_TELEPORTER_BLUE_6
13808       },
13809       {
13810         EL_MM_POLARIZER_1,
13811         EL_MM_POLARIZER_16,
13812         EL_MM_POLARIZER_15,
13813         EL_MM_POLARIZER_14,
13814         EL_MM_POLARIZER_13,
13815         EL_MM_POLARIZER_12,
13816         EL_MM_POLARIZER_11,
13817         EL_MM_POLARIZER_10,
13818         EL_MM_POLARIZER_9,
13819         EL_MM_POLARIZER_8,
13820         EL_MM_POLARIZER_7,
13821         EL_MM_POLARIZER_6,
13822         EL_MM_POLARIZER_5,
13823         EL_MM_POLARIZER_4,
13824         EL_MM_POLARIZER_3,
13825         EL_MM_POLARIZER_2
13826       },
13827       {
13828         EL_DF_MIRROR_1,
13829         EL_DF_MIRROR_16,
13830         EL_DF_MIRROR_15,
13831         EL_DF_MIRROR_14,
13832         EL_DF_MIRROR_13,
13833         EL_DF_MIRROR_12,
13834         EL_DF_MIRROR_11,
13835         EL_DF_MIRROR_10,
13836         EL_DF_MIRROR_9,
13837         EL_DF_MIRROR_8,
13838         EL_DF_MIRROR_7,
13839         EL_DF_MIRROR_6,
13840         EL_DF_MIRROR_5,
13841         EL_DF_MIRROR_4,
13842         EL_DF_MIRROR_3,
13843         EL_DF_MIRROR_2
13844       },
13845       {
13846         EL_DF_MIRROR_ROTATING_1,
13847         EL_DF_MIRROR_ROTATING_16,
13848         EL_DF_MIRROR_ROTATING_15,
13849         EL_DF_MIRROR_ROTATING_14,
13850         EL_DF_MIRROR_ROTATING_13,
13851         EL_DF_MIRROR_ROTATING_12,
13852         EL_DF_MIRROR_ROTATING_11,
13853         EL_DF_MIRROR_ROTATING_10,
13854         EL_DF_MIRROR_ROTATING_9,
13855         EL_DF_MIRROR_ROTATING_8,
13856         EL_DF_MIRROR_ROTATING_7,
13857         EL_DF_MIRROR_ROTATING_6,
13858         EL_DF_MIRROR_ROTATING_5,
13859         EL_DF_MIRROR_ROTATING_4,
13860         EL_DF_MIRROR_ROTATING_3,
13861         EL_DF_MIRROR_ROTATING_2
13862       },
13863       {
13864         EL_DF_MIRROR_FIXED_1,
13865         EL_DF_MIRROR_FIXED_16,
13866         EL_DF_MIRROR_FIXED_15,
13867         EL_DF_MIRROR_FIXED_14,
13868         EL_DF_MIRROR_FIXED_13,
13869         EL_DF_MIRROR_FIXED_12,
13870         EL_DF_MIRROR_FIXED_11,
13871         EL_DF_MIRROR_FIXED_10,
13872         EL_DF_MIRROR_FIXED_9,
13873         EL_DF_MIRROR_FIXED_8,
13874         EL_DF_MIRROR_FIXED_7,
13875         EL_DF_MIRROR_FIXED_6,
13876         EL_DF_MIRROR_FIXED_5,
13877         EL_DF_MIRROR_FIXED_4,
13878         EL_DF_MIRROR_FIXED_3,
13879         EL_DF_MIRROR_FIXED_2
13880       },
13881
13882       {
13883         -1,
13884       },
13885     };
13886     int i, j;
13887
13888     for (i = 0; swappable_elements[i][0] != -1; i++)
13889     {
13890       int element1 = swappable_elements[i][0];
13891       int element2 = swappable_elements[i][1];
13892
13893       if (old_element == element1 || old_element == element2)
13894         new_element = (old_element == element1 ? element2 : element1);
13895     }
13896
13897     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13898     {
13899       for (j = 0; j < 4; j++)
13900       {
13901         int element = rotatable_elements_4[i][j];
13902
13903         if (old_element == element)
13904           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13905                          button == 2 ? rotatable_elements_4[i][0]           :
13906                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13907                          old_element);
13908       }
13909     }
13910
13911     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13912     {
13913       for (j = 0; j < 8; j++)
13914       {
13915         int element = rotatable_elements_8[i][j];
13916
13917         if (old_element == element)
13918           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13919                          button == 2 ? rotatable_elements_8[i][0]           :
13920                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13921                          old_element);
13922       }
13923     }
13924
13925     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13926     {
13927       for (j = 0; j < 16; j++)
13928       {
13929         int element = rotatable_elements_16[i][j];
13930
13931         if (old_element == element)
13932           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13933                          button == 2 ? rotatable_elements_16[i][0]             :
13934                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13935                          old_element);
13936       }
13937     }
13938
13939     if (old_element != new_element)
13940     {
13941       int max_infotext_len = getMaxInfoTextLength();
13942       char infotext[MAX_OUTPUT_LINESIZE + 1];
13943
13944       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13945       infotext[max_infotext_len] = '\0';
13946
13947       ClearEditorGadgetInfoText();
13948
13949       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13950                 infotext);
13951     }
13952   }
13953
13954   if (IS_MM_WALL_EDITOR(new_element))
13955     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13956   else
13957     SetElementSimple(x, y, new_element, change_level);
13958
13959   last_x = x;
13960   last_y = y;
13961 }
13962
13963 static void ResetIntelliDraw(void)
13964 {
13965   int x, y;
13966
13967   for (x = 0; x < lev_fieldx; x++)
13968     for (y = 0; y < lev_fieldy; y++)
13969       IntelliDrawBuffer[x][y] = Tile[x][y];
13970
13971   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13972 }
13973
13974 static boolean draw_mode_hires = FALSE;
13975
13976 static boolean isHiresTileElement(int element)
13977 {
13978   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13979 }
13980
13981 static boolean isHiresDrawElement(int element)
13982 {
13983   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13984 }
13985
13986 static int numHiresTiles(int element)
13987 {
13988   if (IS_MM_WALL(element))
13989     return get_number_of_bits(MM_WALL_BITS(element));
13990
13991   return 1;
13992 }
13993
13994 static void SetDrawModeHiRes(int element)
13995 {
13996   draw_mode_hires =
13997     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13998      isHiresDrawElement(element));
13999 }
14000
14001 static boolean getDrawModeHiRes(void)
14002 {
14003   return draw_mode_hires;
14004 }
14005
14006 static int getLoResScreenPos(int pos)
14007 {
14008   return (getDrawModeHiRes() ? pos / 2 : pos);
14009 }
14010
14011 static int getLoResScreenMod(int pos)
14012 {
14013   return (getDrawModeHiRes() ? pos % 2 : 0);
14014 }
14015
14016 static void SetElementExt(int x, int y, int dx, int dy, int element,
14017                           boolean change_level, int button)
14018 {
14019   if (element < 0)
14020     SetElementSimple(x, y, Tile[x][y], change_level);
14021   else if (GetKeyModState() & KMOD_Shift)
14022     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
14023   else
14024     SetElementSimpleExt(x, y, dx, dy, element, change_level);
14025 }
14026
14027 static void SetElement(int x, int y, int element)
14028 {
14029   SetElementExt(x, y, 0, 0, element, TRUE, -1);
14030 }
14031
14032 static void SetElementButton(int x, int y, int dx, int dy, int element,
14033                              int button)
14034 {
14035   SetElementExt(x, y, dx, dy, element, TRUE, button);
14036 }
14037
14038 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
14039 {
14040   int lx = getLoResScreenPos(sx2) + level_xpos;
14041   int ly = getLoResScreenPos(sy2) + level_ypos;
14042   int dx = getLoResScreenMod(sx2);
14043   int dy = getLoResScreenMod(sy2);
14044
14045   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
14046 }
14047
14048 static void SetLevelElementHiRes(int lx2, int ly2, int element)
14049 {
14050   int lx = lx2 / 2;
14051   int ly = ly2 / 2;
14052   int dx = lx2 % 2;
14053   int dy = ly2 % 2;
14054
14055   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
14056 }
14057
14058 static int getLevelElementHiRes(int lx2, int ly2)
14059 {
14060   int lx = lx2 / 2;
14061   int ly = ly2 / 2;
14062   int dx = lx2 % 2;
14063   int dy = ly2 % 2;
14064   int element = Tile[lx][ly];
14065   unsigned int bitmask = (dx + 1) << (dy * 2);
14066
14067   if (IS_MM_WALL(element))
14068   {
14069     if (element & bitmask)
14070       return map_mm_wall_element(element);
14071     else
14072       return EL_EMPTY;
14073   }
14074
14075   return element;
14076 }
14077
14078 static void DrawLineElement(int x, int y, int element, boolean change_level)
14079 {
14080   SetElementHiRes(x, y, element, change_level);
14081 }
14082
14083 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
14084                      int element, boolean change_level)
14085 {
14086   int xsize = ABS(to_x - from_x);
14087   int ysize = ABS(to_y - from_y);
14088   int dx = (to_x < from_x ? -1 : +1);
14089   int dy = (to_y < from_y ? -1 : +1);
14090   int i;
14091
14092   if (from_y == to_y)                   // horizontal line
14093   {
14094     for (i = 0; i <= xsize; i++)
14095       DrawLineElement(from_x + i * dx, from_y, element, change_level);
14096   }
14097   else if (from_x == to_x)              // vertical line
14098   {
14099     for (i = 0; i <= ysize; i++)
14100       DrawLineElement(from_x, from_y + i * dy, element, change_level);
14101   }
14102   else                                  // diagonal line
14103   {
14104     if (ysize < xsize)                  // a < 1
14105     {
14106       float a = (float)ysize / (float)xsize;
14107
14108       for (i = 0; i <= xsize; i++)
14109       {
14110         int x = dx * i;
14111         int y = dy * (int)(a * i + 0.5);
14112
14113         DrawLineElement(from_x + x, from_y + y, element, change_level);
14114       }
14115     }
14116     else                                // a >= 1
14117     {
14118       float a = (float)xsize / (float)ysize;
14119
14120       for (i = 0; i <= ysize; i++)
14121       {
14122         int x = dx * (int)(a * i + 0.5);
14123         int y = dy * i;
14124
14125         DrawLineElement(from_x + x, from_y + y, element, change_level);
14126       }
14127     }
14128   }
14129 }
14130
14131 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
14132                     int element, boolean change_level)
14133 {
14134   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
14135   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
14136   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
14137   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
14138 }
14139
14140 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
14141                           int element, boolean change_level)
14142 {
14143   int y;
14144
14145   if (from_y > to_y)
14146     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
14147
14148   for (y = from_y; y <= to_y; y++)
14149     DrawLine(from_x, y, to_x, y, element, change_level);
14150 }
14151
14152 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
14153                        int element, boolean change_level)
14154 {
14155   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
14156   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
14157   int len_x = ABS(to_x - from_x);
14158   int len_y = ABS(to_y - from_y);
14159   int radius, x, y;
14160
14161   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
14162
14163   // not optimal (some points get drawn twice) but simple,
14164   // and fast enough for the few points we are drawing
14165
14166   for (x = 0; x <= radius; x++)
14167   {
14168     int sx, sy, sx2, sy2, lx, ly;
14169
14170     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
14171
14172     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14173     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14174     sx = getLoResScreenPos(sx2);
14175     sy = getLoResScreenPos(sy2);
14176     lx = sx + level_xpos;
14177     ly = sy + level_ypos;
14178
14179     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14180       DrawLineElement(sx2, sy2, element, change_level);
14181   }
14182
14183   for (y = 0; y <= radius; y++)
14184   {
14185     int sx, sy, sx2, sy2, lx, ly;
14186
14187     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14188
14189     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14190     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14191     sx = getLoResScreenPos(sx2);
14192     sy = getLoResScreenPos(sy2);
14193     lx = sx + level_xpos;
14194     ly = sy + level_ypos;
14195
14196     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14197       DrawLineElement(sx2, sy2, element, change_level);
14198   }
14199 }
14200
14201 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14202                     int element, boolean change_level)
14203 {
14204   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14205   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14206
14207   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14208 }
14209
14210 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14211
14212 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14213 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14214                        int element, boolean change_level)
14215 {
14216   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14217   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14218   int mirror_to_x2 = from_x - (to_x2 - from_x);
14219   int mirror_to_y2 = from_y - (to_y2 - from_y);
14220
14221   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14222   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14223   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14224   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14225 }
14226 #endif
14227
14228 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14229 {
14230   int from_sx, from_sy;
14231   int to_sx, to_sy;
14232
14233   if (from_x > to_x)
14234     swap_numbers(&from_x, &to_x);
14235
14236   if (from_y > to_y)
14237     swap_numbers(&from_y, &to_y);
14238
14239   from_sx = SX + from_x * ed_tilesize;
14240   from_sy = SY + from_y * ed_tilesize;
14241   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14242   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14243
14244   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14245   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14246   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14247   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14248
14249   if (from_x == to_x && from_y == to_y)
14250     MarkTileDirty(from_x/2, from_y/2);
14251   else
14252     redraw_mask |= REDRAW_FIELD;
14253 }
14254
14255 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14256                         int element, boolean change_level)
14257 {
14258   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14259 }
14260
14261 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14262                        int element, boolean change_level)
14263 {
14264   if (element == -1 || change_level)
14265     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14266   else
14267     DrawAreaBorder(from_x, from_y, to_x, to_y);
14268 }
14269
14270 // values for CopyBrushExt()
14271 #define CB_AREA_TO_BRUSH                0
14272 #define CB_BRUSH_TO_CURSOR              1
14273 #define CB_BRUSH_TO_LEVEL               2
14274 #define CB_DELETE_OLD_CURSOR            3
14275 #define CB_DUMP_BRUSH                   4
14276 #define CB_DUMP_BRUSH_SMALL             5
14277 #define CB_CLIPBOARD_TO_BRUSH           6
14278 #define CB_BRUSH_TO_CLIPBOARD           7
14279 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14280 #define CB_UPDATE_BRUSH_POSITION        9
14281 #define CB_FLIP_BRUSH_X                 10
14282 #define CB_FLIP_BRUSH_Y                 11
14283 #define CB_FLIP_BRUSH_XY                12
14284
14285 #define MAX_CB_PART_SIZE        10
14286 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14287 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14288 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14289                                  MAX_CB_NUM_LINES *     \
14290                                  MAX_CB_PART_SIZE)
14291
14292 static int getFlippedTileExt(int map[], int element)
14293 {
14294   int i;
14295
14296   for (i = 0; map[i] != -1; i++)
14297     if (map[i] == element)
14298       return map[i ^ 1];        // get flipped element by flipping LSB of index
14299
14300   return element;
14301 }
14302
14303 static int getFlippedTileX(int element)
14304 {
14305   int map[] =
14306   {
14307     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14308     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14309     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14310     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14311     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14312     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14313     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14314     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14315     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14316     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14317     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14318     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14319     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14320     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14321     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14322     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14323     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14324     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14325     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14326     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14327     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14328     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14329     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14330     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14331     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14332     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14333     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14334     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14335     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14336     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14337
14338     -1
14339   };
14340
14341   return getFlippedTileExt(map, element);
14342 }
14343
14344 static int getFlippedTileY(int element)
14345 {
14346   int map[] =
14347   {
14348     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14349     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14350     EL_BUG_UP,                          EL_BUG_DOWN,
14351     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14352     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14353     EL_ARROW_UP,                        EL_ARROW_DOWN,
14354     EL_MOLE_UP,                         EL_MOLE_DOWN,
14355     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14356     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14357     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14358     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14359     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14360     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14361     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14362     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14363     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14364     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14365     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14366     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14367     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14368     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14369     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14370     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14371     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14372
14373     -1
14374   };
14375
14376   return getFlippedTileExt(map, element);
14377 }
14378
14379 static int getFlippedTileXY(int element)
14380 {
14381   int map[] =
14382   {
14383     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14384     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14385     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14386     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14387     EL_BUG_LEFT,                        EL_BUG_UP,
14388     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14389     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14390     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14391     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14392     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14393     EL_ARROW_LEFT,                      EL_ARROW_UP,
14394     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14395     EL_MOLE_LEFT,                       EL_MOLE_UP,
14396     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14397     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14398     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14399     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14400     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14401     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14402     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14403     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14404     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14405     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14406     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14407     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14408     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14409     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14410     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14411     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14412     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14413     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14414     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14415     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14416     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14417     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14418     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14419     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14420     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14421     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14422     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14423     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14424     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14425
14426     -1
14427   };
14428
14429   return getFlippedTileExt(map, element);
14430 }
14431
14432 static int getFlippedTile(int element, int mode)
14433 {
14434   if (IS_MM_ELEMENT(element))
14435   {
14436     // get MM game element
14437     element = map_element_RND_to_MM(element);
14438
14439     // get flipped game element
14440     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14441                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14442                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14443                element);
14444
14445     // get RND game element again
14446     element = map_element_MM_to_RND(element);
14447   }
14448   else
14449   {
14450     // get flipped game element
14451     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14452                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14453                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14454                element);
14455   }
14456
14457   return element;
14458 }
14459
14460 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14461 {
14462   // flip tiles
14463   short tile1_flipped = getFlippedTile(*tile1, mode);
14464   short tile2_flipped = getFlippedTile(*tile2, mode);
14465
14466   // swap tiles
14467   *tile1 = tile2_flipped;
14468   *tile2 = tile1_flipped;
14469 }
14470
14471 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14472 {
14473   DrawLineElement(sx, sy, element, change_level);
14474 }
14475
14476 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14477                          int button, int mode)
14478 {
14479   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14480   static int brush_width, brush_height;
14481   static int last_cursor_x = -1, last_cursor_y = -1;
14482   static boolean delete_old_brush = FALSE;
14483   int new_element = BUTTON_ELEMENT(button);
14484   int x, y;
14485
14486   if (mode == CB_DUMP_BRUSH ||
14487       mode == CB_DUMP_BRUSH_SMALL ||
14488       mode == CB_BRUSH_TO_CLIPBOARD ||
14489       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14490   {
14491     if (edit_mode != ED_MODE_DRAWING)
14492       return;
14493
14494     char part[MAX_CB_PART_SIZE + 1] = "";
14495     char text[MAX_CB_TEXT_SIZE + 1] = "";
14496     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14497     int height = (draw_with_brush ? brush_height : lev_fieldy);
14498     char *format = "%s%03d";
14499
14500     for (y = 0; y < height; y++)
14501       for (x = 0; x < width; x++)
14502         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14503           format = "%s%04d";
14504
14505     for (y = 0; y < height; y++)
14506     {
14507       for (x = 0; x < width; x++)
14508       {
14509         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14510         char *prefix = (mode == CB_DUMP_BRUSH ||
14511                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14512
14513         if (element >= NUM_FILE_ELEMENTS)
14514           element = EL_UNKNOWN;
14515
14516         // copy brush to level sketch text buffer for the R'n'D forum:
14517         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14518         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14519         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14520         strcat(text, part);
14521       }
14522
14523       strcat(text, "\n");
14524     }
14525
14526     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14527         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14528       SDL_SetClipboardText(text);
14529     else
14530       Print("%s", text);        // print brush data to console and log file
14531
14532     return;
14533   }
14534
14535   if (mode == CB_CLIPBOARD_TO_BRUSH)
14536   {
14537     if (edit_mode != ED_MODE_DRAWING)
14538       return;
14539
14540     if (!SDL_HasClipboardText())
14541     {
14542       Request("Clipboard is empty!", REQ_CONFIRM);
14543
14544       return;
14545     }
14546
14547     boolean copy_to_brush = (draw_with_brush ||
14548                              drawing_function == GADGET_ID_GRAB_BRUSH);
14549
14550     // this will delete the old brush, if already drawing with a brush
14551     if (copy_to_brush)
14552       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14553
14554     // initialization is required for "odd" (incomplete) clipboard content
14555     for (x = 0; x < MAX_LEV_FIELDX; x++)
14556       for (y = 0; y < MAX_LEV_FIELDY; y++)
14557         brush_buffer[x][y] = EL_EMPTY;
14558
14559     brush_width  = 0;
14560     brush_height = 0;
14561     x = 0;
14562     y = 0;
14563
14564     char *clipboard_text = SDL_GetClipboardText();
14565     char *ptr = clipboard_text;
14566     boolean allow_new_row = FALSE;
14567     boolean stop = FALSE;
14568
14569     while (*ptr && !stop)
14570     {
14571       boolean prefix_found = FALSE;
14572       boolean start_new_row = FALSE;
14573
14574       // level sketch element number prefixes (may be multi-byte characters)
14575       char *prefix_list[] = { "`", "¸" };
14576       int i;
14577
14578       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14579       {
14580         char *prefix = prefix_list[i];
14581
14582         // check if string is large enough for prefix
14583         if (strlen(ptr) < strlen(prefix))
14584         {
14585           stop = TRUE;
14586
14587           break;
14588         }
14589
14590         // check if string starts with prefix
14591         if (strPrefix(ptr, prefix))
14592         {
14593           ptr += strlen(prefix);
14594
14595           prefix_found = TRUE;
14596
14597           break;
14598         }
14599       }
14600
14601       // check if prefix found and followed by (at least) three digits
14602       if (prefix_found &&
14603           strlen(ptr) >= 3 &&
14604           ptr[0] >= '0' && ptr[0] <= '9' &&
14605           ptr[1] >= '0' && ptr[1] <= '9' &&
14606           ptr[2] >= '0' && ptr[2] <= '9')
14607       {
14608         int element = ((ptr[0] - '0') * 100 +
14609                        (ptr[1] - '0') * 10 +
14610                        (ptr[2] - '0'));
14611
14612         ptr += 3;
14613
14614         // level sketch element number might consist of four digits
14615         if (ptr[0] >= '0' && ptr[0] <= '9')
14616         {
14617           element = element * 10 + (ptr[0] - '0');
14618           ptr++;
14619         }
14620
14621         // remap some (historic, now obsolete) elements
14622         element = getMappedElement(element);
14623
14624         if (element >= NUM_FILE_ELEMENTS)
14625           element = EL_UNKNOWN;
14626
14627         brush_buffer[x][y] = element;
14628
14629         brush_width  = MAX(x + 1, brush_width);
14630         brush_height = MAX(y + 1, brush_height);
14631
14632         x++;
14633
14634         if (x >= MAX_LEV_FIELDX)
14635           start_new_row = TRUE;
14636
14637         allow_new_row = TRUE;
14638       }
14639       else
14640       {
14641         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14642           start_new_row = TRUE;
14643
14644         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14645       }
14646
14647       if (start_new_row)
14648       {
14649         x = 0;
14650         y++;
14651
14652         if (y >= MAX_LEV_FIELDY)
14653           stop = TRUE;
14654
14655         allow_new_row = FALSE;
14656       }
14657     }
14658
14659     SDL_free(clipboard_text);
14660
14661     if (brush_width == 0 || brush_height == 0)
14662     {
14663       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14664
14665       return;
14666     }
14667
14668     if (copy_to_brush)
14669     {
14670       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14671       int mx, my;
14672
14673       SDL_GetMouseState(&mx, &my);
14674
14675       // if inside drawing area, activate and draw brush at last mouse position
14676       if (mx >= gi->x && mx < gi->x + gi->width &&
14677           my >= gi->y && my < gi->y + gi->height)
14678         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14679
14680       draw_with_brush = TRUE;
14681     }
14682     else
14683     {
14684       char request[100];
14685
14686       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14687               brush_width, brush_height);
14688
14689       if (!Request(request, REQ_ASK))
14690         return;
14691
14692       for (x = 0; x < MAX_LEV_FIELDX; x++)
14693         for (y = 0; y < MAX_LEV_FIELDY; y++)
14694           Tile[x][y] = brush_buffer[x][y];
14695
14696       lev_fieldx = level.fieldx = brush_width;
14697       lev_fieldy = level.fieldy = brush_height;
14698
14699       boolean use_bd_engine = TRUE;
14700       boolean use_em_engine = TRUE;
14701       boolean use_sp_engine = TRUE;
14702       boolean use_mm_engine = TRUE;
14703
14704       for (x = 0; x < MAX_LEV_FIELDX; x++)
14705       {
14706         for (y = 0; y < MAX_LEV_FIELDY; y++)
14707         {
14708           int element = Tile[x][y];
14709
14710           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14711             use_bd_engine = FALSE;
14712
14713           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14714             use_em_engine = FALSE;
14715
14716           if (!IS_SP_ELEMENT(element))
14717             use_sp_engine = FALSE;
14718
14719           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14720             use_mm_engine = FALSE;
14721         }
14722       }
14723
14724       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14725                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14726                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14727                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14728                                 GAME_ENGINE_TYPE_RND);
14729
14730       // update element selection list
14731       ReinitializeElementList();
14732       ModifyEditorElementList();
14733
14734       SetBorderElement();
14735
14736       DrawEditModeWindow();
14737       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14738     }
14739
14740     return;
14741   }
14742
14743   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14744     return;
14745
14746   if (mode == CB_AREA_TO_BRUSH)
14747   {
14748     int from_lx, from_ly;
14749
14750     if (from_x > to_x)
14751       swap_numbers(&from_x, &to_x);
14752
14753     if (from_y > to_y)
14754       swap_numbers(&from_y, &to_y);
14755
14756     brush_width = to_x - from_x + 1;
14757     brush_height = to_y - from_y + 1;
14758
14759     from_lx = from_x + level_xpos;
14760     from_ly = from_y + level_ypos;
14761
14762     for (y = 0; y < brush_height; y++)
14763     {
14764       for (x = 0; x < brush_width; x++)
14765       {
14766         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14767
14768         if (button != 1)
14769           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14770       }
14771     }
14772
14773     if (button != 1)
14774       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14775
14776     delete_old_brush = FALSE;
14777   }
14778   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14779            mode == CB_BRUSH_TO_LEVEL)
14780   {
14781     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14782     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14783     int cursor_from_x = cursor_x - brush_width / 2;
14784     int cursor_from_y = cursor_y - brush_height / 2;
14785     int border_from_x = cursor_x, border_from_y = cursor_y;
14786     int border_to_x = cursor_x, border_to_y = cursor_y;
14787
14788     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14789       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14790
14791     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14792         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14793     {
14794       delete_old_brush = FALSE;
14795
14796       return;
14797     }
14798
14799     for (y = 0; y < brush_height; y++)
14800     {
14801       for (x = 0; x < brush_width; x++)
14802       {
14803         int sx = cursor_from_x + x;
14804         int sy = cursor_from_y + y;
14805         int lx = sx + level_xpos;
14806         int ly = sy + level_ypos;
14807         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14808         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14809                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14810                        brush_buffer[x][y] : new_element);
14811
14812         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14813         {
14814           if (sx < border_from_x)
14815             border_from_x = sx;
14816           else if (sx > border_to_x)
14817             border_to_x = sx;
14818           if (sy < border_from_y)
14819             border_from_y = sy;
14820           else if (sy > border_to_y)
14821             border_to_y = sy;
14822
14823           DrawBrushElement(sx, sy, element, change_level);
14824         }
14825       }
14826     }
14827
14828     if (mode != CB_DELETE_OLD_CURSOR)
14829       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14830
14831     last_cursor_x = cursor_x;
14832     last_cursor_y = cursor_y;
14833
14834     delete_old_brush = TRUE;
14835   }
14836   else if (mode == CB_FLIP_BRUSH_X)
14837   {
14838     for (y = 0; y < brush_height; y++)
14839       for (x = 0; x < (brush_width + 1) / 2; x++)
14840         SwapFlippedTiles(&brush_buffer[x][y],
14841                          &brush_buffer[brush_width - x - 1][y], mode);
14842
14843     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14844   }
14845   else if (mode == CB_FLIP_BRUSH_Y)
14846   {
14847     for (y = 0; y < (brush_height + 1) / 2; y++)
14848       for (x = 0; x < brush_width; x++)
14849         SwapFlippedTiles(&brush_buffer[x][y],
14850                          &brush_buffer[x][brush_height - y - 1], mode);
14851
14852     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14853   }
14854   else if (mode == CB_FLIP_BRUSH_XY)
14855   {
14856     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14857
14858     for (y = 0; y < MAX(brush_width, brush_height); y++)
14859       for (x = 0; x <= y; x++)
14860         SwapFlippedTiles(&brush_buffer[x][y],
14861                          &brush_buffer[y][x], mode);
14862
14863     swap_numbers(&brush_width, &brush_height);
14864
14865     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14866   }
14867
14868   if (mode == CB_UPDATE_BRUSH_POSITION)
14869   {
14870     last_cursor_x = from_x;
14871     last_cursor_y = from_y;
14872   }
14873 }
14874
14875 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14876                             int button)
14877 {
14878   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14879 }
14880
14881 static void CopyBrushToLevel(int x, int y, int button)
14882 {
14883   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14884 }
14885
14886 static void CopyBrushToCursor(int x, int y)
14887 {
14888   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14889 }
14890
14891 static void UpdateBrushPosition(int x, int y)
14892 {
14893   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14894 }
14895
14896 static void DeleteBrushFromCursor(void)
14897 {
14898   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14899 }
14900
14901 static void FlipBrushX(void)
14902 {
14903   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14904 }
14905
14906 static void FlipBrushY(void)
14907 {
14908   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14909 }
14910
14911 static void RotateBrush(void)
14912 {
14913   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14914   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14915 }
14916
14917 void DumpBrush(void)
14918 {
14919   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14920 }
14921
14922 void DumpBrush_Small(void)
14923 {
14924   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14925 }
14926
14927 void CopyClipboardToBrush(void)
14928 {
14929   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14930 }
14931
14932 void CopyBrushToClipboard(void)
14933 {
14934   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14935 }
14936
14937 void CopyBrushToClipboard_Small(void)
14938 {
14939   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14940 }
14941
14942 void UndoLevelEditorOperation(void)
14943 {
14944   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14945 }
14946
14947 void RedoLevelEditorOperation(void)
14948 {
14949   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14950 }
14951
14952 static void FloodFill(int from_x, int from_y, int fill_element)
14953 {
14954   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14955 }
14956
14957 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14958 {
14959   int from_x = from_sx2 + 2 * level_xpos;
14960   int from_y = from_sy2 + 2 * level_ypos;
14961   int max_fillx = lev_fieldx * 2;
14962   int max_filly = lev_fieldy * 2;
14963   short Fill[max_fillx][max_filly];
14964   int x, y;
14965
14966   for (x = 0; x < max_fillx; x++)
14967     for (y = 0; y < max_filly; y++)
14968       Fill[x][y] = getLevelElementHiRes(x, y);
14969
14970   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14971                     Fill, max_fillx, max_filly);
14972
14973   for (x = 0; x < max_fillx; x++)
14974     for (y = 0; y < max_filly; y++)
14975       if (Fill[x][y] == fill_element)
14976         SetLevelElementHiRes(x, y, Fill[x][y]);
14977 }
14978
14979 // values for DrawLevelText() modes
14980 #define TEXT_INIT               0
14981 #define TEXT_SETCURSOR          1
14982 #define TEXT_WRITECHAR          2
14983 #define TEXT_BACKSPACE          3
14984 #define TEXT_NEWLINE            4
14985 #define TEXT_END                5
14986 #define TEXT_QUERY_TYPING       6
14987
14988 static int DrawLevelText(int sx, int sy, char letter, int mode)
14989 {
14990   static short delete_buffer[MAX_LEV_FIELDX];
14991   static int start_sx;
14992   static int last_sx, last_sy;
14993   static boolean typing = FALSE;
14994   int letter_element;
14995   int lx = 0, ly = 0;
14996
14997   // map lower case letters to upper case and convert special characters
14998   if (letter >= 'a' && letter <= 'z')
14999     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
15000   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
15001     letter_element = EL_CHAR_AUMLAUT;
15002   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
15003     letter_element = EL_CHAR_OUMLAUT;
15004   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
15005     letter_element = EL_CHAR_UUMLAUT;
15006   else if (letter == '^')
15007     letter_element = EL_CHAR_COPYRIGHT;
15008   else
15009     letter_element = EL_CHAR_ASCII0 + letter;
15010
15011   if (mode != TEXT_INIT)
15012   {
15013     if (!typing)
15014       return FALSE;
15015
15016     if (mode != TEXT_SETCURSOR)
15017     {
15018       sx = last_sx;
15019       sy = last_sy;
15020     }
15021
15022     lx = last_sx + level_xpos;
15023     ly = last_sy + level_ypos;
15024   }
15025
15026   switch (mode)
15027   {
15028     case TEXT_INIT:
15029       if (typing)
15030         DrawLevelText(0, 0, 0, TEXT_END);
15031
15032       typing = TRUE;
15033       start_sx = sx;
15034       last_sx = sx;
15035       last_sy = sy;
15036       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
15037       break;
15038
15039     case TEXT_SETCURSOR:
15040       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
15041       DrawAreaBorder(sx, sy, sx, sy);
15042       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
15043                      ed_tilesize, ed_tilesize);
15044       last_sx = sx;
15045       last_sy = sy;
15046       break;
15047
15048     case TEXT_WRITECHAR:
15049       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
15050       {
15051         if (new_element1 >= EL_STEEL_CHAR_START &&
15052             new_element1 <= EL_STEEL_CHAR_END)
15053           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
15054
15055         delete_buffer[sx - start_sx] = Tile[lx][ly];
15056         Tile[lx][ly] = letter_element;
15057
15058         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
15059           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
15060         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15061           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15062         else
15063           DrawLevelText(0, 0, 0, TEXT_END);
15064
15065         level.changed = TRUE;
15066       }
15067       break;
15068
15069     case TEXT_BACKSPACE:
15070       if (sx > start_sx)
15071       {
15072         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
15073         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
15074         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
15075       }
15076       break;
15077
15078     case TEXT_NEWLINE:
15079       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15080         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15081       else
15082         DrawLevelText(0, 0, 0, TEXT_END);
15083       break;
15084
15085     case TEXT_END:
15086       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15087       DrawEditorElement(sx, sy, Tile[lx][ly]);
15088       StopTextInput();
15089       typing = FALSE;
15090       break;
15091
15092     case TEXT_QUERY_TYPING:
15093       break;
15094
15095     default:
15096       break;
15097   }
15098
15099   return typing;
15100 }
15101
15102 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
15103                           int element, boolean change_level)
15104 {
15105   int lx = sx + level_xpos;
15106   int ly = sy + level_ypos;
15107
15108   if (element == -1)
15109     DrawEditorElement(sx, sy, Tile[lx][ly]);
15110   else
15111     DrawAreaBorder(sx, sy, sx, sy);
15112 }
15113
15114 static void CheckLevelBorderElement(boolean redraw_playfield)
15115 {
15116   int last_border_element = BorderElement;
15117
15118   SetBorderElement();
15119
15120   if (redraw_playfield && BorderElement != last_border_element)
15121     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15122 }
15123
15124 static void CopyLevelToUndoBuffer(int mode)
15125 {
15126   static boolean accumulated_undo = FALSE;
15127   boolean new_undo_buffer_position = TRUE;
15128   int x, y;
15129
15130   if (undo_buffer_steps == 0)
15131     accumulated_undo = FALSE;
15132
15133   switch (mode)
15134   {
15135     case UNDO_IMMEDIATE:
15136       accumulated_undo = FALSE;
15137       break;
15138
15139     case UNDO_ACCUMULATE:
15140       if (accumulated_undo)
15141         new_undo_buffer_position = FALSE;
15142       accumulated_undo = TRUE;
15143       break;
15144
15145     default:
15146       break;
15147   }
15148
15149   if (new_undo_buffer_position)
15150   {
15151     // advance position in undo buffer ring
15152     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
15153
15154     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
15155       undo_buffer_steps++;
15156   }
15157
15158   // always reset redo buffer when storing level change into undo buffer
15159   redo_buffer_steps = 0;
15160
15161   for (x = 0; x < lev_fieldx; x++)
15162     for (y = 0; y < lev_fieldy; y++)
15163       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
15164
15165   // check if drawing operation forces change of border style
15166   CheckLevelBorderElement(TRUE);
15167
15168   level.changed = TRUE;
15169 }
15170
15171 static void RandomPlacement(int new_element)
15172 {
15173   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
15174   int num_free_positions = 0;
15175   int num_percentage, num_elements;
15176   int x, y;
15177
15178   ResetIntelliDraw();
15179
15180   // determine number of free positions for randomly placing the new element
15181   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
15182   {
15183     free_position[x][y] =
15184       (random_placement_background_restricted ?
15185        Tile[x][y] == random_placement_background_element :
15186        Tile[x][y] != new_element);
15187
15188     if (free_position[x][y])
15189       num_free_positions++;
15190   }
15191
15192   // determine number of new elements to place there
15193   num_percentage = num_free_positions * random_placement_value / 100;
15194   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15195                   num_percentage : random_placement_value);
15196
15197   // if less free positions than elements to place, fill all these positions
15198   if (num_free_positions < num_elements)
15199   {
15200     for (x = 0; x < lev_fieldx; x++)
15201       for (y = 0; y < lev_fieldy; y++)
15202         if (free_position[x][y])
15203           SetElement(x, y, new_element);
15204   }
15205   else
15206   {
15207     while (num_elements > 0)
15208     {
15209       x = GetSimpleRandom(lev_fieldx);
15210       y = GetSimpleRandom(lev_fieldy);
15211
15212       // don't place element at the same position twice
15213       if (free_position[x][y])
15214       {
15215         free_position[x][y] = FALSE;
15216         SetElement(x, y, new_element);
15217         num_elements--;
15218       }
15219     }
15220   }
15221
15222   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15223   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15224 }
15225
15226 static void WrapLevel(int dx, int dy)
15227 {
15228   int wrap_dx = lev_fieldx - dx;
15229   int wrap_dy = lev_fieldy - dy;
15230   int x, y;
15231
15232   for (x = 0; x < lev_fieldx; x++)
15233     for (y = 0; y < lev_fieldy; y++)
15234       TileBackup[x][y] = Tile[x][y];
15235
15236   for (x = 0; x < lev_fieldx; x++)
15237     for (y = 0; y < lev_fieldy; y++)
15238       Tile[x][y] =
15239         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15240
15241   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15242   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15243 }
15244
15245 static void DrawAreaElementHighlight(boolean highlighted,
15246                                      boolean highlighted_similar)
15247 {
15248   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15249
15250   if (!highlighted)
15251     return;
15252
15253   int x, y;
15254
15255   for (x = 0; x < ed_fieldx; x++)
15256   {
15257     for (y = 0; y < ed_fieldy; y++)
15258     {
15259       boolean highlight = FALSE;
15260       int lx = x + level_xpos;
15261       int ly = y + level_ypos;
15262
15263       if (!IN_LEV_FIELD(lx, ly))
15264         continue;
15265
15266       // check if element is the same
15267       if (Tile[lx][ly] == new_element1)
15268         highlight = TRUE;
15269
15270       // check if element is similar
15271       if (highlighted_similar &&
15272           strEqual(element_info[Tile[lx][ly]].class_name,
15273                    element_info[new_element1].class_name))
15274         highlight = TRUE;
15275
15276       // check if element is matching MM style wall
15277       if (IS_MM_WALL(Tile[lx][ly]) &&
15278           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15279         highlight = TRUE;
15280
15281       if (!highlight)
15282         continue;
15283
15284       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15285       {
15286         int i;
15287
15288         for (i = 0; i < 4; i++)
15289         {
15290           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15291             continue;
15292
15293           int xx = x * 2 + (i % 2);
15294           int yy = y * 2 + (i / 2);
15295           int sx = SX + xx * ed_tilesize / 2;
15296           int sy = SY + yy * ed_tilesize / 2;
15297           int from_sx = sx;
15298           int from_sy = sy;
15299           int to_sx = sx + ed_tilesize / 2 - 1;
15300           int to_sy = sy + ed_tilesize / 2 - 1;
15301
15302           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15303           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15304           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15305           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15306         }
15307       }
15308       else
15309       {
15310         int sx = SX + x * ed_tilesize;
15311         int sy = SY + y * ed_tilesize;
15312         int from_sx = sx;
15313         int from_sy = sy;
15314         int to_sx = sx + ed_tilesize - 1;
15315         int to_sy = sy + ed_tilesize - 1;
15316
15317         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15318         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15319         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15320         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15321       }
15322     }
15323   }
15324 }
15325
15326 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15327 {
15328   char *template_filename_old = getLocalLevelTemplateFilename();
15329   char *template_filename_new =
15330     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15331
15332   if (copyFile(template_filename_old, template_filename_new) != 0)
15333     Request("Cannot copy level template!", REQ_CONFIRM);
15334
15335   free(template_filename_new);
15336 }
15337
15338 static void HandleDrawingAreas(struct GadgetInfo *gi)
15339 {
15340   static boolean started_inside_drawing_area = FALSE;
15341   static int last_sx = -1;
15342   static int last_sy = -1;
15343   static int last_sx2 = -1;
15344   static int last_sy2 = -1;
15345   int id = gi->custom_id;
15346   int type_id = gi->custom_type_id;
15347   boolean button_press_event;
15348   boolean button_release_event;
15349   boolean inside_drawing_area = !gi->event.off_borders;
15350   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15351   int actual_drawing_function;
15352   int button = gi->event.button;
15353   int new_element = BUTTON_ELEMENT(button);
15354   int sx = gi->event.x, sy = gi->event.y;
15355   int min_sx = 0, min_sy = 0;
15356   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15357   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15358   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15359   int sx2 = gi->event.mx / mini_item_xsize;
15360   int sy2 = gi->event.my / mini_item_ysize;
15361   int dx = sx2 % 2;
15362   int dy = sy2 % 2;
15363   int lx = 0, ly = 0;
15364   int x, y;
15365
15366   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15367   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15368
15369   // make sure to stay inside drawing area boundaries
15370   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15371   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15372
15373   if (draw_level)
15374   {
15375     int min_lx = 0, min_ly = 0;
15376     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15377
15378     // get positions inside level field
15379     lx = sx + level_xpos;
15380     ly = sy + level_ypos;
15381
15382     if (!IN_LEV_FIELD(lx, ly))
15383       inside_drawing_area = FALSE;
15384
15385     // make sure to stay inside level field boundaries
15386     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15387     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15388
15389     // correct drawing area positions accordingly
15390     sx = lx - level_xpos;
15391     sy = ly - level_ypos;
15392   }
15393
15394   // also correct MM wall-sized (double) drawing area positions accordingly
15395   if (sx2 / 2 < sx || sx2 / 2 > sx)
15396   {
15397     dx = (sx2 / 2 < sx ? 0 : 1);
15398     sx2 = sx * 2 + dx;
15399   }
15400   if (sy2 / 2 < sy || sy2 / 2 > sy)
15401   {
15402     dy = (sy2 / 2 < sy ? 0 : 1);
15403     sy2 = sy * 2 + dy;
15404   }
15405
15406   if (!button_press_event && !button_release_event)
15407   {
15408     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15409     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15410                              isHiresTileElement(old_element) &&
15411                              isHiresDrawElement(new_element));
15412
15413     // prevent handling events for every pixel position when moving mouse
15414     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15415         (sx2 == last_sx2 && sy2 == last_sy2))
15416       return;
15417   }
15418
15419   last_sx = sx;
15420   last_sy = sy;
15421   last_sx2 = sx2;
15422   last_sy2 = sy2;
15423
15424   if (button_press_event)
15425     started_inside_drawing_area = inside_drawing_area;
15426
15427   if (!started_inside_drawing_area)
15428     return;
15429
15430   if (!IS_VALID_BUTTON(button))
15431     return;
15432
15433   // handle info callback for each invocation of action callback
15434   gi->callback_info(gi);
15435
15436   // automatically switch to 'single item' drawing mode, if needed
15437   actual_drawing_function =
15438     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15439      drawing_function : GADGET_ID_SINGLE_ITEMS);
15440
15441   // clicking into drawing area with pressed Control key picks element
15442   if (GetKeyModState() & KMOD_Control)
15443   {
15444     last_drawing_function = drawing_function;
15445     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15446   }
15447
15448   if (GetKeyModState() & KMOD_Shift)
15449   {
15450     if (button_press_event || button_release_event)
15451       ResetIntelliDraw();
15452   }
15453
15454   SetDrawModeHiRes(-1);         // reset to normal draw mode
15455
15456   switch (actual_drawing_function)
15457   {
15458     case GADGET_ID_SINGLE_ITEMS:
15459       if (draw_level)
15460       {
15461         if (button_release_event)
15462         {
15463           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15464
15465           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15466               !inside_drawing_area)
15467             DeleteBrushFromCursor();
15468
15469           break;
15470         }
15471
15472         if (draw_with_brush)
15473         {
15474           CopyBrushToLevel(sx, sy, button);
15475         }
15476         else
15477         {
15478           SetDrawModeHiRes(new_element);
15479
15480           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15481           {
15482             // remove player at old position
15483             for (y = 0; y < lev_fieldy; y++)
15484             {
15485               for (x = 0; x < lev_fieldx; x++)
15486               {
15487                 int old_element = Tile[x][y];
15488
15489                 if (IS_PLAYER_ELEMENT(old_element) &&
15490                     IS_PLAYER_ELEMENT(new_element))
15491                 {
15492                   int replaced_with_element =
15493                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15494                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15495
15496                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15497                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15498
15499                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15500                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15501
15502                      new_element >= EL_PLAYER_1 &&
15503                      new_element <= EL_PLAYER_4 &&
15504                      new_element == old_element ? EL_EMPTY :
15505
15506                      old_element);
15507
15508                   SetElement(x, y, replaced_with_element);
15509                 }
15510                 else if (IS_MM_MCDUFFIN(old_element) &&
15511                          IS_MM_MCDUFFIN(new_element))
15512                 {
15513                   // remove McDuffin at old position
15514                   SetElement(x, y, EL_EMPTY);
15515                 }
15516               }
15517             }
15518           }
15519
15520           SetElementButton(lx, ly, dx, dy, new_element, button);
15521         }
15522       }
15523       else if (!button_release_event)
15524       {
15525         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15526
15527         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15528           DrawMiniGraphicExt(drawto,
15529                              gi->x + sx * MINI_TILEX,
15530                              gi->y + sy * MINI_TILEY,
15531                              el2edimg(new_element));
15532         else
15533           DrawFixedGraphicExt(drawto,
15534                               gi->x + sx * TILEX,
15535                               gi->y + sy * TILEY,
15536                               el2edimg(new_element), 0);
15537
15538         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15539           new_element = GFX_ELEMENT(new_element);
15540
15541         drawingarea_info[type_id].value[pos] = new_element;
15542
15543         CopyElementPropertiesToGame(properties_element);
15544
15545         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15546         {
15547           UpdateCustomElementGraphicGadgets();
15548
15549           FrameCounter = 0;     // restart animation frame counter
15550         }
15551       }
15552       break;
15553
15554     case GADGET_ID_CONNECTED_ITEMS:
15555       {
15556         static int last_sx = -1;
15557         static int last_sy = -1;
15558
15559         if (button_release_event)
15560           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15561
15562         SetDrawModeHiRes(new_element);
15563
15564         if (getDrawModeHiRes())
15565         {
15566           sx = sx2;
15567           sy = sy2;
15568         }
15569
15570         if (!button_press_event)
15571           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15572
15573         last_sx = sx;
15574         last_sy = sy;
15575       }
15576       break;
15577
15578     case GADGET_ID_LINE:
15579     case GADGET_ID_ARC:
15580     case GADGET_ID_RECTANGLE:
15581     case GADGET_ID_FILLED_BOX:
15582       SetDrawModeHiRes(new_element);
15583
15584       if (getDrawModeHiRes())
15585       {
15586         sx = sx2;
15587         sy = sy2;
15588       }
15589       // FALLTHROUGH
15590     case GADGET_ID_GRAB_BRUSH:
15591     case GADGET_ID_TEXT:
15592       {
15593         static int last_sx = -1;
15594         static int last_sy = -1;
15595         static int start_sx = -1;
15596         static int start_sy = -1;
15597         void (*draw_func)(int, int, int, int, int, boolean);
15598
15599         if (drawing_function == GADGET_ID_LINE)
15600           draw_func = DrawLine;
15601         else if (drawing_function == GADGET_ID_ARC)
15602           draw_func = DrawArc;
15603         else if (drawing_function == GADGET_ID_RECTANGLE)
15604           draw_func = DrawBox;
15605         else if (drawing_function == GADGET_ID_FILLED_BOX)
15606           draw_func = DrawFilledBox;
15607         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15608           draw_func = SelectArea;
15609         else // (drawing_function == GADGET_ID_TEXT)
15610           draw_func = SetTextCursor;
15611
15612         if (button_press_event)
15613         {
15614           draw_func(sx, sy, sx, sy, new_element, FALSE);
15615           start_sx = last_sx = sx;
15616           start_sy = last_sy = sy;
15617
15618           if (drawing_function == GADGET_ID_TEXT)
15619             DrawLevelText(0, 0, 0, TEXT_END);
15620         }
15621         else if (button_release_event)
15622         {
15623           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15624           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15625           {
15626             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15627             CopyBrushToCursor(sx, sy);
15628             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15629                           MB_LEFTBUTTON);
15630             draw_with_brush = TRUE;
15631           }
15632           else if (drawing_function == GADGET_ID_TEXT)
15633             DrawLevelText(sx, sy, 0, TEXT_INIT);
15634           else
15635             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15636         }
15637         else if (last_sx != sx || last_sy != sy)
15638         {
15639           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15640           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15641             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15642           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15643           last_sx = sx;
15644           last_sy = sy;
15645         }
15646       }
15647       break;
15648
15649     case GADGET_ID_FLOOD_FILL:
15650       if (button_press_event && Tile[lx][ly] != new_element)
15651       {
15652         if (IS_MM_WALL_EDITOR(new_element))
15653           FloodFillWall_MM(sx2, sy2, new_element);
15654         else
15655           FloodFill(lx, ly, new_element);
15656
15657         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15658         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15659       }
15660       break;
15661
15662     case GADGET_ID_PICK_ELEMENT:
15663       if (button_release_event)
15664         ClickOnGadget(level_editor_gadget[last_drawing_function],
15665                       MB_LEFTBUTTON);
15666       else if (draw_level)
15667         PickDrawingElement(button, Tile[lx][ly]);
15668       else
15669       {
15670         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15671
15672         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15673       }
15674
15675     default:
15676       break;
15677   }
15678
15679   // do not mark level as modified for certain non-level-changing gadgets
15680   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15681        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15682       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15683       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15684     return;
15685
15686   level.changed = TRUE;
15687 }
15688
15689 static void HandleCounterButtons(struct GadgetInfo *gi)
15690 {
15691   int gadget_id = gi->custom_id;
15692   int counter_id = gi->custom_type_id;
15693   int button = gi->event.button;
15694   int *counter_value = counterbutton_info[counter_id].value;
15695   int step = BUTTON_STEPSIZE(button) *
15696     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15697
15698   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15699   {
15700     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15701     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15702     boolean level_changed = LevelChanged();
15703
15704     if ((level_changed && pressed) || (!level_changed && released))
15705       return;
15706
15707     if (level_changed && !Request("Level has changed! Discard changes?",
15708                                   REQ_ASK))
15709     {
15710       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15711         ModifyEditorCounterValue(counter_id, *counter_value);
15712
15713       return;
15714     }
15715   }
15716
15717   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15718     *counter_value = gi->textinput.number_value;
15719   else
15720     ModifyEditorCounterValue(counter_id, *counter_value + step);
15721
15722   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15723   {
15724     int last_game_engine_type = level.game_engine_type;
15725
15726     LoadLevel(level_nr);
15727     LoadScore(level_nr);
15728
15729     SaveLevelSetup_SeriesInfo();
15730
15731     TapeErase();
15732
15733     ResetUndoBuffer();
15734     DrawEditModeWindow();
15735
15736     if (level.game_engine_type != last_game_engine_type)
15737     {
15738       // update element selection list
15739       ReinitializeElementList();
15740       ModifyEditorElementList();
15741     }
15742
15743     return;
15744   }
15745
15746   switch (counter_id)
15747   {
15748     case ED_COUNTER_ID_YAMYAM_CONTENT:
15749       DrawYamYamContentAreas();
15750       break;
15751
15752     case ED_COUNTER_ID_BALL_CONTENT:
15753       DrawMagicBallContentAreas();
15754       break;
15755
15756     case ED_COUNTER_ID_ANDROID_CONTENT:
15757       DrawAndroidElementArea();
15758       break;
15759
15760     case ED_COUNTER_ID_GROUP_CONTENT:
15761       DrawGroupElementArea();
15762       CopyGroupElementPropertiesToGame(properties_element);
15763       break;
15764
15765     case ED_COUNTER_ID_INVENTORY_SIZE:
15766       DrawPlayerInitialInventoryArea(properties_element);
15767       break;
15768
15769     case ED_COUNTER_ID_MM_BALL_CONTENT:
15770       DrawMMBallContentArea();
15771       break;
15772
15773     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15774     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15775       DrawEnvelopeTextArea(-1);
15776       break;
15777
15778     case ED_COUNTER_ID_LEVEL_XSIZE:
15779     case ED_COUNTER_ID_LEVEL_YSIZE:
15780       lev_fieldx = level.fieldx;
15781       lev_fieldy = level.fieldy;
15782
15783       // check if resizing of level results in change of border border
15784       SetBorderElement();
15785
15786       break;
15787
15788     default:
15789       break;
15790   }
15791
15792   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15793        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15794       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15795        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15796     CopyElementPropertiesToGame(properties_element);
15797
15798   // do not mark level as modified for certain non-level-changing gadgets
15799   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15800        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15801       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15802        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15803     return;
15804
15805   level.changed = TRUE;
15806 }
15807
15808 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15809 {
15810   int type_id = gi->custom_type_id;
15811
15812   strcpy(textinput_info[type_id].value, gi->textinput.value);
15813
15814   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15815   {
15816     CopyElementPropertiesToGame(properties_element);
15817
15818     ModifyEditorElementList();  // update changed button info text
15819   }
15820
15821   // do not mark level as modified for certain non-level-changing gadgets
15822   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15823       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15824     return;
15825
15826   level.changed = TRUE;
15827 }
15828
15829 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15830 {
15831   int type_id = gi->custom_type_id;
15832
15833   strncpy(textarea_info[type_id].value, gi->textarea.value,
15834           MAX_ENVELOPE_TEXT_LEN);
15835   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15836
15837   level.changed = TRUE;
15838 }
15839
15840 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15841 {
15842   int type_id = gi->custom_type_id;
15843   int value_old = *selectbox_info[type_id].value;
15844   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15845
15846   *selectbox_info[type_id].value = value_new;
15847
15848   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15849   {
15850     DrawLevelConfigWindow();
15851   }
15852   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15853   {
15854     element_info[properties_element].current_change_page = gi->selectbox.index;
15855
15856     DrawPropertiesWindow();
15857   }
15858   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15859             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15860            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15861             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15862            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15863   {
15864     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15865     {
15866       // when changing action type, also check action mode and action arg
15867       if (value_old != value_new)
15868         setSelectboxSpecialActionVariablesIfNeeded();
15869
15870       DrawPropertiesChange();
15871     }
15872
15873     CopyElementPropertiesToGame(properties_element);
15874   }
15875   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15876   {
15877     // show or hide "engine" tabulator depending on game engine type
15878     DrawLevelConfigWindow();
15879
15880     // update element selection list depending on game engine type
15881     ReinitializeElementList();
15882     ModifyEditorElementList();
15883   }
15884   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15885   {
15886     // update BD cycle delay counter gadgets depending on BD scheduling type
15887     DrawLevelConfigWindow();
15888   }
15889
15890   // do not mark level as modified for certain non-level-changing gadgets
15891   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15892       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15893     return;
15894
15895   level.changed = TRUE;
15896 }
15897
15898 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15899 {
15900   int type_id = gi->custom_type_id;
15901   int i;
15902
15903   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15904       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15905   {
15906     edit_mode_levelconfig = gi->custom_type_id;
15907
15908     DrawLevelConfigWindow();
15909   }
15910   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15911            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15912   {
15913     edit_mode_properties = gi->custom_type_id;
15914
15915     DrawPropertiesWindow();
15916   }
15917   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15918            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15919   {
15920     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15921
15922     // backup original "level.field" (needed to track playfield changes)
15923     CopyPlayfield(level.field, TileBackup);
15924
15925     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15926     CopyPlayfield(Tile, level.field);
15927
15928     if (new_template ||
15929         Request("Save this template and kill the old?", REQ_ASK))
15930       SaveLevelTemplate();
15931
15932     if (new_template)
15933       Request("Template saved!", REQ_CONFIRM);
15934
15935     // restore original "level.field" (needed to track playfield changes)
15936     CopyPlayfield(TileBackup, level.field);
15937   }
15938   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15939   {
15940     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15941
15942     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15943         leveldir_current->readonly)
15944     {
15945       Request("This level set is read-only!", REQ_CONFIRM);
15946
15947       return;
15948     }
15949
15950     if (strEqual(levelset_name, ""))
15951     {
15952       Request("Please enter level set title!", REQ_CONFIRM);
15953
15954       return;
15955     }
15956
15957     if (strEqual(levelset_author, ""))
15958     {
15959       Request("Please enter level set author!", REQ_CONFIRM);
15960
15961       return;
15962     }
15963
15964     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15965     {
15966       if (UpdateUserLevelSet(levelset_subdir,
15967                              levelset_name,
15968                              levelset_author,
15969                              levelset_num_levels))
15970       {
15971         Request("Level set updated!", REQ_CONFIRM);
15972       }
15973       else
15974       {
15975         Request("Updating level set failed!", REQ_CONFIRM);
15976       }
15977     }
15978     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15979     {
15980       if (level.changed && !Request("Level has changed! Discard changes?",
15981                                      REQ_ASK))
15982         return;
15983
15984       if (CreateUserLevelSet(levelset_subdir,
15985                              levelset_name,
15986                              levelset_author,
15987                              levelset_num_levels,
15988                              levelset_use_levelset_artwork))
15989       {
15990         if (levelset_copy_level_template)
15991           CopyLevelTemplateToUserLevelSet(levelset_subdir);
15992
15993         Request("New level set created!", REQ_CONFIRM);
15994
15995         AddUserLevelSetToLevelInfo(levelset_subdir);
15996         ChangeEditorToLevelSet(levelset_subdir);
15997       }
15998       else
15999       {
16000         Request("Creating new level set failed!", REQ_CONFIRM);
16001       }
16002     }
16003   }
16004   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
16005            custom_element.num_change_pages < MAX_CHANGE_PAGES)
16006   {
16007     struct ElementInfo *ei = &element_info[properties_element];
16008
16009     // when modifying custom element, ask for copying level template
16010     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16011       return;
16012
16013     setElementChangePages(ei, ei->num_change_pages + 1);
16014
16015     // set new change page to be new current change page
16016     ei->current_change_page = ei->num_change_pages - 1;
16017     ei->change = &ei->change_page[ei->current_change_page];
16018
16019     setElementChangeInfoToDefaults(ei->change);
16020
16021     DrawPropertiesWindow();
16022
16023     level.changed = TRUE;
16024   }
16025   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
16026            custom_element.num_change_pages > MIN_CHANGE_PAGES)
16027   {
16028     struct ElementInfo *ei = &element_info[properties_element];
16029
16030     // when modifying custom element, ask for copying level template
16031     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16032       return;
16033
16034     // copy all change pages after change page to be deleted
16035     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
16036       ei->change_page[i] = ei->change_page[i + 1];
16037
16038     setElementChangePages(ei, ei->num_change_pages - 1);
16039
16040     DrawPropertiesWindow();
16041
16042     level.changed = TRUE;
16043   }
16044 }
16045
16046 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
16047 {
16048   int type_id = gi->custom_type_id;
16049
16050   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
16051       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
16052   {
16053     struct ElementInfo *ei = &element_info[properties_element];
16054     int step = BUTTON_STEPSIZE(gi->event.button);
16055
16056     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
16057     ei->current_change_page += step;
16058
16059     if (ei->current_change_page < 0)
16060       ei->current_change_page = 0;
16061     else if (ei->current_change_page >= ei->num_change_pages)
16062       ei->current_change_page = ei->num_change_pages - 1;
16063
16064     DrawPropertiesWindow();
16065   }
16066   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
16067            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16068   {
16069     struct ElementInfo *ei = &element_info[properties_element];
16070     int current_change_page = ei->current_change_page;
16071
16072     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
16073     {
16074       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
16075         ei->change_page[current_change_page];
16076     }
16077     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16078     {
16079       // when modifying custom element, ask for copying level template
16080       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16081         return;
16082
16083       ei->change_page[current_change_page] =
16084         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
16085
16086       level.changed = TRUE;
16087     }
16088
16089     DrawPropertiesWindow();
16090   }
16091 }
16092
16093 static void HandleRadiobuttons(struct GadgetInfo *gi)
16094 {
16095   int type_id = gi->custom_type_id;
16096
16097   *radiobutton_info[type_id].value =
16098     radiobutton_info[type_id].checked_value;
16099
16100   // do not mark level as modified for certain non-level-changing gadgets
16101   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
16102       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
16103     return;
16104
16105   level.changed = TRUE;
16106 }
16107
16108 static void HandleCheckbuttons(struct GadgetInfo *gi)
16109 {
16110   int type_id = gi->custom_type_id;
16111
16112   *checkbutton_info[type_id].value ^= TRUE;
16113
16114   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
16115       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
16116       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
16117       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
16118          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
16119         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
16120          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
16121        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
16122   {
16123     CopyElementPropertiesToGame(properties_element);
16124   }
16125
16126   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
16127   {
16128     UpdateCustomElementGraphicGadgets();
16129   }
16130   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
16131            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
16132   {
16133     boolean template_related_changes_found = FALSE;
16134     int i;
16135
16136     // check if any custom, group or empty elements have been changed
16137     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
16138       if ((IS_CUSTOM_ELEMENT(i) ||
16139            IS_GROUP_ELEMENT(i) ||
16140            IS_EMPTY_ELEMENT(i)) &&
16141           element_info[i].modified_settings)
16142         template_related_changes_found = TRUE;
16143
16144     if (level.use_custom_template &&
16145         !fileExists(getGlobalLevelTemplateFilename()))
16146     {
16147       Request("No level template found!", REQ_CONFIRM);
16148
16149       level.use_custom_template = FALSE;
16150
16151       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16152
16153       return;
16154     }
16155
16156     if (level.use_custom_template &&
16157         template_related_changes_found &&
16158         !Request("Discard changes and use level template?", REQ_ASK))
16159     {
16160       level.use_custom_template = FALSE;
16161
16162       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16163
16164       return;
16165     }
16166
16167     if (!level.use_custom_template &&
16168         Request("Copy settings from level template?", REQ_ASK))
16169     {
16170       return;
16171     }
16172
16173     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
16174
16175     DrawEditModeWindow();
16176   }
16177   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
16178   {
16179     if (setup.editor.use_template_for_new_levels &&
16180         !fileExists(getGlobalLevelTemplateFilename()))
16181     {
16182       Request("No level template found!", REQ_CONFIRM);
16183
16184       return;
16185     }
16186
16187     if (setup.editor.use_template_for_new_levels &&
16188         level.changed &&
16189         !Request("Discard level and load template?", REQ_ASK))
16190     {
16191       return;
16192     }
16193
16194     if (!setup.editor.use_template_for_new_levels &&
16195         level.changed &&
16196         !Request("Discard level and use empty level?", REQ_ASK))
16197     {
16198       return;
16199     }
16200
16201     LoadLevel(level_nr);
16202     LoadScore(level_nr);
16203
16204     TapeErase();
16205
16206     ResetUndoBuffer();
16207     DrawEditModeWindow();
16208   }
16209   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16210   {
16211     SetAutomaticNumberOfGemsNeeded();
16212   }
16213
16214   // do not mark level as modified for certain non-level-changing gadgets
16215   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16216        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16217       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16218        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16219        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16220       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16221     return;
16222
16223   level.changed = TRUE;
16224 }
16225
16226 static void HandleControlButtons(struct GadgetInfo *gi)
16227 {
16228   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16229   static int last_edit_mode = ED_MODE_DRAWING;
16230   static int last_custom_copy_mode = -1;
16231   static int last_button = 0;
16232   int id = gi->custom_id;
16233   int button = gi->event.button;
16234   int step = BUTTON_STEPSIZE(button);
16235   int new_element = BUTTON_ELEMENT(button);
16236   int last_properties_element = properties_element;
16237   int x, y;
16238
16239   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16240     DrawLevelText(0, 0, 0, TEXT_END);
16241
16242   if (id < ED_NUM_CTRL1_BUTTONS &&
16243       id != GADGET_ID_SINGLE_ITEMS &&
16244       id != GADGET_ID_PICK_ELEMENT &&
16245       edit_mode != ED_MODE_DRAWING &&
16246       drawing_function != GADGET_ID_PICK_ELEMENT &&
16247       !(GetKeyModState() & KMOD_Control))
16248     ChangeEditModeWindow(ED_MODE_DRAWING);
16249
16250   // element copy mode active, but no element button pressed => deactivate
16251   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16252     last_custom_copy_mode = -1;
16253
16254   // when showing palette on element buttons, change element of button used
16255   if (editor.palette.show_on_element_buttons &&
16256       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16257   {
16258     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16259
16260     id = GADGET_ID_PALETTE;
16261   }
16262
16263   switch (id)
16264   {
16265     case GADGET_ID_SCROLL_LEFT:
16266       if (level_xpos >= 0)
16267       {
16268         if (lev_fieldx < ed_fieldx - 2)
16269           break;
16270
16271         level_xpos -= step;
16272         if (level_xpos < -1)
16273           level_xpos = -1;
16274         if (button == 1)
16275           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16276         else
16277           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16278
16279         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16280                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16281       }
16282       break;
16283
16284     case GADGET_ID_SCROLL_RIGHT:
16285       if (level_xpos <= lev_fieldx - ed_fieldx)
16286       {
16287         if (lev_fieldx < ed_fieldx - 2)
16288           break;
16289
16290         level_xpos += step;
16291         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16292           level_xpos = lev_fieldx - ed_fieldx + 1;
16293         if (button == 1)
16294           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16295         else
16296           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16297
16298         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16299                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16300       }
16301       break;
16302
16303     case GADGET_ID_SCROLL_UP:
16304       if (level_ypos >= 0)
16305       {
16306         if (lev_fieldy < ed_fieldy - 2)
16307           break;
16308
16309         level_ypos -= step;
16310         if (level_ypos < -1)
16311           level_ypos = -1;
16312         if (button == 1)
16313           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16314         else
16315           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16316
16317         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16318                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16319       }
16320       break;
16321
16322     case GADGET_ID_SCROLL_DOWN:
16323       if (level_ypos <= lev_fieldy - ed_fieldy)
16324       {
16325         if (lev_fieldy < ed_fieldy - 2)
16326           break;
16327
16328         level_ypos += step;
16329         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16330           level_ypos = lev_fieldy - ed_fieldy + 1;
16331         if (button == 1)
16332           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16333         else
16334           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16335
16336         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16337                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16338       }
16339       break;
16340
16341     case GADGET_ID_SCROLL_HORIZONTAL:
16342       level_xpos = gi->event.item_position - 1;
16343
16344       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16345       BackToFront();
16346
16347       break;
16348
16349     case GADGET_ID_SCROLL_VERTICAL:
16350       level_ypos = gi->event.item_position - 1;
16351
16352       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16353       BackToFront();
16354
16355       break;
16356
16357     case GADGET_ID_SCROLL_LIST_UP:
16358     case GADGET_ID_SCROLL_LIST_DOWN:
16359     case GADGET_ID_SCROLL_LIST_VERTICAL:
16360       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16361         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16362       else
16363       {
16364         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16365         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16366
16367         if (element_shift < 0)
16368           element_shift = 0;
16369         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16370           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16371
16372         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16373                      GDI_SCROLLBAR_ITEM_POSITION,
16374                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16375       }
16376
16377       ModifyEditorElementList();
16378
16379       break;
16380
16381     case GADGET_ID_PROPERTIES:
16382       // always switch off element properties when they are already displayed
16383       last_properties_element = new_element;
16384     case GADGET_ID_ELEMENT_LEFT:
16385     case GADGET_ID_ELEMENT_MIDDLE:
16386     case GADGET_ID_ELEMENT_RIGHT:
16387       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16388                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16389                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16390                             new_element);
16391
16392       if (edit_mode != ED_MODE_PROPERTIES)
16393       {
16394         last_edit_mode = edit_mode;
16395
16396         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16397
16398         last_level_drawing_function = drawing_function;
16399         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16400                       MB_LEFTBUTTON);
16401       }
16402       else if (properties_element != last_properties_element)
16403       {
16404         DrawEditModeWindow();
16405       }
16406       else
16407       {
16408         ChangeEditModeWindow(ED_MODE_DRAWING);
16409
16410         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16411                       MB_LEFTBUTTON);
16412       }
16413       break;
16414
16415     case GADGET_ID_PALETTE:
16416       if (edit_mode != ED_MODE_PALETTE)
16417       {
16418         last_edit_mode = edit_mode;
16419
16420         ChangeEditModeWindow(ED_MODE_PALETTE);
16421       }
16422       else
16423       {
16424         ChangeEditModeWindow(last_edit_mode);
16425       }
16426       break;
16427
16428     case GADGET_ID_WRAP_LEFT:
16429       WrapLevel(-step, 0);
16430       break;
16431
16432     case GADGET_ID_WRAP_RIGHT:
16433       WrapLevel(step, 0);
16434       break;
16435
16436     case GADGET_ID_WRAP_UP:
16437       WrapLevel(0, -step);
16438       break;
16439
16440     case GADGET_ID_WRAP_DOWN:
16441       WrapLevel(0, step);
16442       break;
16443
16444     case GADGET_ID_SINGLE_ITEMS:
16445     case GADGET_ID_CONNECTED_ITEMS:
16446     case GADGET_ID_LINE:
16447     case GADGET_ID_ARC:
16448     case GADGET_ID_TEXT:
16449     case GADGET_ID_RECTANGLE:
16450     case GADGET_ID_FILLED_BOX:
16451     case GADGET_ID_FLOOD_FILL:
16452     case GADGET_ID_GRAB_BRUSH:
16453     case GADGET_ID_PICK_ELEMENT:
16454       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16455         last_drawing_function = drawing_function;
16456       drawing_function = id;
16457       draw_with_brush = FALSE;
16458       break;
16459
16460     case GADGET_ID_RANDOM_PLACEMENT:
16461       RandomPlacement(new_element);
16462       break;
16463
16464     case GADGET_ID_ZOOM:
16465       // zoom level editor tile size in or out (or reset to default size)
16466       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16467                      button == 2 ? ed_tilesize_default :
16468                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16469
16470       // when using touch device, cycle through all zoom tilesizes
16471       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16472         ed_tilesize = MICRO_TILESIZE;
16473
16474       // limit zoom level by upper and lower bound
16475       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16476
16477       InitZoomLevelSettings(ed_tilesize);
16478
16479       if (edit_mode == ED_MODE_DRAWING)
16480       {
16481         DrawDrawingWindow();
16482
16483         // redraw zoom gadget info text
16484         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16485       }
16486
16487       // save current editor zoom tilesize
16488       SaveSetup_AutoSetup();
16489
16490       break;
16491
16492     case GADGET_ID_CUSTOM_COPY_FROM:
16493     case GADGET_ID_CUSTOM_COPY_TO:
16494     case GADGET_ID_CUSTOM_EXCHANGE:
16495       last_custom_copy_mode = id;
16496       last_drawing_function = drawing_function;
16497       break;
16498
16499     case GADGET_ID_CUSTOM_COPY:
16500       CopyCustomElement(properties_element, -1, id);
16501       break;
16502
16503     case GADGET_ID_CUSTOM_PASTE:
16504       CopyCustomElement(-1, properties_element, id);
16505       break;
16506
16507     case GADGET_ID_UNDO:
16508       if (button < 0)   // keep button value (even if modifier keys are pressed)
16509         button = -button;
16510       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16511         button = 3;
16512
16513       if (button == 1 && undo_buffer_steps == 0)
16514       {
16515         Request("Undo buffer empty!", REQ_CONFIRM);
16516
16517         break;
16518       }
16519       else if (button == 2)
16520       {
16521         break;
16522       }
16523       else if (button == 3 && redo_buffer_steps == 0)
16524       {
16525         Request("Redo buffer empty!", REQ_CONFIRM);
16526
16527         break;
16528       }
16529
16530       if (edit_mode != ED_MODE_DRAWING)
16531         ChangeEditModeWindow(ED_MODE_DRAWING);
16532
16533       if (button == 1)
16534       {
16535         // undo
16536
16537         undo_buffer_position =
16538           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16539
16540         undo_buffer_steps--;
16541         redo_buffer_steps++;
16542       }
16543       else
16544       {
16545         // redo
16546
16547         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16548
16549         undo_buffer_steps++;
16550         redo_buffer_steps--;
16551       }
16552
16553       for (x = 0; x < lev_fieldx; x++)
16554         for (y = 0; y < lev_fieldy; y++)
16555           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16556
16557       // check if undo operation forces change of border style
16558       CheckLevelBorderElement(FALSE);
16559
16560       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16561
16562       break;
16563
16564     case GADGET_ID_CONF:
16565       if (edit_mode != ED_MODE_LEVELCONFIG)
16566       {
16567         last_edit_mode = edit_mode;
16568
16569         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16570       }
16571       else
16572       {
16573         ChangeEditModeWindow(ED_MODE_DRAWING);
16574       }
16575       break;
16576
16577     case GADGET_ID_CLEAR:
16578       if (edit_mode != ED_MODE_DRAWING)
16579         ChangeEditModeWindow(ED_MODE_DRAWING);
16580
16581       for (x = 0; x < MAX_LEV_FIELDX; x++)
16582         for (y = 0; y < MAX_LEV_FIELDY; y++)
16583           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16584
16585       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16586
16587       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16588       break;
16589
16590     case GADGET_ID_SAVE:
16591     {
16592       // saving read-only levels into personal level set modifies global vars
16593       // "leveldir_current" and "level_nr"; restore them after saving level
16594       LevelDirTree *leveldir_former = leveldir_current;
16595       int level_nr_former = level_nr;
16596       char *level_filename;
16597       boolean new_level;
16598
16599       if (leveldir_current->readonly &&
16600           !PrepareSavingIntoPersonalLevelSet())
16601         break;
16602
16603       level_filename = getDefaultLevelFilename(level_nr);
16604       new_level = !fileExists(level_filename);
16605
16606       if (new_level ||
16607           Request("Save this level and kill the old?", REQ_ASK))
16608       {
16609         if (leveldir_former->readonly)
16610           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16611
16612         SetAutomaticNumberOfGemsNeeded();
16613
16614         CopyPlayfield(Tile, level.field);
16615         SaveLevel(level_nr);
16616
16617         level.changed = FALSE;
16618
16619         if (new_level)
16620         {
16621           char level_saved_msg[64];
16622
16623           if (leveldir_former->readonly)
16624             sprintf(level_saved_msg,
16625                     "Level saved as level %d into personal level set!",
16626                     level_nr);
16627           else
16628             strcpy(level_saved_msg, "Level saved!");
16629
16630           Request(level_saved_msg, REQ_CONFIRM);
16631         }
16632       }
16633
16634       // "cd" back to copied-from levelset (in case of saved read-only level)
16635       leveldir_current = leveldir_former;
16636       level_nr = level_nr_former;
16637
16638       break;
16639     }
16640
16641     case GADGET_ID_TEST:
16642       if (LevelChanged())
16643         level.game_version = GAME_VERSION_ACTUAL;
16644
16645       CopyPlayfield(level.field, TileBackup);
16646       CopyPlayfield(Tile, level.field);
16647
16648       CopyNativeLevel_RND_to_Native(&level);
16649
16650       UnmapLevelEditorGadgets();
16651       UndrawSpecialEditorDoor();
16652
16653       CloseDoor(DOOR_CLOSE_ALL);
16654
16655       // needed before playing if editor playfield area has different size
16656       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16657
16658       // redraw_mask = REDRAW_ALL;
16659
16660       level_editor_test_game = TRUE;
16661
16662       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16663
16664       break;
16665
16666     case GADGET_ID_EXIT:
16667       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16668       break;
16669
16670     default:
16671       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16672           id <= GADGET_ID_ELEMENTLIST_LAST)
16673       {
16674         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16675
16676         new_element = editor_elements[element_position + element_shift];
16677
16678         if (IS_EDITOR_CASCADE(new_element))
16679         {
16680           int i;
16681
16682           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16683           {
16684             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16685             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16686
16687             if (*cascade_element == new_element)
16688             {
16689               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16690               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16691
16692               // update element selection list
16693               ReinitializeElementList();
16694               ModifyEditorElementList();
16695
16696               // update cascading gadget info text
16697               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16698
16699               // save current editor cascading state
16700               SaveSetup_EditorCascade();
16701
16702               break;
16703             }
16704           }
16705
16706           break;
16707         }
16708
16709         if (last_custom_copy_mode != -1)
16710         {
16711           if (CopyCustomElement(properties_element, new_element,
16712                                 last_custom_copy_mode))
16713           {
16714             ClickOnGadget(level_editor_gadget[last_drawing_function],
16715                           MB_LEFTBUTTON);
16716
16717             last_custom_copy_mode = -1;
16718           }
16719
16720           break;
16721         }
16722
16723         // change element of button used to show palette
16724         if (editor.palette.show_on_element_buttons)
16725           button = last_button;
16726
16727         PickDrawingElement(button, new_element);
16728
16729         if (!stick_element_properties_window &&
16730             drawing_function != GADGET_ID_PICK_ELEMENT &&
16731             !(GetKeyModState() & KMOD_Control))
16732         {
16733           properties_element = new_element;
16734           if (edit_mode == ED_MODE_PROPERTIES)
16735             DrawPropertiesWindow();
16736         }
16737
16738         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16739           ClickOnGadget(level_editor_gadget[last_drawing_function],
16740                         MB_LEFTBUTTON);
16741
16742         if (!use_permanent_palette)
16743           ChangeEditModeWindow(last_edit_mode);
16744       }
16745 #ifdef DEBUG
16746       else if (gi->event.type == GD_EVENT_PRESSED)
16747         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16748       else if (gi->event.type == GD_EVENT_RELEASED)
16749         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16750       else if (gi->event.type == GD_EVENT_MOVING)
16751         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16752       else
16753         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16754 #endif
16755       break;
16756   }
16757 }
16758
16759 void HandleLevelEditorKeyInput(Key key)
16760 {
16761   char letter = getCharFromKey(key);
16762
16763   if (drawing_function == GADGET_ID_TEXT &&
16764       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16765   {
16766     if (letter)
16767       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16768     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16769       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16770     else if (key == KSYM_Return)
16771       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16772     else if (key == KSYM_Escape)
16773       DrawLevelText(0, 0, 0, TEXT_END);
16774
16775     return;
16776   }
16777
16778   int id = GADGET_ID_NONE;
16779   int new_element_shift = element_shift;
16780   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16781   int button = MB_LEFTBUTTON;
16782   int i;
16783
16784   switch (key)
16785   {
16786     case KSYM_Left:
16787       id = GADGET_ID_SCROLL_LEFT;
16788       break;
16789     case KSYM_Right:
16790       id = GADGET_ID_SCROLL_RIGHT;
16791       break;
16792     case KSYM_Up:
16793       id = GADGET_ID_SCROLL_UP;
16794       break;
16795     case KSYM_Down:
16796       id = GADGET_ID_SCROLL_DOWN;
16797       break;
16798
16799     case KSYM_Page_Up:
16800     case KSYM_Page_Down:
16801       step *= (key == KSYM_Page_Up ? -1 : +1);
16802       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16803
16804       if (element_shift < 0)
16805         element_shift = 0;
16806       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16807         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16808
16809       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16810                    GDI_SCROLLBAR_ITEM_POSITION,
16811                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16812
16813       ModifyEditorElementList();
16814
16815       break;
16816
16817     case KSYM_Home:
16818     case KSYM_End:
16819       element_shift = (key == KSYM_Home ? 0 :
16820                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16821
16822       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16823                    GDI_SCROLLBAR_ITEM_POSITION,
16824                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16825
16826       ModifyEditorElementList();
16827
16828       break;
16829
16830     case KSYM_Insert:
16831     case KSYM_Delete:
16832
16833       // this is needed to prevent interference with running "True X-Mouse"
16834       if (GetKeyModStateFromEvents() & KMOD_Control)
16835         break;
16836
16837       // check for last or next editor cascade block in element list
16838       for (i = 0; i < num_editor_elements; i++)
16839       {
16840         if ((key == KSYM_Insert && i == element_shift) ||
16841             (key == KSYM_Delete && new_element_shift > element_shift))
16842           break;
16843
16844         // jump to next cascade block (or to start of element list)
16845         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16846           new_element_shift = i;
16847       }
16848
16849       if (i < num_editor_elements)
16850         element_shift = new_element_shift;
16851
16852       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16853         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16854
16855       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16856                    GDI_SCROLLBAR_ITEM_POSITION,
16857                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16858
16859       ModifyEditorElementList();
16860
16861       break;
16862
16863     case KSYM_Escape:
16864       if (edit_mode == ED_MODE_DRAWING)
16865         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16866       else if (edit_mode == ED_MODE_LEVELCONFIG)
16867         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16868       else if (edit_mode == ED_MODE_PROPERTIES)
16869         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16870       else if (edit_mode == ED_MODE_PALETTE)
16871         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16872       else              // should never happen
16873         ChangeEditModeWindow(ED_MODE_DRAWING);
16874
16875       break;
16876
16877     default:
16878       break;
16879   }
16880
16881   if (id != GADGET_ID_NONE)
16882     ClickOnGadget(level_editor_gadget[id], button);
16883   else if (letter == '1' || letter == '?')
16884     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16885   else if (letter == '2')
16886     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16887   else if (letter == '3')
16888     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16889   else if (letter == '.')
16890     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16891   else if (letter == 'U')
16892     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16893   else if (letter == '-' || key == KSYM_KP_Subtract)
16894     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16895   else if (letter == '0' || key == KSYM_KP_0)
16896     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16897   else if (letter == '+' || key == KSYM_KP_Add ||
16898            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16899     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16900   else if (key == KSYM_Return ||
16901            key == KSYM_space ||
16902            key == setup.shortcut.toggle_pause)
16903     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16904   else
16905     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16906       if (letter && letter == controlbutton_info[i].shortcut)
16907         if (!anyTextGadgetActive())
16908           ClickOnGadget(level_editor_gadget[i], button);
16909
16910   if (draw_with_brush)
16911   {
16912     if (letter == 'x')
16913       FlipBrushX();
16914     else if (letter == 'y')
16915       FlipBrushY();
16916     else if (letter == 'z')
16917       RotateBrush();
16918   }
16919 }
16920
16921 static void HandleLevelEditorIdle_Properties(void)
16922 {
16923   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16924   int x = editor.settings.element_graphic.x + element_border;
16925   int y = editor.settings.element_graphic.y + element_border;
16926   static DelayCounter action_delay = { 0 };
16927   int i;
16928
16929   action_delay.value = GameFrameDelay;
16930
16931   if (!DelayReached(&action_delay))
16932     return;
16933
16934   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16935   {
16936     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16937
16938     if (gi->mapped && gi->active && gi->selectbox.open)
16939       return;
16940   }
16941
16942   DrawEditorElementAnimation(SX + x, SY + y);
16943
16944   redraw_mask |= REDRAW_FIELD;
16945
16946   FrameCounter++;       // increase animation frame counter
16947 }
16948
16949 static void HandleLevelEditorIdle_Drawing(void)
16950 {
16951   static boolean last_highlighted = FALSE;
16952   static boolean last_highlighted_similar = FALSE;
16953   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16954   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16955
16956   if (highlighted != last_highlighted ||
16957       (highlighted && highlighted_similar != last_highlighted_similar))
16958   {
16959     DrawAreaElementHighlight(highlighted, highlighted_similar);
16960
16961     redraw_mask |= REDRAW_FIELD;
16962   }
16963
16964   last_highlighted = highlighted;
16965   last_highlighted_similar = highlighted_similar;
16966 }
16967
16968 void HandleLevelEditorIdle(void)
16969 {
16970   if (edit_mode == ED_MODE_PROPERTIES)
16971     HandleLevelEditorIdle_Properties();
16972   else if (edit_mode == ED_MODE_DRAWING)
16973     HandleLevelEditorIdle_Drawing();
16974 }
16975
16976 static void ClearEditorGadgetInfoText(void)
16977 {
16978   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16979 }
16980
16981 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16982 {
16983   char infotext[MAX_OUTPUT_LINESIZE + 1];
16984   int max_infotext_len = getMaxInfoTextLength();
16985
16986   if (gi == NULL || strlen(gi->info_text) == 0)
16987     return;
16988
16989   strncpy(infotext, gi->info_text, max_infotext_len);
16990   infotext[max_infotext_len] = '\0';
16991
16992   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
16993   {
16994     int key = controlbutton_info[gi->custom_id].shortcut;
16995
16996     if (key)
16997     {
16998       char shortcut[MAX_OUTPUT_LINESIZE + 1];
16999
17000       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
17001         sprintf(shortcut, " ('.' or '%c')", key);
17002       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
17003         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
17004       else if (gi->custom_id == GADGET_ID_TEST)
17005         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
17006       else if (gi->custom_id == GADGET_ID_UNDO)
17007         sprintf(shortcut, " ('%c/Shift-U')", key);
17008       else if (gi->custom_id == GADGET_ID_ZOOM)
17009         sprintf(shortcut, " ('%c', '0', '-')", key);
17010       else
17011         sprintf(shortcut, " ('%s%c')",
17012                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
17013
17014       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
17015         strcat(infotext, shortcut);
17016     }
17017   }
17018
17019   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
17020 }
17021
17022 void HandleEditorGadgetInfoText(void *ptr)
17023 {
17024   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
17025
17026   if (game_status != GAME_MODE_EDITOR)
17027     return;
17028
17029   ClearEditorGadgetInfoText();
17030
17031   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
17032     return;
17033
17034   // misuse this function to delete brush cursor, if needed
17035   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
17036     DeleteBrushFromCursor();
17037
17038   PrintEditorGadgetInfoText(gi);
17039 }
17040
17041 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
17042 {
17043   int id = gi->custom_id;
17044   int type_id = gi->custom_type_id;
17045   int sx = gi->event.x;
17046   int sy = gi->event.y;
17047   int lx = sx + level_xpos;
17048   int ly = sy + level_ypos;
17049   int min_sx = 0, min_sy = 0;
17050   int max_sx = gi->drawing.area_xsize - 1;
17051   int max_sy = gi->drawing.area_ysize - 1;
17052   int actual_drawing_function = drawing_function;
17053   int max_infotext_len = getMaxInfoTextLength();
17054   char infotext[MAX_OUTPUT_LINESIZE + 1];
17055
17056   infotext[0] = '\0';           // start with empty info text
17057
17058   // pressed Control key: simulate picking element
17059   if (GetKeyModState() & KMOD_Control)
17060     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
17061
17062   ClearEditorGadgetInfoText();
17063
17064   if (gi->event.type == GD_EVENT_INFO_LEAVING)
17065     return;
17066
17067   // make sure to stay inside drawing area boundaries
17068   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
17069   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
17070
17071   if (id == GADGET_ID_DRAWING_LEVEL)
17072   {
17073     if (button_status)
17074     {
17075       int min_lx = 0, min_ly = 0;
17076       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
17077
17078       // get positions inside level field
17079       lx = sx + level_xpos;
17080       ly = sy + level_ypos;
17081
17082       // make sure to stay inside level field boundaries
17083       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
17084       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
17085
17086       // correct drawing area positions accordingly
17087       sx = lx - level_xpos;
17088       sy = ly - level_ypos;
17089     }
17090
17091     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17092     {
17093       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
17094       {
17095         static int start_lx = 0;
17096         static int start_ly = 0;
17097         char *text;
17098
17099         if (gi->event.type == GD_EVENT_PRESSED)
17100         {
17101           start_lx = lx;
17102           start_ly = ly;
17103         }
17104
17105         switch (actual_drawing_function)
17106         {
17107           case GADGET_ID_SINGLE_ITEMS:
17108             text = "Drawing single items";
17109             break;
17110           case GADGET_ID_CONNECTED_ITEMS:
17111             text = "Drawing connected items";
17112             break;
17113           case GADGET_ID_LINE:
17114             text = "Drawing line";
17115             break;
17116           case GADGET_ID_ARC:
17117             text = "Drawing arc";
17118             break;
17119           case GADGET_ID_TEXT:
17120             text = "Setting text cursor";
17121             break;
17122           case GADGET_ID_RECTANGLE:
17123             text = "Drawing rectangle";
17124             break;
17125           case GADGET_ID_FILLED_BOX:
17126             text = "Drawing filled box";
17127             break;
17128           case GADGET_ID_FLOOD_FILL:
17129             text = "Flood fill";
17130             break;
17131           case GADGET_ID_GRAB_BRUSH:
17132             text = "Grabbing brush";
17133             break;
17134           case GADGET_ID_PICK_ELEMENT:
17135             text = "Picking element";
17136             break;
17137
17138           default:
17139             text = "Drawing position";
17140             break;
17141         }
17142
17143         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17144           sprintf(infotext, "%s: %d, %d", text, lx, ly);
17145         else
17146           sprintf(infotext, "%s: %d, %d", text,
17147                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
17148       }
17149       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17150         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
17151       else
17152         sprintf(infotext, "Level position: %d, %d", lx, ly);
17153     }
17154
17155     // misuse this function to draw brush cursor, if needed
17156     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
17157     {
17158       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17159         CopyBrushToCursor(sx, sy);
17160       else
17161         DeleteBrushFromCursor();
17162     }
17163
17164     if (!draw_with_brush)
17165       UpdateBrushPosition(sx, sy);
17166   }
17167   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17168   {
17169     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
17170     int element = drawingarea_info[type_id].value[pos];
17171
17172     strncpy(infotext, getElementInfoText(element), max_infotext_len);
17173   }
17174   else
17175   {
17176     if (id == GADGET_ID_CUSTOM_CONTENT)
17177       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
17178     else if (id == GADGET_ID_GROUP_CONTENT)
17179       sprintf(infotext, "group element position: %d", sx + 1);
17180     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
17181              id <= GADGET_ID_YAMYAM_CONTENT_7)
17182       sprintf(infotext, "content area %d position: %d, %d",
17183               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
17184     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17185              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17186       sprintf(infotext, "content area %d position: %d, %d",
17187               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17188     else if (id == GADGET_ID_ANDROID_CONTENT)
17189       sprintf(infotext, "android element position: %d", sx + 1);
17190     else if (drawingarea_info[type_id].infotext != NULL)
17191       strcpy(infotext, drawingarea_info[type_id].infotext);
17192   }
17193
17194   infotext[max_infotext_len] = '\0';
17195
17196   if (strlen(infotext) > 0)
17197     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17198 }
17199
17200 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17201                             boolean quick_quit)
17202 {
17203   if (!ask_if_level_has_changed ||
17204       !LevelChanged() ||
17205       Request("Level has changed! Exit without saving?",
17206               REQ_ASK | REQ_STAY_OPEN))
17207   {
17208     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17209     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17210
17211     // draw normal door
17212     UndrawSpecialEditorDoor();
17213
17214     // use door animation if door 1 viewport is unchanged and contains toolbox
17215     if (useEditorDoorAnimation())
17216       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17217
17218     // close editor doors if viewport definition is the same as in main menu
17219     if (vp_door_1->x      == DX     &&
17220         vp_door_1->y      == DY     &&
17221         vp_door_1->width  == DXSIZE &&
17222         vp_door_1->height == DYSIZE &&
17223         vp_door_2->x      == VX     &&
17224         vp_door_2->y      == VY     &&
17225         vp_door_2->width  == VXSIZE &&
17226         vp_door_2->height == VYSIZE)
17227       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17228     else
17229       SetDoorState(DOOR_CLOSE_ALL);
17230
17231     BackToFront();
17232
17233     if (quick_quit)
17234       FadeSkipNextFadeIn();
17235
17236     SetGameStatus(GAME_MODE_MAIN);
17237
17238     DrawMainMenu();
17239   }
17240   else
17241   {
17242     if (!global.use_envelope_request)
17243     {
17244       CloseDoor(DOOR_CLOSE_1);
17245       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17246     }
17247   }
17248 }